i mean technically this might compile

This commit is contained in:
Ben Kerllenevich
2021-11-23 16:37:40 -05:00
parent 5149e879e0
commit 26a89140d0
300 changed files with 9 additions and 9 deletions

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ben Kerllenevich <ben@omega24.dev>
Date: Tue, 23 Nov 2021 08:38:18 -0500
Subject: [PATCH] Decompile Fixes
diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java
index c5b9c0c650df5f4b7e3d2a431dc900e210104dea..212e2c5b4b917c0c327d4b0612fecaea81c0ad87 100644
--- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java
+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java
@@ -123,7 +123,7 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
@Override
public Brain<Hoglin> getBrain() {
- return super.getBrain();
+ return (Brain<Hoglin>) super.getBrain(); // Purpur - decompile fix
}
@Override

View File

@@ -0,0 +1,787 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 4 May 2019 01:02:11 -0500
Subject: [PATCH] Rebrand
diff --git a/build.gradle.kts b/build.gradle.kts
index e067c69fea1dec79ef8e97cad1c74020b6a3a235..9bc497993c38a04b3435d368f282595c42bcb582 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -22,8 +22,8 @@ repositories {
}
dependencies {
- implementation(project(":Paper-API"))
- implementation(project(":Paper-MojangAPI"))
+ implementation(project(":Purpur-API")) // Purpur
+ implementation("io.papermc.paper:paper-mojangapi:1.17.1-R0.1-SNAPSHOT") // Purpur
// Paper start
implementation("org.jline:jline-terminal-jansi:3.21.0")
implementation("net.minecrell:terminalconsoleappender:1.3.0")
@@ -53,6 +53,8 @@ dependencies {
runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.0")
implementation("io.netty:netty-all:4.1.65.Final") // Paper
+ implementation("cat.inspiracio:rhino-js-engine:1.7.7.1") // Purpur
+ implementation("dev.omega24:upnp4j:1.0") // Purpur
implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation
implementation("com.velocitypowered:velocity-native:1.1.0-SNAPSHOT") // Paper
@@ -74,7 +76,7 @@ tasks.jar {
attributes(
"Main-Class" to "org.bukkit.craftbukkit.Main",
"Implementation-Title" to "CraftBukkit",
- "Implementation-Version" to "git-Paper-$implementationVersion",
+ "Implementation-Version" to "git-Purpur-$implementationVersion", // Purpur
"Implementation-Vendor" to date, // Paper
"Specification-Title" to "Bukkit",
"Specification-Version" to project.version,
@@ -201,7 +203,7 @@ tasks.test {
fun TaskContainer.registerRunTask(
name: String, block: JavaExec.() -> Unit
): TaskProvider<JavaExec> = register<JavaExec>(name) {
- group = "paper"
+ group = "paperweight" // Purpur
standardInput = System.`in`
workingDir = rootProject.layout.projectDirectory.dir(
providers.gradleProperty("runWorkDir").forUseAtConfigurationTime().orElse("run")
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
index ece77f5ea4b14bbed7c070131b3251ea86764538..aadd6550a5892e403f7b0bbef008461c1566a1bb 100644
--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
@@ -19,8 +19,8 @@ import java.util.stream.StreamSupport;
public class PaperVersionFetcher implements VersionFetcher {
private static final java.util.regex.Pattern VER_PATTERN = java.util.regex.Pattern.compile("^([0-9\\.]*)\\-.*R"); // R is an anchor, will always give '-R' at end
- private static final String GITHUB_BRANCH_NAME = "master";
- private static final String DOWNLOAD_PAGE = "https://papermc.io/downloads";
+ private static final String DOWNLOAD_PAGE = "https://purpur.pl3x.net/downloads/";
+ private static final String JENKINS_URL = "https://ci.pl3x.net/job/Purpur/lastSuccessfulBuild/buildNumber"; // Purpur
private static @Nullable String mcVer;
@Override
@@ -31,8 +31,8 @@ public class PaperVersionFetcher implements VersionFetcher {
@Nonnull
@Override
public Component getVersionMessage(@Nonnull String serverVersion) {
- String[] parts = serverVersion.substring("git-Paper-".length()).split("[-\\s]");
- final Component updateMessage = getUpdateStatusMessage("PaperMC/Paper", GITHUB_BRANCH_NAME, parts[0]);
+ String[] parts = serverVersion.substring("git-Purpur-".length()).split("[-\\s]"); // Airplane // Purpur
+ final Component updateMessage = getUpdateStatusMessage("pl3xgaming/Purpur", "ver/" + getMinecraftVersion(), parts[0]); // Airplane // Purpur
final Component history = getHistory();
return history != null ? TextComponent.ofChildren(updateMessage, Component.newline(), history) : updateMessage;
@@ -45,7 +45,7 @@ public class PaperVersionFetcher implements VersionFetcher {
String result = matcher.group();
mcVer = result.substring(0, result.length() - 2); // strip 'R' anchor and trailing '-'
} else {
- org.bukkit.Bukkit.getLogger().warning("Unable to match version to pattern! Report to PaperMC!");
+ org.bukkit.Bukkit.getLogger().warning("Unable to match version to pattern! Report to Purpur!"); // Purpur
org.bukkit.Bukkit.getLogger().warning("Pattern: " + VER_PATTERN.toString());
org.bukkit.Bukkit.getLogger().warning("Version: " + org.bukkit.Bukkit.getBukkitVersion());
}
@@ -85,15 +85,11 @@ public class PaperVersionFetcher implements VersionFetcher {
if (siteApiVersion == null) { return -1; }
try {
try (BufferedReader reader = Resources.asCharSource(
- new URL("https://papermc.io/api/v2/projects/paper/versions/" + siteApiVersion),
+ new URL("https://api.pl3x.net/v2/purpur/" + siteApiVersion), // Purpur
Charsets.UTF_8
).openBufferedStream()) {
JsonObject json = new Gson().fromJson(reader, JsonObject.class);
- JsonArray builds = json.getAsJsonArray("builds");
- int latest = StreamSupport.stream(builds.spliterator(), false)
- .mapToInt(e -> e.getAsInt())
- .max()
- .getAsInt();
+ int latest = json.getAsJsonObject("builds").getAsJsonPrimitive("latest").getAsInt(); // Purpur
return latest - jenkinsBuild;
} catch (JsonSyntaxException ex) {
ex.printStackTrace();
diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
index e0b1f0671d16ddddcb6725acd25a1d1d69e42701..8c3c68465197fafc14849dc38a572e309931e2a2 100644
--- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
+++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
@@ -17,7 +17,7 @@ public final class PaperConsole extends SimpleTerminalConsole {
@Override
protected LineReader buildReader(LineReaderBuilder builder) {
builder
- .appName("Paper")
+ .appName("Purpur") // Purpur
.variable(LineReader.HISTORY_FILE, java.nio.file.Paths.get(".console_history"))
.completer(new ConsoleCommandCompleter(this.server))
.option(LineReader.Option.COMPLETE_IN_WORD, true);
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 5a4172faaf960d48939d6a485719041987df9242..c97387afe3dec66eec436f5e109f17acf024f988 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1729,7 +1729,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@DontObfuscate
public String getServerModName() {
- return "Paper"; // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla!
+ return "Purpur"; // Purpur - Purpur > // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla!
}
public SystemReport fillSystemReport(SystemReport details) {
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index b6ee0e709b0f0529b99567bc9b8fb6bfd99bcd8e..fce717f47bfb951e1483b96180864c66da2eb773 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -292,11 +292,12 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!");
DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware.");
// Spigot start
- if (org.spigotmc.SpigotConfig.bungee) {
- DedicatedServer.LOGGER.warn("Whilst this makes it possible to use BungeeCord, unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose.");
+ if (com.destroystokyo.paper.PaperConfig.isProxyOnlineMode()) { // Purpur
+ DedicatedServer.LOGGER.warn("Whilst this makes it possible to use BungeeCord or Velocity, unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose."); // Purpur
DedicatedServer.LOGGER.warn("Please see http://www.spigotmc.org/wiki/firewall-guide/ for further information.");
} else {
DedicatedServer.LOGGER.warn("While this makes the game possible to play without internet access, it also opens up the ability for hackers to connect with any username they choose.");
+ DedicatedServer.LOGGER.warn("You will not be offered any support as long as the server allows offline-mode players to join."); // Purpur
}
// Spigot end
DedicatedServer.LOGGER.warn("To change this, set \"online-mode\" to \"true\" in the server.properties file.");
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 99a94898316b0601f55b333c15a9926eae24f8a2..58fd726baccee28bcab6fb693616e7da5c87be8f 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -251,7 +251,7 @@ import javax.annotation.Nullable; // Paper
import javax.annotation.Nonnull; // Paper
public final class CraftServer implements Server {
- private final String serverName = "Paper"; // Paper
+ private final String serverName = "Purpur"; // Paper // Purpur
private final String serverVersion;
private final String bukkitVersion = Versioning.getBukkitVersion();
private final Logger logger = Logger.getLogger("Minecraft");
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
index 774556a62eb240da42e84db4502e2ed43495be17..e9aee2d8a929bded46c79c3ea0f1fcfd172af438 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
@@ -11,7 +11,7 @@ public final class Versioning {
public static String getBukkitVersion() {
String result = "Unknown-Version";
- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties");
+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/net.pl3x.purpur/purpur-api/pom.properties"); // Purpur
Properties properties = new Properties();
if (stream != null) {
diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png
index a7d785f60c884ee4ee487cc364402d66c3dc2ecc..35ae7a94cebd4a9a16fc9112ccc248fa3cac5f32 100644
GIT binary patch
literal 17292
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
SDfV^%0000<MNUMnLSTXhlS0b?
literal 14310
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%0ABLt+m?son?j
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
WX&3$!%>|s_1IbA#OV)^+1pg1OmmZn`

View File

@@ -0,0 +1,511 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 9 May 2019 18:09:43 -0500
Subject: [PATCH] Purpur config files
diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
index 218f5bafeed8551b55b91c7fccaf6935c8b631ca..7bc497bcae6a6a752e3c432178cb1e3c633e0bec 100644
--- a/src/main/java/com/destroystokyo/paper/Metrics.java
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
@@ -593,8 +593,7 @@ public class Metrics {
boolean logFailedRequests = config.getBoolean("logFailedRequests", false);
// Only start Metrics, if it's enabled in the config
if (config.getBoolean("enabled", true)) {
- Metrics metrics = new Metrics("Paper", serverUUID, logFailedRequests, Bukkit.getLogger());
-
+ Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger()); // Purpur
metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> {
String minecraftVersion = Bukkit.getVersion();
minecraftVersion = minecraftVersion.substring(minecraftVersion.indexOf("MC: ") + 4, minecraftVersion.length() - 1);
@@ -602,8 +601,8 @@ public class Metrics {
}));
metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size()));
- metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : "offline"));
- metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown"));
+ metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : (PaperConfig.isProxyOnlineMode() ? "bungee" : "offline"))); // Purpur
+ metrics.addCustomChart(new Metrics.SimplePie("purpur_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Purpur
metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> {
Map<String, Map<String, Integer>> map = new HashMap<>();
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
index 71e29d29ed5c2d61832e2f124967bb223708406f..224669ecaad37ac2f16900700eea40ef52d938a5 100644
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
@@ -236,6 +236,30 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy
return this.anchor;
}
+ // Purpur start
+ public void sendSuccess(@Nullable String message) {
+ sendSuccess(message, false);
+ }
+
+ public void sendSuccess(@Nullable String message, boolean broadcastToOps) {
+ if (message == null) {
+ return;
+ }
+ sendSuccess(net.kyori.adventure.text.minimessage.MiniMessage.get().parse(message), broadcastToOps);
+ }
+
+ public void sendSuccess(@Nullable net.kyori.adventure.text.Component message) {
+ sendSuccess(message, false);
+ }
+
+ public void sendSuccess(@Nullable net.kyori.adventure.text.Component message, boolean broadcastToOps) {
+ if (message == null) {
+ return;
+ }
+ sendSuccess(io.papermc.paper.adventure.PaperAdventure.asVanilla(message), broadcastToOps);
+ }
+ // Purpur end
+
public void sendSuccess(Component message, boolean broadcastToOps) {
if (this.source.acceptsSuccess() && !this.silent) {
this.source.sendMessage(message, Util.NIL_UUID);
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index fce717f47bfb951e1483b96180864c66da2eb773..a8f91d39819687284f09a10152ef9b4ed5029394 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -230,6 +230,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
}
thread.start(); // Paper - start console thread after MinecraftServer.console & PaperConfig are initialized
com.destroystokyo.paper.PaperConfig.registerCommands();
+ // Purpur start
+ try {
+ net.pl3x.purpur.PurpurConfig.init((java.io.File) options.valueOf("purpur-settings"));
+ } catch (Exception e) {
+ DedicatedServer.LOGGER.error("Unable to load server configuration", e);
+ return false;
+ }
+ net.pl3x.purpur.PurpurConfig.registerCommands();
+ // Purpur end
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now
io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // load mappings for stacktrace deobf and etc.
io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 9cafd000b3533ed9fd35df2ec880f55e262084fb..c44dc4cefdd74437a39283800aa6e93372525fbd 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -168,6 +168,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper
public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
+ public final net.pl3x.purpur.PurpurWorldConfig purpurConfig; // Purpur
+
public final co.aikar.timings.WorldTimingsHandler timings; // Paper
public static BlockPos lastPhysicsProblem; // Spigot
private org.spigotmc.TickLimiter entityLimiter;
@@ -314,6 +316,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, final DimensionType dimensionmanager, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper - Anti-Xray - Pass executor
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper
+ this.purpurConfig = new net.pl3x.purpur.PurpurWorldConfig((ServerLevel) this, ((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), env); // Purpur
this.generator = gen;
this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);
this.ticksPerAnimalSpawns = this.getCraftServer().getTicksPerAnimalSpawns(); // CraftBukkit
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..f589e4376f88c7774a7fe999cad4d11a59379cd9
--- /dev/null
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -0,0 +1,159 @@
+package net.pl3x.purpur;
+
+import co.aikar.timings.TimingsManager;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableMap;
+import net.kyori.adventure.bossbar.BossBar;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.world.entity.EntityDimensions;
+import net.minecraft.world.entity.EntityType;
+import net.pl3x.purpur.command.PurpurCommand;
+import net.pl3x.purpur.task.TPSBarTask;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.InvalidConfigurationException;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+
+@SuppressWarnings("unused")
+public class PurpurConfig {
+ private static final String HEADER = "This is the main configuration file for Purpur.\n"
+ + "As you can see, there's tons to configure. Some options may impact gameplay, so use\n"
+ + "with caution, and make sure you know what each option does before configuring.\n"
+ + "\n"
+ + "If you need help with the configuration or have any questions related to Purpur,\n"
+ + "join us in our Discord guild.\n"
+ + "\n"
+ + "Website: https://github.com/pl3xgaming/Purpur \n"
+ + "Wiki: https://github.com/pl3xgaming/Purpur/wiki \n";
+ private static File CONFIG_FILE;
+ public static YamlConfiguration config;
+
+ private static Map<String, Command> commands;
+
+ static int version;
+ static boolean verbose;
+
+ public static void init(File configFile) {
+ CONFIG_FILE = configFile;
+ config = new YamlConfiguration();
+ try {
+ config.load(CONFIG_FILE);
+ } catch (IOException ignore) {
+ } catch (InvalidConfigurationException ex) {
+ Bukkit.getLogger().log(Level.SEVERE, "Could not load purpur.yml, please correct your syntax errors", ex);
+ throw Throwables.propagate(ex);
+ }
+ config.options().header(HEADER);
+ config.options().copyDefaults(true);
+ verbose = getBoolean("verbose", false);
+
+ commands = new HashMap<>();
+ commands.put("purpur", new PurpurCommand("purpur"));
+
+ version = getInt("config-version", 22);
+ set("config-version", 22);
+
+ readConfig(PurpurConfig.class, null);
+ }
+
+ protected static void log(String s) {
+ if (verbose) {
+ log(Level.INFO, s);
+ }
+ }
+
+ protected static void log(Level level, String s) {
+ Bukkit.getLogger().log(level, s);
+ }
+
+ public static void registerCommands() {
+ for (Map.Entry<String, Command> entry : commands.entrySet()) {
+ MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Purpur", entry.getValue());
+ }
+ }
+
+ static void readConfig(Class<?> clazz, Object instance) {
+ for (Method method : clazz.getDeclaredMethods()) {
+ if (Modifier.isPrivate(method.getModifiers())) {
+ if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) {
+ try {
+ method.setAccessible(true);
+ method.invoke(instance);
+ } catch (InvocationTargetException ex) {
+ throw Throwables.propagate(ex.getCause());
+ } catch (Exception ex) {
+ Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex);
+ }
+ }
+ }
+ }
+
+ try {
+ config.save(CONFIG_FILE);
+ } catch (IOException ex) {
+ Bukkit.getLogger().log(Level.SEVERE, "Could not save " + CONFIG_FILE, ex);
+ }
+ }
+
+ private static void set(String path, Object val) {
+ config.addDefault(path, val);
+ config.set(path, val);
+ }
+
+ private static String getString(String path, String def) {
+ config.addDefault(path, def);
+ return config.getString(path, config.getString(path));
+ }
+
+ private static boolean getBoolean(String path, boolean def) {
+ config.addDefault(path, def);
+ return config.getBoolean(path, config.getBoolean(path));
+ }
+
+ private static double getDouble(String path, double def) {
+ config.addDefault(path, def);
+ return config.getDouble(path, config.getDouble(path));
+ }
+
+ private static int getInt(String path, int def) {
+ config.addDefault(path, def);
+ return config.getInt(path, config.getInt(path));
+ }
+
+ private static <T> List getList(String path, T def) {
+ config.addDefault(path, def);
+ return config.getList(path, config.getList(path));
+ }
+
+ static Map<String, Object> getMap(String path, Map<String, Object> def) {
+ if (def != null && config.getConfigurationSection(path) == null) {
+ config.addDefault(path, def);
+ return def;
+ }
+ return toMap(config.getConfigurationSection(path));
+ }
+
+ private static Map<String, Object> toMap(ConfigurationSection section) {
+ ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
+ if (section != null) {
+ for (String key : section.getKeys(false)) {
+ Object obj = section.get(key);
+ if (obj != null) {
+ builder.put(key, obj instanceof ConfigurationSection val ? toMap(val) : obj);
+ }
+ }
+ }
+ return builder.build();
+ }
+}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..8bc89d48695c816a1db77f9cdffd05f35afea92a
--- /dev/null
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -0,0 +1,96 @@
+package net.pl3x.purpur;
+
+import net.minecraft.core.Registry;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.Difficulty;
+import net.minecraft.world.item.DyeColor;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.item.Items;
+import net.minecraft.world.level.Explosion;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.block.state.properties.Tilt;
+import net.pl3x.purpur.tool.Strippable;
+import net.pl3x.purpur.tool.Tillable;
+import net.pl3x.purpur.tool.Waxable;
+import net.pl3x.purpur.tool.Weatherable;
+import org.apache.commons.lang.BooleanUtils;
+import org.bukkit.ChatColor;
+import org.bukkit.World;
+import org.bukkit.configuration.ConfigurationSection;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.logging.Level;
+import static net.pl3x.purpur.PurpurConfig.log;
+
+@SuppressWarnings("unused")
+public class PurpurWorldConfig {
+
+ private final ServerLevel level;
+ private final String worldName;
+ private final World.Environment environment;
+
+ public PurpurWorldConfig(ServerLevel level, String worldName, World.Environment environment) {
+ this.level = level;
+ this.worldName = worldName;
+ this.environment = environment;
+ init();
+ }
+
+ public void init() {
+ log("-------- World Settings For [" + worldName + "] --------");
+ PurpurConfig.readConfig(PurpurWorldConfig.class, this);
+ }
+
+ private void set(String path, Object val) {
+ PurpurConfig.config.addDefault("world-settings.default." + path, val);
+ PurpurConfig.config.set("world-settings.default." + path, val);
+ if (PurpurConfig.config.get("world-settings." + worldName + "." + path) != null) {
+ PurpurConfig.config.addDefault("world-settings." + worldName + "." + path, val);
+ PurpurConfig.config.set("world-settings." + worldName + "." + path, val);
+ }
+ }
+
+ private ConfigurationSection getConfigurationSection(String path) {
+ ConfigurationSection section = PurpurConfig.config.getConfigurationSection("world-settings." + worldName + "." + path);
+ return section != null ? section : PurpurConfig.config.getConfigurationSection("world-settings.default." + path);
+ }
+
+ private String getString(String path, String def) {
+ PurpurConfig.config.addDefault("world-settings.default." + path, def);
+ return PurpurConfig.config.getString("world-settings." + worldName + "." + path, PurpurConfig.config.getString("world-settings.default." + path));
+ }
+
+ private boolean getBoolean(String path, boolean def) {
+ PurpurConfig.config.addDefault("world-settings.default." + path, def);
+ return PurpurConfig.config.getBoolean("world-settings." + worldName + "." + path, PurpurConfig.config.getBoolean("world-settings.default." + path));
+ }
+
+ private double getDouble(String path, double def) {
+ PurpurConfig.config.addDefault("world-settings.default." + path, def);
+ return PurpurConfig.config.getDouble("world-settings." + worldName + "." + path, PurpurConfig.config.getDouble("world-settings.default." + path));
+ }
+
+ private int getInt(String path, int def) {
+ PurpurConfig.config.addDefault("world-settings.default." + path, def);
+ return PurpurConfig.config.getInt("world-settings." + worldName + "." + path, PurpurConfig.config.getInt("world-settings.default." + path));
+ }
+
+ private <T> List<?> getList(String path, T def) {
+ PurpurConfig.config.addDefault("world-settings.default." + path, def);
+ return PurpurConfig.config.getList("world-settings." + worldName + "." + path, PurpurConfig.config.getList("world-settings.default." + path));
+ }
+
+ private Map<String, Object> getMap(String path, Map<String, Object> def) {
+ final Map<String, Object> fallback = PurpurConfig.getMap("world-settings.default." + path, def);
+ final Map<String, Object> value = PurpurConfig.getMap("world-settings." + worldName + "." + path, null);
+ return value.isEmpty() ? fallback : value;
+ }
+}
diff --git a/src/main/java/net/pl3x/purpur/command/PurpurCommand.java b/src/main/java/net/pl3x/purpur/command/PurpurCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..6e7f56fe2b78d7a09d5d130f2c88338fb8ae628e
--- /dev/null
+++ b/src/main/java/net/pl3x/purpur/command/PurpurCommand.java
@@ -0,0 +1,65 @@
+package net.pl3x.purpur.command;
+
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+import net.pl3x.purpur.PurpurConfig;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class PurpurCommand extends Command {
+ public PurpurCommand(String name) {
+ super(name);
+ this.description = "Purpur related commands";
+ this.usageMessage = "/purpur [reload | version]";
+ this.setPermission("bukkit.command.purpur");
+ }
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
+ if (args.length == 1) {
+ return Stream.of("reload", "version")
+ .filter(arg -> arg.startsWith(args[0].toLowerCase()))
+ .collect(Collectors.toList());
+ }
+ return Collections.emptyList();
+ }
+
+ @Override
+ public boolean execute(CommandSender sender, String commandLabel, String[] args) {
+ if (!testPermission(sender)) return true;
+
+ if (args.length != 1) {
+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
+ return false;
+ }
+
+ if (args[0].equalsIgnoreCase("reload")) {
+ Command.broadcastCommandMessage(sender, ChatColor.RED + "Please note that this command is not supported and may cause issues.");
+ Command.broadcastCommandMessage(sender, ChatColor.RED + "If you encounter any issues please use the /stop command to restart your server.");
+
+ MinecraftServer console = MinecraftServer.getServer();
+ PurpurConfig.init((File) console.options.valueOf("purpur-settings"));
+ for (ServerLevel level : console.getAllLevels()) {
+ level.purpurConfig.init();
+ }
+ console.server.reloadCount++;
+
+ Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Purpur config reload complete.");
+ } else if (args[0].equalsIgnoreCase("version")) {
+ Command verCmd = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version");
+ if (verCmd != null) {
+ return verCmd.execute(sender, commandLabel, new String[0]);
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 58fd726baccee28bcab6fb693616e7da5c87be8f..665eca7a2d8ad49f2016e3ec81a724bc638ab2a1 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -924,6 +924,7 @@ public final class CraftServer implements Server {
org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot
com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings")); // Paper
+ net.pl3x.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur
for (ServerLevel world : this.console.getAllLevels()) {
// world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
@@ -964,6 +965,7 @@ public final class CraftServer implements Server {
}
world.spigotConfig.init(); // Spigot
world.paperConfig.init(); // Paper
+ world.purpurConfig.init(); // Purpur
}
Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
@@ -979,6 +981,7 @@ public final class CraftServer implements Server {
this.reloadData();
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
com.destroystokyo.paper.PaperConfig.registerCommands(); // Paper
+ net.pl3x.purpur.PurpurConfig.registerCommands(); // Purpur
this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*");
this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions");
@@ -2566,6 +2569,18 @@ public final class CraftServer implements Server {
return com.destroystokyo.paper.PaperConfig.config;
}
+ // Purpur start
+ @Override
+ public YamlConfiguration getPurpurConfig() {
+ return net.pl3x.purpur.PurpurConfig.config;
+ }
+
+ @Override
+ public java.util.Properties getServerProperties() {
+ return getProperties().properties;
+ }
+ // Purpur end
+
@Override
public void restart() {
org.spigotmc.RestartCommand.restart();
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index 22e9dd17f62103c5061435099ce96a3d70d54808..5b527a32f56a82131168879106f76c1f6cbb7b30 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -147,6 +147,14 @@ public class Main {
.describedAs("Yml file");
// Paper end
+ // Purpur Start
+ acceptsAll(asList("purpur", "purpur-settings"), "File for purpur settings")
+ .withRequiredArg()
+ .ofType(File.class)
+ .defaultsTo(new File("purpur.yml"))
+ .describedAs("Yml file");
+ // Purpur end
+
// Paper start
acceptsAll(asList("server-name"), "Name of the server")
.withRequiredArg()

View File

@@ -0,0 +1,60 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 30 Jul 2021 14:31:25 -0500
Subject: [PATCH] Purpur client support
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 78fda0c982810b8b881a87099f355247566e513a..88b141e2d5518e5cbe43a48e209d85d4a51319e8 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -258,6 +258,7 @@ public class ServerPlayer extends Player {
public Integer clientViewDistance;
// CraftBukkit end
public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
+ public boolean purpurClient = false; // Purpur
public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 621ec8e8a197323da6b423fee57c816ac9d7c875..96c15c334f299cc289e55bc4b3286c498ca3334d 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -3120,6 +3120,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
private static final ResourceLocation CUSTOM_UNREGISTER = new ResourceLocation("unregister");
private static final ResourceLocation MINECRAFT_BRAND = new ResourceLocation("brand"); // Paper - Brand support
+ private static final ResourceLocation PURPUR_CLIENT = new ResourceLocation("purpur", "client"); // Purpur
@Override
public void handleCustomPayload(ServerboundCustomPayloadPacket packet) {
@@ -3144,6 +3145,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t unregister custom payload", ex);
this.disconnect("Invalid payload UNREGISTER!", org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause
}
+ // Purpur start
+ } else if (packet.identifier.equals(PURPUR_CLIENT)) {
+ try {
+ player.purpurClient = true;
+ } catch (Exception ignore) {
+ }
+ // Purpur end
} else {
try {
byte[] data = new byte[packet.data.readableBytes()];
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 4ff4143f3a7cd89ef92f4b8882fa3e5addfe0f06..614efd4204eb0cb712964c71566ad7e2c609c439 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2577,4 +2577,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
return this.spigot;
}
// Spigot end
+
+ // Purpur start
+ @Override
+ public boolean usesPurpurClient() {
+ return getHandle().purpurClient;
+ }
+ // Purpur end
}

View File

@@ -0,0 +1,143 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Tue, 29 Jun 2021 21:37:40 -0500
Subject: [PATCH] Component related conveniences
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 88b141e2d5518e5cbe43a48e209d85d4a51319e8..6c241da9f2711aeade0f3863e4e2bab1f6b242af 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1678,6 +1678,26 @@ public class ServerPlayer extends Player {
}
// CraftBukkit end
+ // Purpur start
+ public void sendActionBarMessage(@Nullable String message) {
+ if (message != null) {
+ sendActionBarMessage(net.kyori.adventure.text.minimessage.MiniMessage.get().parse(message));
+ }
+ }
+
+ public void sendActionBarMessage(@Nullable net.kyori.adventure.text.Component message) {
+ if (message != null) {
+ sendActionBarMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message));
+ }
+ }
+
+ public void sendActionBarMessage(@Nullable Component message) {
+ if (message != null) {
+ displayClientMessage(message, true);
+ }
+ }
+ // Purpur end
+
@Override
public void displayClientMessage(Component message, boolean actionBar) {
this.sendMessage(message, actionBar ? ChatType.GAME_INFO : ChatType.CHAT, Util.NIL_UUID);
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index eaa005c1c9b4386bcdbe1d6eb28c3eca7635066c..b0ff18e420d064db81f4e8f3a383e1d208abf783 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -1396,6 +1396,62 @@ public abstract class PlayerList {
}
// CraftBukkit end
+ // Purpur start
+ public void broadcast(@Nullable String message) {
+ broadcast(message, Util.NIL_UUID);
+ }
+
+ public void broadcast(@Nullable String message, ChatType type) {
+ broadcast(message, type, Util.NIL_UUID);
+ }
+
+ public void broadcast(@Nullable String message, UUID sender) {
+ broadcast(message, ChatType.SYSTEM, sender);
+ }
+
+ public void broadcast(@Nullable String message, ChatType type, UUID sender) {
+ if (message != null) {
+ broadcast(net.kyori.adventure.text.minimessage.MiniMessage.get().parse(message), type, sender);
+ }
+ }
+
+ public void broadcast(@Nullable net.kyori.adventure.text.Component message) {
+ broadcast(message, Util.NIL_UUID);
+ }
+
+ public void broadcast(@Nullable net.kyori.adventure.text.Component message, ChatType type) {
+ broadcast(message, type, Util.NIL_UUID);
+ }
+
+ public void broadcast(@Nullable net.kyori.adventure.text.Component message, UUID sender) {
+ broadcast(message, ChatType.SYSTEM, sender);
+ }
+
+ public void broadcast(@Nullable net.kyori.adventure.text.Component message, ChatType type, UUID sender) {
+ if (message != null) {
+ broadcast(io.papermc.paper.adventure.PaperAdventure.asVanilla(message), type, sender);
+ }
+ }
+
+ public void broadcast(@Nullable Component message) {
+ broadcast(message, Util.NIL_UUID);
+ }
+
+ public void broadcast(@Nullable Component message, ChatType type) {
+ broadcast(message, type, Util.NIL_UUID);
+ }
+
+ public void broadcast(@Nullable Component message, UUID sender) {
+ broadcast(message, ChatType.SYSTEM, sender);
+ }
+
+ public void broadcast(@Nullable Component message, ChatType type, UUID sender) {
+ if (message != null) {
+ broadcastMessage(message, type, sender);
+ }
+ }
+ // Purpur end
+
public void broadcastMessage(Component message, ChatType type, UUID sender) {
this.server.sendMessage(message, sender);
Iterator iterator = this.players.iterator();
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index b7c4700fd5db14c77e7ee78311dd77a754d9d41c..33a0272b35c8823fe125b8dcb0b1616656672925 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -3602,6 +3602,34 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
return SlotAccess.NULL;
}
+ // Purpur Start
+ public void sendMessage(@Nullable String message) {
+ sendMessage(message, Util.NIL_UUID);
+ }
+
+ public void sendMessage(@Nullable String message, UUID sender) {
+ if (org.apache.commons.lang3.StringUtils.isNotEmpty(message)) {
+ sendMessage(net.kyori.adventure.text.minimessage.MiniMessage.get().parse(message), sender);
+ }
+ }
+
+ public void sendMessage(@Nullable net.kyori.adventure.text.Component message) {
+ sendMessage(message, Util.NIL_UUID);
+ }
+
+ public void sendMessage(@Nullable net.kyori.adventure.text.Component message, UUID sender) {
+ if (message != null) {
+ sendMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message), sender);
+ }
+ }
+
+ public void sendMessage(@Nullable Component message) {
+ if (message != null) {
+ sendMessage(message, Util.NIL_UUID);
+ }
+ }
+ // Purpur end
+
@Override
public void sendMessage(Component message, UUID sender) {}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Fri, 5 Jun 2020 21:30:19 -0500
Subject: [PATCH] Timings stuff
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
index e29b0a90019b12bd6586ad0f7b5314f307e527ba..e3f5a66eb4e36cfd633dfa4ae64eab5015b0e961 100644
--- a/src/main/java/co/aikar/timings/TimingsExport.java
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
@@ -226,9 +226,14 @@ public class TimingsExport extends Thread {
// Information on the users Config
parent.put("config", createObject(
- pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)),
+ // Purpur start
+ pair("server.properties", mapAsJSON(Bukkit.spigot().getServerProperties())),
pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)),
- pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null))
+ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)),
+ pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)),
+ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)),
+ pair("purpur", mapAsJSON(Bukkit.spigot().getPurpurConfig(), null))
+ // Purpur end
));
new TimingsExport(listeners, parent, history).start();
@@ -269,6 +274,19 @@ public class TimingsExport extends Thread {
return timingsCost;
}
+ // Purpur start
+ private static JSONObject mapAsJSON(java.util.Properties properties) {
+ JSONObject object = new JSONObject();
+ for (String key : properties.stringPropertyNames()) {
+ if (key.startsWith("rcon") || key.startsWith("query") || key.equals("level-seed") || TimingsManager.hiddenConfigs.contains(key)) {
+ continue;
+ }
+ object.put(key, valAsJSON(properties.get(key), key));
+ }
+ return object;
+ }
+ // Purpur end
+
private static JSONObject mapAsJSON(ConfigurationSection config, String parentKey) {
JSONObject object = new JSONObject();
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index 2509a170b8ddd812ad5be49e5345ec5a3c0cf2b8..3937a78981fe3e2cb0db752365d20a3165ff3333 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -206,7 +206,7 @@ public class PaperConfig {
private static void timings() {
boolean timings = getBoolean("timings.enabled", true);
boolean verboseTimings = getBoolean("timings.verbose", true);
- TimingsManager.url = getString("timings.url", "https://timings.aikar.co/");
+ TimingsManager.url = getString("timings.url", "https://timings.pl3x.net/");
if (!TimingsManager.url.endsWith("/")) {
TimingsManager.url += "/";
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index f5cdf3338411650add4a2eb41e0412182b1f6fdf..8747593597ed270400ef3d3f6b141a0fb370f1b4 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -161,4 +161,17 @@ public class PurpurConfig {
private static void messages() {
cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob);
}
+
+ private static void timingsSettings() {
+ if (version < 18) {
+ String oldVal = getString("settings.timings.url", "https://timings.pl3x.net");
+ com.destroystokyo.paper.PaperConfig.config.set("timings.url", oldVal);
+ TimingsManager.url = getString("timings.url", oldVal);
+ if (!TimingsManager.url.endsWith("/")) {
+ TimingsManager.url += "/";
+ }
+ set("settings.timings.url", null);
+ }
+ if (!co.aikar.timings.TimingsManager.hiddenConfigs.contains("server-ip")) co.aikar.timings.TimingsManager.hiddenConfigs.add("server-ip");
+ }
}

View File

@@ -0,0 +1,253 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 23 May 2019 21:50:37 -0500
Subject: [PATCH] Barrels and enderchests 6 rows
diff --git a/src/main/java/net/minecraft/world/inventory/ChestMenu.java b/src/main/java/net/minecraft/world/inventory/ChestMenu.java
index e9d9245f7efaaeefc8f107b8016a462ce173816a..56dcc1b6ceaad998be62e3b8c125e8f5e833e4c0 100644
--- a/src/main/java/net/minecraft/world/inventory/ChestMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/ChestMenu.java
@@ -67,10 +67,30 @@ public class ChestMenu extends AbstractContainerMenu {
return new ChestMenu(MenuType.GENERIC_9x6, syncId, playerInventory, 6);
}
+ // Purpur start
+ public static ChestMenu oneRow(int syncId, Inventory playerInventory, Container inventory) {
+ return new ChestMenu(MenuType.GENERIC_9x1, syncId, playerInventory, inventory, 1);
+ }
+
+ public static ChestMenu twoRows(int syncId, Inventory playerInventory, Container inventory) {
+ return new ChestMenu(MenuType.GENERIC_9x2, syncId, playerInventory, inventory, 2);
+ }
+ // Purpur end
+
public static ChestMenu threeRows(int syncId, Inventory playerInventory, Container inventory) {
return new ChestMenu(MenuType.GENERIC_9x3, syncId, playerInventory, inventory, 3);
}
+ // Purpur start
+ public static ChestMenu fourRows(int syncId, Inventory playerInventory, Container inventory) {
+ return new ChestMenu(MenuType.GENERIC_9x4, syncId, playerInventory, inventory, 4);
+ }
+
+ public static ChestMenu fiveRows(int syncId, Inventory playerInventory, Container inventory) {
+ return new ChestMenu(MenuType.GENERIC_9x5, syncId, playerInventory, inventory, 5);
+ }
+ // Purpur end
+
public static ChestMenu sixRows(int syncId, Inventory playerInventory, Container inventory) {
return new ChestMenu(MenuType.GENERIC_9x6, syncId, playerInventory, inventory, 6);
}
diff --git a/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java b/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java
index 59acb1aab21e2dce0f046942f124b50ac1cb8d0f..a26cb4e4e4e23a06c970ea3c42c1060108708568 100644
--- a/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java
+++ b/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java
@@ -29,11 +29,34 @@ public class PlayerEnderChestContainer extends SimpleContainer {
}
public PlayerEnderChestContainer(Player owner) {
- super(27);
+ super(net.pl3x.purpur.PurpurConfig.enderChestSixRows ? 54 : 27); // Purpur
this.owner = owner;
// CraftBukkit end
}
+ // Purpur start
+ @Override
+ public int getContainerSize() {
+ if (net.pl3x.purpur.PurpurConfig.enderChestSixRows && net.pl3x.purpur.PurpurConfig.enderChestPermissionRows && owner != null && owner.getGameProfile() != null) {
+ org.bukkit.craftbukkit.entity.CraftHumanEntity bukkit = owner.getBukkitEntity();
+ if (bukkit.hasPermission("purpur.enderchest.rows.six")) {
+ return 54;
+ } else if (bukkit.hasPermission("purpur.enderchest.rows.five")) {
+ return 45;
+ } else if (bukkit.hasPermission("purpur.enderchest.rows.four")) {
+ return 36;
+ } else if (bukkit.hasPermission("purpur.enderchest.rows.three")) {
+ return 27;
+ } else if (bukkit.hasPermission("purpur.enderchest.rows.two")) {
+ return 18;
+ } else if (bukkit.hasPermission("purpur.enderchest.rows.one")) {
+ return 9;
+ }
+ }
+ return super.getContainerSize();
+ }
+ // Purpur end
+
public void setActiveChest(EnderChestBlockEntity blockEntity) {
this.activeChest = blockEntity;
}
diff --git a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java
index 7e45c97acce83a9fe8ada486e9fcdafe58769736..e3c84ad3fad4ee479bb00b7dc02a2502f2088984 100644
--- a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java
@@ -86,6 +86,27 @@ public class EnderChestBlock extends AbstractChestBlock<EnderChestBlockEntity> i
EnderChestBlockEntity enderChestBlockEntity = (EnderChestBlockEntity)blockEntity;
playerEnderChestContainer.setActiveChest(enderChestBlockEntity);
player.openMenu(new SimpleMenuProvider((syncId, inventory, playerx) -> {
+ // Purpur start
+ if (net.pl3x.purpur.PurpurConfig.enderChestSixRows) {
+ if (net.pl3x.purpur.PurpurConfig.enderChestPermissionRows) {
+ org.bukkit.craftbukkit.entity.CraftHumanEntity bukkitPlayer = player.getBukkitEntity();
+ if (bukkitPlayer.hasPermission("purpur.enderchest.rows.six")) {
+ return ChestMenu.sixRows(syncId, inventory, playerEnderChestContainer);
+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.five")) {
+ return ChestMenu.fiveRows(syncId, inventory, playerEnderChestContainer);
+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.four")) {
+ return ChestMenu.fourRows(syncId, inventory, playerEnderChestContainer);
+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.three")) {
+ return ChestMenu.threeRows(syncId, inventory, playerEnderChestContainer);
+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.two")) {
+ return ChestMenu.twoRows(syncId, inventory, playerEnderChestContainer);
+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.one")) {
+ return ChestMenu.oneRow(syncId, inventory, playerEnderChestContainer);
+ }
+ }
+ return ChestMenu.sixRows(syncId, inventory, playerEnderChestContainer);
+ }
+ // Purpur end
return ChestMenu.threeRows(syncId, inventory, playerEnderChestContainer);
}, CONTAINER_TITLE));
player.awardStat(Stats.OPEN_ENDERCHEST);
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
index f494063ead9c6303fb3ca880aba2a877ae8d83ab..aa4d3a8a51050df14d5df4a494ee6665a065e2cb 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
@@ -68,7 +68,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
public BarrelBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntityType.BARREL, pos, state);
- this.items = NonNullList.withSize(27, ItemStack.EMPTY);
+ // Purpur start
+ this.items = NonNullList.withSize(switch (net.pl3x.purpur.PurpurConfig.barrelRows) {
+ case 6 -> 54;
+ case 5 -> 45;
+ case 4 -> 36;
+ case 2 -> 18;
+ case 1 -> 9;
+ default -> 27;
+ }, ItemStack.EMPTY);
+ // Purpur end
this.openersCounter = new ContainerOpenersCounter() {
@Override
protected void onOpen(Level world, BlockPos pos, BlockState state) {
@@ -120,7 +129,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
@Override
public int getContainerSize() {
- return 27;
+ // Purpur start
+ return switch (net.pl3x.purpur.PurpurConfig.barrelRows) {
+ case 6 -> 54;
+ case 5 -> 45;
+ case 4 -> 36;
+ case 2 -> 18;
+ case 1 -> 9;
+ default -> 27;
+ };
+ // Purpur end
}
@Override
@@ -140,7 +158,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
@Override
protected AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) {
- return ChestMenu.threeRows(syncId, playerInventory, (Container) this);
+ // Purpur start
+ return switch (net.pl3x.purpur.PurpurConfig.barrelRows) {
+ case 6 -> ChestMenu.sixRows(syncId, playerInventory, this);
+ case 5 -> ChestMenu.fiveRows(syncId, playerInventory, this);
+ case 4 -> ChestMenu.fourRows(syncId, playerInventory, this);
+ case 2 -> ChestMenu.twoRows(syncId, playerInventory, this);
+ case 1 -> ChestMenu.oneRow(syncId, playerInventory, this);
+ default -> ChestMenu.threeRows(syncId, playerInventory, this);
+ };
+ // Purpur end
}
@Override
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index 8747593597ed270400ef3d3f6b141a0fb370f1b4..eaff201b75f74a41e14c43d522d7b87faf9296b3 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -174,4 +174,39 @@ public class PurpurConfig {
}
if (!co.aikar.timings.TimingsManager.hiddenConfigs.contains("server-ip")) co.aikar.timings.TimingsManager.hiddenConfigs.add("server-ip");
}
+
+ public static int barrelRows = 3;
+ public static boolean enderChestSixRows = false;
+ public static boolean enderChestPermissionRows = false;
+ private static void blockSettings() {
+ if (version < 3) {
+ boolean oldValue = getBoolean("settings.barrel.packed-barrels", true);
+ set("settings.blocks.barrel.six-rows", oldValue);
+ set("settings.packed-barrels", null);
+ oldValue = getBoolean("settings.large-ender-chests", true);
+ set("settings.blocks.ender_chest.six-rows", oldValue);
+ set("settings.large-ender-chests", null);
+ }
+ if (version < 20) {
+ boolean oldValue = getBoolean("settings.blocks.barrel.six-rows", false);
+ set("settings.blocks.barrel.rows", oldValue ? 6 : 3);
+ set("settings.blocks.barrel.six-rows", null);
+ }
+ barrelRows = getInt("settings.blocks.barrel.rows", barrelRows);
+ if (barrelRows < 1 || barrelRows > 6) {
+ Bukkit.getLogger().severe("settings.blocks.barrel.rows must be 1-6, resetting to default");
+ barrelRows = 3;
+ }
+ org.bukkit.event.inventory.InventoryType.BARREL.setDefaultSize(switch (barrelRows) {
+ case 6 -> 54;
+ case 5 -> 45;
+ case 4 -> 36;
+ case 2 -> 18;
+ case 1 -> 9;
+ default -> 27;
+ });
+ enderChestSixRows = getBoolean("settings.blocks.ender_chest.six-rows", enderChestSixRows);
+ org.bukkit.event.inventory.InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27);
+ enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows);
+ }
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
index 60fa587ce17e138d2baf8959c26e25ed1db17a4a..72d656dfbdf21849f0c7a41de2f1dcf963623bec 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
@@ -165,8 +165,19 @@ public class CraftContainer extends AbstractContainerMenu {
case PLAYER:
case CHEST:
case ENDER_CHEST:
+ // Purpur start
+ this.delegate = new ChestMenu(net.pl3x.purpur.PurpurConfig.enderChestSixRows ? MenuType.GENERIC_9x6 : MenuType.GENERIC_9x3, windowId, bottom, top, top.getContainerSize() / 9);
+ break;
case BARREL:
- this.delegate = new ChestMenu(MenuType.GENERIC_9x3, windowId, bottom, top, top.getContainerSize() / 9);
+ this.delegate = new ChestMenu(switch (net.pl3x.purpur.PurpurConfig.barrelRows) {
+ case 6 -> MenuType.GENERIC_9x6;
+ case 5 -> MenuType.GENERIC_9x5;
+ case 4 -> MenuType.GENERIC_9x4;
+ case 2 -> MenuType.GENERIC_9x2;
+ case 1 -> MenuType.GENERIC_9x1;
+ default -> MenuType.GENERIC_9x3;
+ }, windowId, bottom, top, top.getContainerSize() / 9);
+ // Purpur end
break;
case DISPENSER:
case DROPPER:
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
index 396a4ae3d5a829eda78ef98561333aea300aa722..91478d614a56d1ac371187515d4c92b2a373b65c 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
@@ -81,7 +81,7 @@ public class CraftInventory implements Inventory {
@Override
public void setContents(ItemStack[] items) {
- if (this.getSize() < items.length) {
+ if (false && this.getSize() < items.length) { // Purpur
throw new IllegalArgumentException("Invalid inventory size; expected " + this.getSize() + " or less");
}

View File

@@ -0,0 +1,141 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 18 Oct 2019 22:50:12 -0500
Subject: [PATCH] Llama API
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java
index e037d618955de9a213a9cd90752b29d189faace4..34dec0a94840a8865f1d80857ec54a1022ae5b84 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java
@@ -22,6 +22,7 @@ public class LlamaFollowCaravanGoal extends Goal {
@Override
public boolean canUse() {
+ if (!this.llama.shouldJoinCaravan) return false; // Purpur
if (!this.llama.isLeashed() && !this.llama.inCaravan()) {
List<Entity> list = this.llama.level.getEntities(this.llama, this.llama.getBoundingBox().inflate(9.0D, 4.0D, 9.0D), (entity) -> {
EntityType<?> entityType = entity.getType();
@@ -71,6 +72,7 @@ public class LlamaFollowCaravanGoal extends Goal {
@Override
public boolean canContinueToUse() {
+ if (!this.llama.shouldJoinCaravan) return false; // Purpur
if (this.llama.inCaravan() && this.llama.getCaravanHead().isAlive() && this.firstIsLeashed(this.llama, 0)) {
double d = this.llama.distanceToSqr(this.llama.getCaravanHead());
if (d > 676.0D) {
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java
index 6ee84f21e5dc64cbd5bdf51acd69fff09494f056..98da60e297f08dc77bf1cd754458cb138ca9d219 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java
@@ -65,6 +65,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob {
private Llama caravanHead;
@Nullable
private Llama caravanTail;
+ public boolean shouldJoinCaravan = true; // Purpur
public Llama(EntityType<? extends Llama> type, Level world) {
super(type, world);
@@ -149,7 +150,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob {
if (!this.inventory.getItem(1).isEmpty()) {
nbt.put("DecorItem", this.inventory.getItem(1).save(new CompoundTag()));
}
-
+ nbt.putBoolean("Purpur.ShouldJoinCaravan", shouldJoinCaravan); // Purpur
}
@Override
@@ -161,6 +162,12 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob {
this.inventory.setItem(1, ItemStack.of(nbt.getCompound("DecorItem")));
}
+ // Purpur start
+ if (nbt.contains("Purpur.ShouldJoinCaravan")) {
+ this.shouldJoinCaravan = nbt.getBoolean("Purpur.ShouldJoinCaravan");
+ }
+ // Purpur end
+
this.updateContainerEquipment();
}
@@ -482,6 +489,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob {
public void leaveCaravan() {
if (this.caravanHead != null) {
+ new net.pl3x.purpur.event.entity.LlamaLeaveCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity()).callEvent(); // Purpur
this.caravanHead.caravanTail = null;
}
@@ -489,6 +497,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob {
}
public void joinCaravan(Llama llama) {
+ if (!shouldJoinCaravan || !new net.pl3x.purpur.event.entity.LlamaJoinCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity(), (org.bukkit.entity.Llama) llama.getBukkitEntity()).callEvent()) return; // Purpur
this.caravanHead = llama;
this.caravanHead.caravanTail = this;
}
@@ -506,6 +515,13 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob {
return this.caravanHead;
}
+ // Purpur start
+ @Nullable
+ public Llama getCaravanTail() {
+ return this.caravanTail;
+ }
+ // Purpur end
+
@Override
protected double followLeashSpeed() {
return 2.0D;
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java
index 6ad12711a82d7be42ba41c0428779f86536fd900..4dd47cac823a63056985079e75588dd3d81f0af4 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java
@@ -64,4 +64,46 @@ public class CraftLlama extends CraftChestedHorse implements Llama, com.destroys
public EntityType getType() {
return EntityType.LLAMA;
}
+
+ // Purpur start
+ @Override
+ public boolean shouldJoinCaravan() {
+ return getHandle().shouldJoinCaravan;
+ }
+
+ @Override
+ public void setShouldJoinCaravan(boolean shouldJoinCaravan) {
+ getHandle().shouldJoinCaravan = shouldJoinCaravan;
+ }
+
+ @Override
+ public boolean inCaravan() {
+ return getHandle().inCaravan();
+ }
+
+ @Override
+ public void joinCaravan(@org.jetbrains.annotations.NotNull Llama llama) {
+ getHandle().joinCaravan(((CraftLlama) llama).getHandle());
+ }
+
+ @Override
+ public void leaveCaravan() {
+ getHandle().leaveCaravan();
+ }
+
+ @Override
+ public boolean hasCaravanTail() {
+ return getHandle().hasCaravanTail();
+ }
+
+ @Override
+ public Llama getCaravanHead() {
+ return getHandle().getCaravanHead() == null ? null : (Llama) getHandle().getCaravanHead().getBukkitEntity();
+ }
+
+ @Override
+ public Llama getCaravanTail() {
+ return getHandle().getCaravanTail() == null ? null : (Llama) getHandle().getCaravanTail().getBukkitEntity();
+ }
+ // Purpur end
}

View File

@@ -0,0 +1,318 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 8 Aug 2019 15:29:15 -0500
Subject: [PATCH] AFK API
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 6c7628bb6f7f46555650195b19318c7f338825ae..f819cc4f5e6e2d5c820a840fa76226ea381b96d6 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1953,8 +1953,58 @@ public class ServerPlayer extends Player {
public void resetLastActionTime() {
this.lastActionTime = Util.getMillis();
+ this.setAfk(false); // Purpur
}
+ // Purpur Start
+ private boolean isAfk = false;
+
+ @Override
+ public void setAfk(boolean afk) {
+ if (this.isAfk == afk) {
+ return;
+ }
+
+ String msg = afk ? net.pl3x.purpur.PurpurConfig.afkBroadcastAway : net.pl3x.purpur.PurpurConfig.afkBroadcastBack;
+
+ net.pl3x.purpur.event.PlayerAFKEvent event = new net.pl3x.purpur.event.PlayerAFKEvent(this.getBukkitEntity(), afk, level.purpurConfig.idleTimeoutKick, msg, !Bukkit.isPrimaryThread());
+ if (!event.callEvent() || event.shouldKick()) {
+ return;
+ }
+
+ this.isAfk = afk;
+
+ if (!afk) {
+ resetLastActionTime();
+ }
+
+ msg = event.getBroadcastMsg();
+ if (msg != null && !msg.isEmpty()) {
+ server.getPlayerList().broadcast(String.format(msg, this.getGameProfile().getName()));
+ }
+
+ if (level.purpurConfig.idleTimeoutUpdateTabList) {
+ if (afk) {
+ getBukkitEntity().setPlayerListName(net.pl3x.purpur.PurpurConfig.afkTabListPrefix + getScoreboardName() + net.pl3x.purpur.PurpurConfig.afkTabListSuffix, true);
+ } else {
+ getBukkitEntity().setPlayerListName(getScoreboardName());
+ }
+ }
+
+ ((ServerLevel) level).updateSleepingPlayerList();
+ }
+
+ @Override
+ public boolean isAfk() {
+ return this.isAfk;
+ }
+
+ @Override
+ public boolean canBeCollidedWith() {
+ return !this.isAfk() && super.canBeCollidedWith();
+ }
+ // Purpur End
+
public ServerStatsCounter getStats() {
return this.stats;
}
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 6a71bbd96f3720321bb840d94bbd8942378fa695..5c15deee4105df67716edb117ecf0ac0ba978e39 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -294,6 +294,20 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
private boolean justTeleported = false;
private boolean hasMoved; // Spigot
+ // Purpur start
+ private final com.google.common.cache.LoadingCache<CraftPlayer, Boolean> kickPermissionCache = com.google.common.cache.CacheBuilder.newBuilder()
+ .maximumSize(1000)
+ .expireAfterWrite(1, java.util.concurrent.TimeUnit.MINUTES)
+ .build(
+ new com.google.common.cache.CacheLoader<>() {
+ @Override
+ public Boolean load(CraftPlayer player) {
+ return player.hasPermission("purpur.bypassIdleKick");
+ }
+ }
+ );
+ // Purpur end
+
public CraftPlayer getCraftPlayer() {
return (this.player == null) ? null : (CraftPlayer) this.player.getBukkitEntity();
}
@@ -390,6 +404,12 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
}
if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) (this.server.getPlayerIdleTimeout() * 1000 * 60) && !this.player.wonGame) { // Paper - Prevent AFK kick while watching end credits.
+ // Purpur start
+ this.player.setAfk(true);
+ if (!this.player.level.purpurConfig.idleTimeoutKick || kickPermissionCache.getUnchecked(this.player.getBukkitEntity())) {
+ return;
+ }
+ // Purpur end
this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854
this.disconnect(new TranslatableComponent("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause
}
@@ -662,6 +682,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
this.lastYaw = to.getYaw();
this.lastPitch = to.getPitch();
+ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetLastActionTime(); // Purpur
+
// Skip the first time we do this
if (true) { // Spigot - don't skip any move events
Location oldTo = to.clone();
@@ -1425,7 +1447,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
if (!this.player.isChangingDimension() && d11 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.gameMode.isCreative() && this.player.gameMode.getGameModeForPlayer() != GameType.SPECTATOR) { // Spigot
flag1 = true; // Paper - diff on change, this should be moved wrongly
- ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString());
+ ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!, ({})", this.player.getName().getString(), d11); // Purpur
}
this.player.absMoveTo(d0, d1, d2, f, f1);
@@ -1475,6 +1497,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
this.lastYaw = to.getYaw();
this.lastPitch = to.getPitch();
+ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetLastActionTime(); // Purpur
+
// Skip the first time we do this
if (from.getX() != Double.MAX_VALUE) {
Location oldTo = to.clone();
diff --git a/src/main/java/net/minecraft/server/players/SleepStatus.java b/src/main/java/net/minecraft/server/players/SleepStatus.java
index 823efad652d8ff9e96b99375b102fef6f017716e..60f89d7c77a5e792e21e93e35ed1670bd565799a 100644
--- a/src/main/java/net/minecraft/server/players/SleepStatus.java
+++ b/src/main/java/net/minecraft/server/players/SleepStatus.java
@@ -19,7 +19,7 @@ public class SleepStatus {
public boolean areEnoughDeepSleeping(int percentage, List<ServerPlayer> players) {
// CraftBukkit start
- int j = (int) players.stream().filter((eh) -> { return eh.isSleepingLongEnough() || eh.fauxSleeping; }).count();
+ int j = (int) players.stream().filter((eh) -> { return eh.isSleepingLongEnough() || eh.fauxSleeping || (eh.level.purpurConfig.idleTimeoutCountAsSleeping && eh.isAfk()); }).count(); // Purpur
boolean anyDeepSleep = players.stream().anyMatch(Player::isSleepingLongEnough);
return anyDeepSleep && j >= this.sleepersNeeded(percentage);
@@ -52,7 +52,7 @@ public class SleepStatus {
if (!entityplayer.isSpectator()) {
++this.activePlayers;
- if (entityplayer.isSleeping() || entityplayer.fauxSleeping) { // CraftBukkit
+ if ((entityplayer.isSleeping() || entityplayer.fauxSleeping) || (entityplayer.level.purpurConfig.idleTimeoutCountAsSleeping && entityplayer.isAfk())) { // CraftBukkit // Purpur
++this.sleepingPlayers;
}
// CraftBukkit start
diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java
index a060cca08631fb42041e3a79a9abc422fe7757af..e7b11d1ba984ea14f0cdf8e84f9eaab46b3f1684 100644
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
@@ -27,6 +27,7 @@ public final class EntitySelector {
return !entity.isSpectator();
};
public static Predicate<Player> isInsomniac = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper
+ public static Predicate<Player> notAfk = (player) -> !player.isAfk(); // Purpur
private EntitySelector() {}
// Paper start
diff --git a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
index 3ee691d4caccbc1b3e0f52decb41d436ac0d08ec..dc0900dd6aee20cf1735bbb490b79d7e33468751 100644
--- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
+++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
@@ -63,6 +63,10 @@ public class TargetingConditions {
return false;
} else if (this.selector != null && !this.selector.test(targetEntity)) {
return false;
+ // Purpur start
+ } else if (!targetEntity.level.purpurConfig.idleTimeoutTargetPlayer && targetEntity instanceof net.minecraft.server.level.ServerPlayer player && player.isAfk()) {
+ return false;
+ // Purpur end
} else {
if (baseEntity == null) {
if (this.isCombat && (!targetEntity.canBeSeenAsEnemy() || targetEntity.level.getDifficulty() == Difficulty.PEACEFUL)) {
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index 218ad12db29d2201667dc252b0ee55b6d94b89f7..3d66d2e86cef17bcd8813d4c2b29078beebf23fe 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -196,6 +196,13 @@ public abstract class Player extends LivingEntity {
// Purpur start
public abstract void resetLastActionTime();
+ public void setAfk(boolean afk) {
+ }
+
+ public boolean isAfk() {
+ return false;
+ }
+
@Override
public boolean processClick(InteractionHand hand) {
Entity vehicle = getRootVehicle();
diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java
index 7224c56e8a68870364c6538c82c04f371b74aabd..730e8a856b9e9560a62d959cefb6efadd056e9d3 100644
--- a/src/main/java/net/minecraft/world/level/EntityGetter.java
+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java
@@ -161,7 +161,7 @@ public interface EntityGetter {
default boolean hasNearbyAlivePlayer(double x, double y, double z, double range) {
for(Player player : this.players()) {
- if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) {
+ if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player) && EntitySelector.notAfk.test(player)) {
double d = player.distanceToSqr(x, y, z);
if (range < 0.0D || d < range * range) {
return true;
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index eaff201b75f74a41e14c43d522d7b87faf9296b3..7f572658706fdc3009490bd54c2393f7685c7de7 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -158,8 +158,16 @@ public class PurpurConfig {
}
public static String cannotRideMob = "<red>You cannot mount that mob";
+ public static String afkBroadcastAway = "<yellow><italic>%s is now AFK";
+ public static String afkBroadcastBack = "<yellow><italic>%s is no longer AFK";
+ public static String afkTabListPrefix = "[AFK] ";
+ public static String afkTabListSuffix = "";
private static void messages() {
cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob);
+ afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway);
+ afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack);
+ afkTabListPrefix = getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix);
+ afkTabListSuffix = getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix);
}
private static void timingsSettings() {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 20215510857b8e49ea0c93d35eddfbad7cd355b0..996171e7271e62e72c0b2b213c21caf53c815e97 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -94,6 +94,24 @@ public class PurpurWorldConfig {
return value.isEmpty() ? fallback : value;
}
+ public boolean idleTimeoutKick = true;
+ public boolean idleTimeoutTickNearbyEntities = true;
+ public boolean idleTimeoutCountAsSleeping = false;
+ public boolean idleTimeoutUpdateTabList = false;
+ public boolean idleTimeoutTargetPlayer = true;
+ private void playerSettings() {
+ if (PurpurConfig.version < 19) {
+ boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer);
+ set("gameplay-mechanics.player.idle-timeout.mods-target", null);
+ set("gameplay-mechanics.player.idle-timeout.mobs-target", oldVal);
+ }
+ idleTimeoutKick = getBoolean("gameplay-mechanics.player.idle-timeout.kick-if-idle", idleTimeoutKick);
+ idleTimeoutTickNearbyEntities = getBoolean("gameplay-mechanics.player.idle-timeout.tick-nearby-entities", idleTimeoutTickNearbyEntities);
+ idleTimeoutCountAsSleeping = getBoolean("gameplay-mechanics.player.idle-timeout.count-as-sleeping", idleTimeoutCountAsSleeping);
+ idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList);
+ idleTimeoutTargetPlayer = getBoolean("gameplay-mechanics.player.idle-timeout.mobs-target", idleTimeoutTargetPlayer);
+ }
+
public boolean babiesAreRidable = true;
public boolean untamedTamablesAreRidable = true;
public boolean useNightVisionWhenRiding = false;
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 614efd4204eb0cb712964c71566ad7e2c609c439..bd68d2509fe08955eaab08a73924d6d58064c2b7 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -424,10 +424,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override
public void setPlayerListName(String name) {
+ // Purpur start
+ setPlayerListName(name, false);
+ }
+ public void setPlayerListName(String name, boolean useMM) {
+ // Purpur end
if (name == null) {
name = getName();
}
- this.getHandle().listName = name.equals(getName()) ? null : CraftChatMessage.fromStringOrNull(name);
+ this.getHandle().listName = name.equals(getName()) ? null : useMM ? io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.get().parse(name)) : CraftChatMessage.fromStringOrNull(name); // Purpur
for (ServerPlayer player : (List<ServerPlayer>) server.getHandle().players) {
if (player.getBukkitEntity().canSee(this)) {
player.connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.UPDATE_DISPLAY_NAME, this.getHandle()));
@@ -2583,5 +2588,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
public boolean usesPurpurClient() {
return getHandle().purpurClient;
}
+
+ @Override
+ public boolean isAfk() {
+ return getHandle().isAfk();
+ }
+
+ @Override
+ public void setAfk(boolean setAfk) {
+ getHandle().setAfk(setAfk);
+ }
+
+ @Override
+ public void resetIdleTimer() {
+ getHandle().resetLastActionTime();
+ }
// Purpur end
}
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index 9c456cce42ef9d1654df9047d6fc1e0da13dc1c9..12ffca6a545e4af5c66ecd8b15d9d8e20a6327c1 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -194,6 +194,7 @@ public class ActivationRange
{
player.activatedTick = MinecraftServer.currentTick;
+ if (!player.level.purpurConfig.idleTimeoutTickNearbyEntities && player.isAfk()) continue; // Purpur
ActivationRange.maxBB = player.getBoundingBox().inflate( maxRange, 256, maxRange );
ActivationType.MISC.boundingBox = player.getBoundingBox().inflate( miscActivationRange, 256, miscActivationRange );
ActivationType.RAIDER.boundingBox = player.getBoundingBox().inflate( raiderActivationRange, 256, raiderActivationRange );

View File

@@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sun, 26 May 2019 15:19:14 -0500
Subject: [PATCH] Bring back server name
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
index 0544ac93513d3a274bfb53bb6120bd598f4d603b..9ce5984fbeba4839290c9d213d441957d38fe835 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
@@ -18,6 +18,7 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
public final boolean onlineMode = this.get("online-mode", true);
public final boolean preventProxyConnections = this.get("prevent-proxy-connections", false);
public final String serverIp = this.get("server-ip", "");
+ public final String serverName = this.get("server-name", "Unknown Server"); // Purpur
public final boolean spawnAnimals = this.get("spawn-animals", true);
public final boolean spawnNpcs = this.get("spawn-npcs", true);
public final boolean pvp = this.get("pvp", true);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 665eca7a2d8ad49f2016e3ec81a724bc638ab2a1..67f23320a4dc4e2eef4b55bf371b367dcf5d8369 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2735,4 +2735,11 @@ public final class CraftServer implements Server {
}
// Paper end
+
+ // Purpur start
+ @Override
+ public String getServerName() {
+ return this.getProperties().serverName;
+ }
+ // Purpur end
}

View File

@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Sat, 21 Mar 2020 11:47:39 -0500
Subject: [PATCH] Configurable server mod name
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 2965c79daf2126b691307442ad4a41ce3420ed34..66c357a01759c04463c663bad10bd1be9753ec26 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1730,7 +1730,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@DontObfuscate
public String getServerModName() {
- return "Purpur"; // Purpur - Purpur > // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla!
+ return net.pl3x.purpur.PurpurConfig.serverModName; // Purpur - Purpur > // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla!
}
public SystemReport fillSystemReport(SystemReport details) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index 7f572658706fdc3009490bd54c2393f7685c7de7..bc5f937e7480d954680c7b9f1d698aff3e28665d 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -170,6 +170,11 @@ public class PurpurConfig {
afkTabListSuffix = getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix);
}
+ public static String serverModName = "Purpur";
+ private static void serverModName() {
+ serverModName = getString("settings.server-mod-name", serverModName);
+ }
+
private static void timingsSettings() {
if (version < 18) {
String oldVal = getString("settings.timings.url", "https://timings.pl3x.net");

View File

@@ -0,0 +1,84 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Sun, 5 May 2019 12:58:45 -0500
Subject: [PATCH] LivingEntity safeFallDistance
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 99d0403fbe40206e91687a208f790f5b4bb08cae..a0b8154c44401dde57a729e202ba59688aea54bd 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -255,6 +255,7 @@ public abstract class LivingEntity extends Entity {
// CraftBukkit start
public int expToDrop;
public int maxAirTicks = 300;
+ public float safeFallDistance = 3.0F; // Purpur
public boolean forceDrops;
public ArrayList<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
public final org.bukkit.craftbukkit.attribute.CraftAttributeMap craftAttributes;
@@ -353,8 +354,8 @@ public abstract class LivingEntity extends Entity {
this.tryAddSoulSpeed();
}
- if (!this.level.isClientSide && this.fallDistance > 3.0F && onGround) {
- float f = (float) Mth.ceil(this.fallDistance - 3.0F);
+ if (!this.level.isClientSide && this.fallDistance > this.safeFallDistance && onGround) { // Purpur
+ float f = (float) Mth.ceil(this.fallDistance - this.safeFallDistance); // Purpur
if (!landedState.isAir()) {
double d1 = Math.min((double) (0.2F + f / 15.0F), 2.5D);
@@ -1891,7 +1892,7 @@ public abstract class LivingEntity extends Entity {
MobEffectInstance mobeffect = this.getEffect(MobEffects.JUMP);
float f2 = mobeffect == null ? 0.0F : (float) (mobeffect.getAmplifier() + 1);
- return Mth.ceil((fallDistance - 3.0F - f2) * damageMultiplier);
+ return Mth.ceil((fallDistance - this.safeFallDistance - f2) * damageMultiplier); // Purpur
}
protected void playBlockFallSound() {
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java
index 44d5f629da36a88e5245e9a2cff39dd946be4ea1..dbd34f589a146b9b408318c3810321ab6bce57f6 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java
@@ -321,7 +321,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener,
@Override
protected int calculateFallDamage(float fallDistance, float damageMultiplier) {
- return Mth.ceil((fallDistance * 0.5F - 3.0F) * damageMultiplier);
+ return Mth.ceil((fallDistance * 0.5F - this.safeFallDistance) * damageMultiplier);
}
protected int getInventorySize() {
diff --git a/src/main/java/net/minecraft/world/entity/monster/Giant.java b/src/main/java/net/minecraft/world/entity/monster/Giant.java
index c67f33f2e2e0ff5c2a85782185103325a6bf4535..a8ffdc8810152d77668aad7bad15a00c4d194d4c 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Giant.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Giant.java
@@ -12,6 +12,7 @@ import net.minecraft.world.level.LevelReader;
public class Giant extends Monster {
public Giant(EntityType<? extends Giant> type, Level world) {
super(type, world);
+ this.safeFallDistance = 10.0F; // Purpur
}
// Purpur start
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index 4cdc80b31ac56b63df80fefec87e4ba8b4dcf455..916d487372efdbf68a383f4ae761cccd75e0a1d8 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -920,4 +920,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
throw new IllegalArgumentException(entityCategory + " is an unrecognized entity category");
}
// Paper end
+
+ // Purpur start
+ @Override
+ public float getSafeFallDistance() {
+ return getHandle().safeFallDistance;
+ }
+
+ @Override
+ public void setSafeFallDistance(float safeFallDistance) {
+ getHandle().safeFallDistance = safeFallDistance;
+ }
+ // Purpur end
}

View File

@@ -0,0 +1,57 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Tue, 23 Jul 2019 10:07:16 -0500
Subject: [PATCH] Lagging threshold
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 66c357a01759c04463c663bad10bd1be9753ec26..1049f5f40d07f0c0fde965b1ab927607651b3e38 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -306,6 +306,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public static final int TICK_TIME = 1000000000 / MinecraftServer.TPS;
private static final int SAMPLE_INTERVAL = 20; // Paper
public final double[] recentTps = new double[ 3 ];
+ public boolean lagging = false; // Purpur
public final SlackActivityAccountant slackActivityAccountant = new SlackActivityAccountant();
// Spigot end
public static long currentTickLong = 0L; // Paper
@@ -1265,6 +1266,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.recentTps[1] = tps5.getAverage();
this.recentTps[2] = tps15.getAverage();
// Paper end
+ lagging = recentTps[0] < net.pl3x.purpur.PurpurConfig.laggingThreshold; // Purpur
tickSection = curTime;
}
// Spigot end
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index bc5f937e7480d954680c7b9f1d698aff3e28665d..c0e7027ad804d7b801ef8cb94963c113c95735d1 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -188,6 +188,11 @@ public class PurpurConfig {
if (!co.aikar.timings.TimingsManager.hiddenConfigs.contains("server-ip")) co.aikar.timings.TimingsManager.hiddenConfigs.add("server-ip");
}
+ public static double laggingThreshold = 19.0D;
+ private static void tickLoopSettings() {
+ laggingThreshold = getDouble("settings.lagging-threshold", laggingThreshold);
+ }
+
public static int barrelRows = 3;
public static boolean enderChestSixRows = false;
public static boolean enderChestPermissionRows = false;
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 67f23320a4dc4e2eef4b55bf371b367dcf5d8369..895799585e1a6964b709094d4aa4dfe8fe6470d4 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2741,5 +2741,10 @@ public final class CraftServer implements Server {
public String getServerName() {
return this.getProperties().serverName;
}
+
+ @Override
+ public boolean isLagging() {
+ return getServer().lagging;
+ }
// Purpur end
}

View File

@@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 5 Jul 2019 18:21:00 -0500
Subject: [PATCH] PlayerSetSpawnerTypeWithEggEvent
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
index 1c446dba5de89698397041ee38a2e1a00bec8a56..686417e2bd45c1f10964a8c22014b98de4f8d381 100644
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
@@ -286,6 +286,16 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T> {
return (EntityType) Registry.register((Registry) Registry.ENTITY_TYPE, id, (Object) type.build(id));
}
+ // Purpur start
+ public static EntityType<?> getFromBukkitType(org.bukkit.entity.EntityType bukkitType) {
+ return getFromKey(new ResourceLocation(bukkitType.getKey().toString()));
+ }
+
+ public static EntityType<?> getFromKey(ResourceLocation location) {
+ return Registry.ENTITY_TYPE.get(location);
+ }
+ // Purpur end
+
public static ResourceLocation getKey(EntityType<?> type) {
return Registry.ENTITY_TYPE.getKey(type);
}
@@ -453,6 +463,16 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T> {
return this.category;
}
+ // Purpur start
+ public String getName() {
+ return Registry.ENTITY_TYPE.getKey(this).getPath();
+ }
+
+ public String getTranslatedName() {
+ return getDescription().getString();
+ }
+ // Purpur end
+
public String getDescriptionId() {
if (this.descriptionId == null) {
this.descriptionId = Util.makeDescriptionId("entity", Registry.ENTITY_TYPE.getKey(this));
diff --git a/src/main/java/net/minecraft/world/item/SpawnEggItem.java b/src/main/java/net/minecraft/world/item/SpawnEggItem.java
index 6cb0be998757d3ec89cc1064480c3a3ddc3cc381..deb02b8263dd9fe4196cb1db3d73ed9db533f41d 100644
--- a/src/main/java/net/minecraft/world/item/SpawnEggItem.java
+++ b/src/main/java/net/minecraft/world/item/SpawnEggItem.java
@@ -68,6 +68,15 @@ public class SpawnEggItem extends Item {
BaseSpawner mobspawnerabstract = ((SpawnerBlockEntity) tileentity).getSpawner();
EntityType<?> entitytypes = this.getType(itemstack.getTag());
+ // Purpur start
+ org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());
+ net.pl3x.purpur.event.PlayerSetSpawnerTypeWithEggEvent event = new net.pl3x.purpur.event.PlayerSetSpawnerTypeWithEggEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), bukkitBlock, (org.bukkit.block.CreatureSpawner) bukkitBlock.getState(), org.bukkit.entity.EntityType.fromName(entitytypes.getName()));
+ if (!event.callEvent()) {
+ return InteractionResult.FAIL;
+ }
+ entitytypes = EntityType.getFromBukkitType(event.getEntityType());
+ // Purpur end
+
mobspawnerabstract.setEntityId(entitytypes);
tileentity.setChanged();
world.sendBlockUpdated(blockposition, iblockdata, iblockdata, 3);

View File

@@ -0,0 +1,63 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 20 Jul 2013 22:40:56 -0400
Subject: [PATCH] EMC - MonsterEggSpawnEvent
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
index 686417e2bd45c1f10964a8c22014b98de4f8d381..3aeeba4465a5ff551a56ac50e23036074f9315c3 100644
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
@@ -334,13 +334,20 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T> {
@Nullable
public Entity spawn(ServerLevel world, @Nullable ItemStack stack, @Nullable Player player, BlockPos pos, MobSpawnType spawnReason, boolean alignPosition, boolean invertY) {
- return this.spawn(world, stack == null ? null : stack.getTag(), stack != null && stack.hasCustomHoverName() ? stack.getHoverName() : null, player, pos, spawnReason, alignPosition, invertY);
+ return this.spawn(world, stack, stack == null ? null : stack.getTag(), stack != null && stack.hasCustomHoverName() ? stack.getHoverName() : null, player, pos, spawnReason, alignPosition, invertY); // Purpur
}
@Nullable
public T spawn(ServerLevel world, @Nullable CompoundTag itemNbt, @Nullable Component name, @Nullable Player player, BlockPos pos, MobSpawnType spawnReason, boolean alignPosition, boolean invertY) {
+ // Purpur start
+ return spawn(world, null, itemNbt, name, player, pos, spawnReason, alignPosition, invertY); // Purpur
+ }
+
+ @Nullable
+ public T spawn(ServerLevel world, @Nullable ItemStack stack, @Nullable CompoundTag itemNbt, @Nullable Component name, @Nullable Player player, BlockPos pos, MobSpawnType spawnReason, boolean alignPosition, boolean invertY) {
+ // Purpur end
// CraftBukkit start
- return this.spawnCreature(world, itemNbt, name, player, pos, spawnReason, alignPosition, invertY, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG);
+ return this.spawn(world, stack, itemNbt, name, player, pos, spawnReason, alignPosition, invertY, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG, null); // Purpur
}
@Nullable
@@ -365,9 +372,29 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T> {
}
}
// Paper end
+ // Purpur start
+ return this.spawn(worldserver, null, nbttagcompound, ichatbasecomponent, entityhuman, blockposition, enummobspawn, flag, flag1, spawnReason, op);
+ }
+
+ @Nullable
+ public T spawn(ServerLevel worldserver, @Nullable ItemStack stack, @Nullable CompoundTag nbttagcompound, @Nullable Component ichatbasecomponent, @Nullable Player entityhuman, BlockPos blockposition, MobSpawnType enummobspawn, boolean flag, boolean flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason, @Nullable java.util.function.Consumer<T> op) {
+ // Purpur end
T t0 = this.create(worldserver, nbttagcompound, ichatbasecomponent, entityhuman, blockposition, enummobspawn, flag, flag1);
if (t0 != null && op != null) op.accept(t0); // Paper
+ // Purpur start
+ if (spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG && stack != null && t0 != null) {
+ final net.pl3x.purpur.event.entity.MonsterEggSpawnEvent event = new net.pl3x.purpur.event.entity.MonsterEggSpawnEvent(entityhuman != null ? entityhuman.getBukkitEntity() : null, t0.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack));
+ if (!event.callEvent()) {
+ t0.setRemoved(Entity.RemovalReason.DISCARDED);
+ return null;
+ }
+ if (event.getEntity().getEntityId() != t0.getId()) {
+ return (T) ((org.bukkit.craftbukkit.entity.CraftEntity) event.getEntity()).getHandle();
+ }
+ }
+ // Purpur end
+
if (t0 != null) {
worldserver.addAllEntities(t0, spawnReason);
return !t0.isRemoved() ? t0 : null; // Don't return an entity when CreatureSpawnEvent is canceled

View File

@@ -0,0 +1,169 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Sat, 2 May 2020 20:55:44 -0500
Subject: [PATCH] Player invulnerabilities
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index f819cc4f5e6e2d5c820a840fa76226ea381b96d6..7368e7df44c95aa5daa84e617d13ef140c3f96ed 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -259,6 +259,7 @@ public class ServerPlayer extends Player {
// CraftBukkit end
public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
public boolean purpurClient = false; // Purpur
+ public boolean acceptingResourcePack = false; // Purpur
public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
@@ -335,6 +336,7 @@ public class ServerPlayer extends Player {
this.bukkitPickUpLoot = true;
this.maxHealthCache = this.getMaxHealth();
this.cachedSingleMobDistanceMap = new com.destroystokyo.paper.util.PooledHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper
+ this.spawnInvulnerableTime = world.purpurConfig.playerSpawnInvulnerableTicks; // Purpur
}
// Paper start - Chunk priority
public BlockPos getPointInFront(double inFront) {
@@ -976,6 +978,12 @@ public class ServerPlayer extends Player {
}
+ // Purpur start
+ public boolean isSpawnInvulnerable() {
+ return spawnInvulnerableTime > 0 || frozen;
+ }
+ // Purpur end
+
@Override
public boolean hurt(DamageSource source, float amount) {
if (this.isInvulnerableTo(source)) {
@@ -983,7 +991,7 @@ public class ServerPlayer extends Player {
} else {
boolean flag = this.server.isDedicatedServer() && this.isPvpAllowed() && "fall".equals(source.msgId);
- if (!flag && this.spawnInvulnerableTime > 0 && source != DamageSource.OUT_OF_WORLD) {
+ if (!flag && isSpawnInvulnerable() && source != DamageSource.OUT_OF_WORLD) { // Purpur
return false;
} else {
if (source instanceof EntityDamageSource) {
@@ -1158,6 +1166,7 @@ public class ServerPlayer extends Player {
}
// Paper end
+ this.spawnInvulnerableTime = worldserver.purpurConfig.playerSpawnInvulnerableTicks; // Purpur
return this;
}
}
@@ -1943,6 +1952,7 @@ public class ServerPlayer extends Player {
}
public void sendTexturePack(String url, String hash, boolean required, @Nullable Component resourcePackPrompt) {
+ this.acceptingResourcePack = true; // Purpur
this.connection.send(new ClientboundResourcePackPacket(url, hash, required, resourcePackPrompt));
}
@@ -2449,9 +2459,17 @@ public class ServerPlayer extends Player {
@Override
public boolean isImmobile() {
- return super.isImmobile() || (this.connection != null && this.connection.isDisconnected()); // Paper
+ return super.isImmobile() || frozen || (this.connection != null && this.connection.isDisconnected()); // Paper // Purpur
}
+ // Purpur start
+ private boolean frozen = false;
+
+ public void setFrozen(boolean frozen) {
+ this.frozen = frozen;
+ }
+ // Purpur end
+
@Override
public Scoreboard getScoreboard() {
return this.getBukkitEntity().getScoreboard().getHandle();
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 5c15deee4105df67716edb117ecf0ac0ba978e39..b836820ce38bbb9b0594c4cedcf716b4cf85485f 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1940,12 +1940,21 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
@Override
public void handleResourcePackResponse(ServerboundResourcePackPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
+ // Purpur start
+ if (player.level.purpurConfig.playerInvulnerableWhileAcceptingResourcePack && !this.player.acceptingResourcePack) {
+ ServerGamePacketListenerImpl.LOGGER.info("Disconnecting {} due to resource pack packet exploitation attempt", this.player.getName());
+ this.disconnect(new TranslatableComponent("multiplayer.texturePrompt.failure.line1")); // "Server resource pack couldn't be applied"
+ return;
+ }
+ // Purpur end
if (packet.getAction() == ServerboundResourcePackPacket.Action.DECLINED && this.server.isResourcePackRequired()) {
ServerGamePacketListenerImpl.LOGGER.info("Disconnecting {} due to resource pack rejection", this.player.getName());
this.disconnect(new TranslatableComponent("multiplayer.requiredTexturePrompt.disconnect"), org.bukkit.event.player.PlayerKickEvent.Cause.RESOURCE_PACK_REJECTION); // Paper - add cause
}
// Paper start
PlayerResourcePackStatusEvent.Status packStatus = PlayerResourcePackStatusEvent.Status.values()[packet.action.ordinal()];
+ if (player.level.purpurConfig.playerInvulnerableWhileAcceptingResourcePack) player.setFrozen(packStatus == PlayerResourcePackStatusEvent.Status.ACCEPTED); // Purpur
+ this.player.acceptingResourcePack = packStatus == PlayerResourcePackStatusEvent.Status.ACCEPTED; // Purpur
player.getBukkitEntity().setResourcePackStatus(packStatus);
this.cserver.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(this.getCraftPlayer(), packStatus)); // CraftBukkit
// Paper end
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index b0ff18e420d064db81f4e8f3a383e1d208abf783..8e4c01a9b8994c3467bbb64661d457ce64ba3a6b 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -998,6 +998,8 @@ public abstract class PlayerList {
}
// Paper end
+ entityplayer1.spawnInvulnerableTime = entityplayer1.level.purpurConfig.playerSpawnInvulnerableTicks; // Purpur
+
// CraftBukkit end
return entityplayer1;
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 996171e7271e62e72c0b2b213c21caf53c815e97..8e9ba3a8582c8e5d1e14bf3bfa8ecfce5ccf7b0c 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -99,6 +99,8 @@ public class PurpurWorldConfig {
public boolean idleTimeoutCountAsSleeping = false;
public boolean idleTimeoutUpdateTabList = false;
public boolean idleTimeoutTargetPlayer = true;
+ public int playerSpawnInvulnerableTicks = 60;
+ public boolean playerInvulnerableWhileAcceptingResourcePack = false;
private void playerSettings() {
if (PurpurConfig.version < 19) {
boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer);
@@ -110,6 +112,8 @@ public class PurpurWorldConfig {
idleTimeoutCountAsSleeping = getBoolean("gameplay-mechanics.player.idle-timeout.count-as-sleeping", idleTimeoutCountAsSleeping);
idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList);
idleTimeoutTargetPlayer = getBoolean("gameplay-mechanics.player.idle-timeout.mobs-target", idleTimeoutTargetPlayer);
+ playerSpawnInvulnerableTicks = getInt("gameplay-mechanics.player.spawn-invulnerable-ticks", playerSpawnInvulnerableTicks);
+ playerInvulnerableWhileAcceptingResourcePack = getBoolean("gameplay-mechanics.player.invulnerable-while-accepting-resource-pack", playerInvulnerableWhileAcceptingResourcePack);
}
public boolean babiesAreRidable = true;
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index bd68d2509fe08955eaab08a73924d6d58064c2b7..e72e2ec797526772dc9c490739f5b45e4d135c89 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2603,5 +2603,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
public void resetIdleTimer() {
getHandle().resetLastActionTime();
}
+
+ @Override
+ public boolean isSpawnInvulnerable() {
+ return getHandle().isSpawnInvulnerable();
+ }
+
+ @Override
+ public int getSpawnInvulnerableTicks() {
+ return getHandle().spawnInvulnerableTime;
+ }
+
+ @Override
+ public void setSpawnInvulnerableTicks(int spawnInvulnerableTime) {
+ getHandle().spawnInvulnerableTime = spawnInvulnerableTime;
+ }
// Purpur end
}

View File

@@ -0,0 +1,146 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Sun, 19 Apr 2020 00:17:56 -0500
Subject: [PATCH] Anvil API
diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
index b62c6b56867b645520cb3c3e382ec96d421e7e97..ca8dd8b7f7bf8826472f11cb9472cf84c0368f34 100644
--- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
@@ -2,8 +2,12 @@ package net.minecraft.world.inventory;
import java.util.Iterator;
import java.util.Map;
+import net.minecraft.nbt.IntTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
+import net.minecraft.network.protocol.game.ClientboundContainerSetDataPacket;
+import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.Tag;
import net.minecraft.world.entity.player.Inventory;
@@ -42,6 +46,8 @@ public class AnvilMenu extends ItemCombinerMenu {
public int maximumRepairCost = 40;
private CraftInventoryView bukkitEntity;
// CraftBukkit end
+ public boolean bypassCost = false; // Purpur
+ public boolean canDoUnsafeEnchants = false; // Purpur
public AnvilMenu(int syncId, Inventory inventory) {
this(syncId, inventory, ContainerLevelAccess.NULL);
@@ -60,12 +66,14 @@ public class AnvilMenu extends ItemCombinerMenu {
@Override
protected boolean mayPickup(Player player, boolean present) {
- return (player.getAbilities().instabuild || player.experienceLevel >= this.cost.get()) && this.cost.get() >= 0; // Paper - fix anvil prepare event not working with 0 xp
+ return (player.getAbilities().instabuild || player.experienceLevel >= this.cost.get()) && (bypassCost || this.cost.get() >= 0); // Paper - fix anvil prepare event not working with 0 xp // Purpur
}
@Override
protected void onTake(Player player, ItemStack stack) {
+ if (net.pl3x.purpur.event.inventory.AnvilTakeResultEvent.getHandlerList().getRegisteredListeners().length > 0) new net.pl3x.purpur.event.inventory.AnvilTakeResultEvent(player.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack)).callEvent(); // Purpur
if (!player.getAbilities().instabuild) {
+ if (bypassCost) ((ServerPlayer) player).lastSentExp = -1; else // Purpur
player.giveExperienceLevels(-this.cost.get());
}
@@ -116,6 +124,12 @@ public class AnvilMenu extends ItemCombinerMenu {
@Override
public void createResult() {
+ // Purpur start
+ bypassCost = false;
+ canDoUnsafeEnchants = false;
+ if (net.pl3x.purpur.event.inventory.AnvilUpdateResultEvent.getHandlerList().getRegisteredListeners().length > 0) new net.pl3x.purpur.event.inventory.AnvilUpdateResultEvent(getBukkitView()).callEvent();
+ // Purpur end
+
ItemStack itemstack = this.inputSlots.getItem(0);
this.cost.set(1);
@@ -192,7 +206,7 @@ public class AnvilMenu extends ItemCombinerMenu {
int i2 = (Integer) map1.get(enchantment);
i2 = l1 == i2 ? i2 + 1 : Math.max(i2, l1);
- boolean flag3 = enchantment.canEnchant(itemstack);
+ boolean flag3 = canDoUnsafeEnchants || enchantment.canEnchant(itemstack); // Purpur
if (this.player.getAbilities().instabuild || itemstack.is(Items.ENCHANTED_BOOK)) {
flag3 = true;
@@ -204,7 +218,7 @@ public class AnvilMenu extends ItemCombinerMenu {
Enchantment enchantment1 = (Enchantment) iterator1.next();
if (enchantment1 != enchantment && !enchantment.isCompatibleWith(enchantment1)) {
- flag3 = false;
+ flag3 = canDoUnsafeEnchants; // Purpur
++i;
}
}
@@ -275,6 +289,13 @@ public class AnvilMenu extends ItemCombinerMenu {
this.cost.set(this.maximumRepairCost - 1); // CraftBukkit
}
+ // Purpur start
+ if (bypassCost && cost.get() >= maximumRepairCost) {
+ itemstack.addTagElement("Purpur.realCost", IntTag.valueOf(cost.get()));
+ cost.set(maximumRepairCost - 1);
+ }
+ // Purpur end
+
if (this.cost.get() >= this.maximumRepairCost && !this.player.getAbilities().instabuild) { // CraftBukkit
itemstack1 = ItemStack.EMPTY;
}
@@ -297,6 +318,12 @@ public class AnvilMenu extends ItemCombinerMenu {
org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemstack1); // CraftBukkit
sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686: Always send completed inventory to stay in sync with client
this.broadcastChanges();
+ // Purpur start
+ if (canDoUnsafeEnchants && itemstack1 != ItemStack.EMPTY) {
+ ((ServerPlayer) player).connection.send(new ClientboundContainerSetSlotPacket(containerId, incrementStateId(), 2, itemstack1));
+ ((ServerPlayer) player).connection.send(new ClientboundContainerSetDataPacket(containerId, 0, cost.get()));
+ }
+ // Purpur end
}
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java
index 3ff03e3e8c723d0f2a7c115d4dba01f1b3c2c46e..4dc71c761371400fb92e6943ba44bf40968dae97 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java
@@ -9,7 +9,7 @@ import org.bukkit.inventory.AnvilInventory;
public class CraftInventoryAnvil extends CraftResultInventory implements AnvilInventory {
private final Location location;
- private final AnvilMenu container;
+ public final AnvilMenu container; // Purpur - private -> public
public CraftInventoryAnvil(Location location, Container inventory, Container resultInventory, AnvilMenu container) {
super(inventory, resultInventory);
@@ -47,4 +47,26 @@ public class CraftInventoryAnvil extends CraftResultInventory implements AnvilIn
Preconditions.checkArgument(levels >= 0, "Maximum repair cost must be positive (or 0)");
container.maximumRepairCost = levels;
}
+
+ // Purpur start
+ @Override
+ public boolean canBypassCost() {
+ return container.bypassCost;
+ }
+
+ @Override
+ public void setBypassCost(boolean bypassCost) {
+ container.bypassCost = bypassCost;
+ }
+
+ @Override
+ public boolean canDoUnsafeEnchants() {
+ return container.canDoUnsafeEnchants;
+ }
+
+ @Override
+ public void setDoUnsafeEnchants(boolean canDoUnsafeEnchants) {
+ container.canDoUnsafeEnchants = canDoUnsafeEnchants;
+ }
+ // Purpur end
}

View File

@@ -0,0 +1,59 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Tue, 23 Jul 2019 08:28:21 -0500
Subject: [PATCH] Configurable villager brain ticks
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index c19030be3e65e317c979610e3cc130ffdf183622..136b6f0f19c9ece222eedbf2b20b118e206ee3e9 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -141,6 +141,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}, MemoryModuleType.MEETING_POINT, (entityvillager, villageplacetype) -> {
return villageplacetype == PoiType.MEETING;
});
+ private final int brainTickOffset; // Purpur
public Villager(EntityType<? extends Villager> entityType, Level world) {
this(entityType, world, VillagerType.PLAINS);
@@ -153,6 +154,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
this.getNavigation().setCanFloat(true);
this.setCanPickUpLoot(true);
this.setVillagerData(this.getVillagerData().setType(type).setProfession(VillagerProfession.NONE));
+ this.brainTickOffset = getRandom().nextInt(100); // Purpur
}
// Purpur start
@@ -271,6 +273,10 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
protected void customServerAiStep() { mobTick(false); }
protected void mobTick(boolean inactive) {
this.level.getProfiler().push("villagerBrain");
+ // Purpur start
+ boolean tick = (level.getGameTime() + brainTickOffset) % level.purpurConfig.villagerBrainTicks == 0;
+ if (((ServerLevel) level).getServer().lagging ? tick : level.purpurConfig.villagerUseBrainTicksOnlyWhenLagging || tick)
+ // Purpur end
if (!inactive) this.getBrain().tick((ServerLevel) this.level, this); // CraftBukkit - decompile error // Paper
this.level.getProfiler().pop();
if (this.assignProfessionWhenSpawned) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 8e9ba3a8582c8e5d1e14bf3bfa8ecfce5ccf7b0c..6df320ab8214669517d5de30a28f044a5a6b4a33 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1077,6 +1077,8 @@ public class PurpurWorldConfig {
public boolean villagerRidable = false;
public boolean villagerRidableInWater = false;
public double villagerMaxHealth = 20.0D;
+ public int villagerBrainTicks = 1;
+ public boolean villagerUseBrainTicksOnlyWhenLagging = true;
private void villagerSettings() {
villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable);
villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater);
@@ -1086,6 +1088,8 @@ public class PurpurWorldConfig {
set("mobs.villager.attributes.max_health", oldValue);
}
villagerMaxHealth = getDouble("mobs.villager.attributes.max_health", villagerMaxHealth);
+ villagerBrainTicks = getInt("mobs.villager.brain-ticks", villagerBrainTicks);
+ villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging);
}
public boolean vindicatorRidable = false;

View File

@@ -0,0 +1,73 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 11 Oct 2019 00:17:39 -0500
Subject: [PATCH] Alternative Keepalive Handling
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index b836820ce38bbb9b0594c4cedcf716b4cf85485f..68d51846987f4c5707cfc9dec737728770a66f11 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -228,6 +228,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
private long keepAliveTime = Util.getMillis();
private boolean keepAlivePending;
private long keepAliveChallenge;
+ private java.util.List<Long> keepAlives = new java.util.ArrayList<>(); // Purpur
// CraftBukkit start - multithreaded fields
private AtomicInteger chatSpamTickCount = new AtomicInteger();
private final java.util.concurrent.atomic.AtomicInteger tabSpamLimiter = new java.util.concurrent.atomic.AtomicInteger(); // Paper - configurable tab spam limits
@@ -372,6 +373,21 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
long currentTime = Util.getMillis();
long elapsedTime = currentTime - this.keepAliveTime;
+ // Purpur start
+ if (net.pl3x.purpur.PurpurConfig.useAlternateKeepAlive) {
+ if (elapsedTime >= 1000L) { // 1 second
+ if (!processedDisconnect && keepAlives.size() > KEEPALIVE_LIMIT) {
+ LOGGER.warn("{} was kicked due to keepalive timeout!", player.getName());
+ disconnect(new TranslatableComponent("disconnect.timeout"));
+ } else {
+ keepAliveTime = currentTime; // hijack this field for 1 second intervals
+ keepAlives.add(currentTime); // currentTime is ID
+ send(new ClientboundKeepAlivePacket(currentTime));
+ }
+ }
+ } else
+ // Purpur end
+
if (this.keepAlivePending) {
if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected
ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked due to keepalive timeout!", this.player.getScoreboardName()); // more info
@@ -3112,6 +3128,16 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
@Override
public void handleKeepAlive(ServerboundKeepAlivePacket packet) {
+ // Purpur start
+ if (net.pl3x.purpur.PurpurConfig.useAlternateKeepAlive) {
+ long id = packet.getId();
+ if (keepAlives.size() > 0 && keepAlives.contains(id)) {
+ int ping = (int) (Util.getMillis() - id);
+ player.latency = (player.latency * 3 + ping) / 4;
+ keepAlives.clear(); // we got a valid response, lets roll with it and forget the rest
+ }
+ } else
+ // Purpur end
//PlayerConnectionUtils.ensureMainThread(packetplayinkeepalive, this, this.player.getWorldServer()); // CraftBukkit // Paper - This shouldn't be on the main thread
if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) {
int i = (int) (Util.getMillis() - this.keepAliveTime);
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index c0e7027ad804d7b801ef8cb94963c113c95735d1..4b6bb477db0af506508e73dd42155429777b49d0 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -193,6 +193,11 @@ public class PurpurConfig {
laggingThreshold = getDouble("settings.lagging-threshold", laggingThreshold);
}
+ public static boolean useAlternateKeepAlive = false;
+ private static void useAlternateKeepAlive() {
+ useAlternateKeepAlive = getBoolean("settings.use-alternate-keepalive", useAlternateKeepAlive);
+ }
+
public static int barrelRows = 3;
public static boolean enderChestSixRows = false;
public static boolean enderChestPermissionRows = false;

View File

@@ -0,0 +1,224 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 9 May 2019 14:27:37 -0500
Subject: [PATCH] Silk touch spawners
diff --git a/src/main/java/io/papermc/paper/adventure/PaperAdventure.java b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java
index f763a3ea5796737304e0c1f41349622e1d7adadf..26c5c3c6e7c51ad6ccc9bac05e2af4972658179d 100644
--- a/src/main/java/io/papermc/paper/adventure/PaperAdventure.java
+++ b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java
@@ -91,6 +91,7 @@ public final class PaperAdventure {
})
.build();
public static final LegacyComponentSerializer LEGACY_SECTION_UXRC = LegacyComponentSerializer.builder().flattener(FLATTENER).hexColors().useUnusualXRepeatedCharacterHexFormat().build();
+ public static final LegacyComponentSerializer LEGACY_AMPERSAND = LegacyComponentSerializer.builder().character(LegacyComponentSerializer.AMPERSAND_CHAR).hexColors().build(); // Purpur
public static final PlainComponentSerializer PLAIN = PlainComponentSerializer.builder().flattener(FLATTENER).build();
public static final GsonComponentSerializer GSON = GsonComponentSerializer.builder()
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.INSTANCE)
diff --git a/src/main/java/net/minecraft/world/item/Items.java b/src/main/java/net/minecraft/world/item/Items.java
index f68639508d7ff9a0e743b5282301e62435d53656..89d4b7e4cd4222b61b49833fceda56ffa39710fa 100644
--- a/src/main/java/net/minecraft/world/item/Items.java
+++ b/src/main/java/net/minecraft/world/item/Items.java
@@ -258,7 +258,7 @@ public class Items {
public static final Item PURPUR_BLOCK = registerBlock(Blocks.PURPUR_BLOCK, CreativeModeTab.TAB_BUILDING_BLOCKS);
public static final Item PURPUR_PILLAR = registerBlock(Blocks.PURPUR_PILLAR, CreativeModeTab.TAB_BUILDING_BLOCKS);
public static final Item PURPUR_STAIRS = registerBlock(Blocks.PURPUR_STAIRS, CreativeModeTab.TAB_BUILDING_BLOCKS);
- public static final Item SPAWNER = registerBlock(new BlockItem(Blocks.SPAWNER, (new Item.Properties()).rarity(Rarity.EPIC)));
+ public static final Item SPAWNER = registerBlock(Blocks.SPAWNER, new net.pl3x.purpur.item.SpawnerItem(Blocks.SPAWNER, new Item.Properties().rarity(Rarity.EPIC))); // Purpur
public static final Item OAK_STAIRS = registerBlock(Blocks.OAK_STAIRS, CreativeModeTab.TAB_BUILDING_BLOCKS);
public static final Item CHEST = registerBlock(Blocks.CHEST, CreativeModeTab.TAB_DECORATIONS);
public static final Item CRAFTING_TABLE = registerBlock(Blocks.CRAFTING_TABLE, CreativeModeTab.TAB_DECORATIONS);
diff --git a/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java b/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java
index b1e04d41de80971a7a1616beb0860226ecc25045..a499cf626a54fcef62bc34bba4193ba0565d8379 100644
--- a/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java
@@ -1,9 +1,19 @@
package net.minecraft.world.level.block;
import javax.annotation.Nullable;
+
+import net.kyori.adventure.text.minimessage.MiniMessage;
import net.minecraft.core.BlockPos;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.ListTag;
+import net.minecraft.nbt.StringTag;
+import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.enchantment.EnchantmentHelper;
+import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
@@ -13,6 +23,19 @@ import net.minecraft.world.level.block.entity.SpawnerBlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
+// Purpur start
+import io.papermc.paper.adventure.PaperAdventure;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.TextReplacementConfig;
+import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+
+import java.util.List;
+import java.util.Locale;
+
+import static net.kyori.adventure.text.format.TextDecoration.ITALIC;
+// Purpur end
+
public class SpawnerBlock extends BaseEntityBlock {
protected SpawnerBlock(BlockBehaviour.Properties settings) {
@@ -30,6 +53,55 @@ public class SpawnerBlock extends BaseEntityBlock {
return createTickerHelper(type, BlockEntityType.MOB_SPAWNER, world.isClientSide ? SpawnerBlockEntity::clientTick : SpawnerBlockEntity::serverTick);
}
+ // Purpur start
+ @Override
+ public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, BlockEntity blockEntity, ItemStack stack) {
+ if (level.purpurConfig.silkTouchEnabled && player.getBukkitEntity().hasPermission("purpur.drop.spawners") && isSilkTouch(level, stack)) {
+ ResourceLocation type = ((SpawnerBlockEntity) blockEntity).getSpawner().getEntityId(level, pos);
+ if (type != null) {
+ final Component mobName = PaperAdventure.asAdventure(EntityType.getFromKey(type).getDescription());
+ CompoundTag display = new CompoundTag();
+ CompoundTag tag = new CompoundTag();
+
+ String name = level.purpurConfig.silkTouchSpawnerName;
+ if (name != null && !name.isEmpty() && !name.equals("Spawner")) {
+ Component displayName = MiniMessage.get().parse(name, "mob", mobName);
+ if (name.startsWith("<reset>")) {
+ displayName = displayName.decoration(ITALIC, false);
+ }
+ display.put("Name", StringTag.valueOf(PaperAdventure.asJsonString(displayName, Locale.ROOT)));
+ tag.put("display", display);
+ }
+
+ List<String> lore = level.purpurConfig.silkTouchSpawnerLore;
+ if (lore != null && !lore.isEmpty()) {
+ ListTag list = new ListTag();
+ for (String line : lore) {
+ Component lineComponent = MiniMessage.get().parse(line, "mob", mobName);
+ if (line.startsWith("<reset>")) {
+ lineComponent = lineComponent.decoration(ITALIC, false);
+ }
+ list.add(StringTag.valueOf(PaperAdventure.asJsonString(lineComponent, Locale.ROOT)));
+ }
+ display.put("Lore", list);
+ tag.put("display", display);
+ }
+
+ ItemStack item = new ItemStack(Blocks.SPAWNER.asItem());
+ tag.putString("Purpur.mob_type", type.toString());
+ item.setTag(tag);
+
+ popResource(level, pos, item);
+ }
+ }
+ super.playerDestroy(level, player, pos, state, blockEntity, stack);
+ }
+
+ private boolean isSilkTouch(Level level, ItemStack stack) {
+ return stack != null && level.purpurConfig.silkTouchTools.contains(stack.getItem()) && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, stack) >= level.purpurConfig.minimumSilkTouchSpawnerRequire;
+ }
+ // Purpur end
+
@Override
public void spawnAfterBreak(BlockState state, ServerLevel world, BlockPos pos, ItemStack stack) {
super.spawnAfterBreak(state, world, pos, stack);
@@ -42,6 +114,7 @@ public class SpawnerBlock extends BaseEntityBlock {
@Override
public int getExpDrop(BlockState iblockdata, ServerLevel worldserver, BlockPos blockposition, ItemStack itemstack) {
+ if (isSilkTouch(worldserver, itemstack)) return 0; // Purpur
int i = 15 + worldserver.random.nextInt(15) + worldserver.random.nextInt(15);
return i;
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 6df320ab8214669517d5de30a28f044a5a6b4a33..8920b47610a323ceb6b19a05b7592d8acf809bc4 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -116,6 +116,38 @@ public class PurpurWorldConfig {
playerInvulnerableWhileAcceptingResourcePack = getBoolean("gameplay-mechanics.player.invulnerable-while-accepting-resource-pack", playerInvulnerableWhileAcceptingResourcePack);
}
+ public boolean silkTouchEnabled = false;
+ public String silkTouchSpawnerName = "<reset><white>Spawner";
+ public List<String> silkTouchSpawnerLore = new ArrayList<>();
+ public List<Item> silkTouchTools = new ArrayList<>();
+ public int minimumSilkTouchSpawnerRequire = 1;
+ private void silkTouchSettings() {
+ if (PurpurConfig.version < 21) {
+ String oldName = getString("gameplay-mechanics.silk-touch.spawner-name", silkTouchSpawnerName);
+ set("gameplay-mechanics.silk-touch.spawner-name", "<reset>" + ChatColor.toMM(oldName.replace("{mob}", "<mob>")));
+ List<String> list = new ArrayList<>();
+ getList("gameplay-mechanics.silk-touch.spawner-lore", List.of("Spawns a <mob>"))
+ .forEach(line -> list.add("<reset>" + ChatColor.toMM(line.toString().replace("{mob}", "<mob>"))));
+ set("gameplay-mechanics.silk-touch.spawner-lore", list);
+ }
+ silkTouchEnabled = getBoolean("gameplay-mechanics.silk-touch.enabled", silkTouchEnabled);
+ silkTouchSpawnerName = getString("gameplay-mechanics.silk-touch.spawner-name", silkTouchSpawnerName);
+ minimumSilkTouchSpawnerRequire = getInt("gameplay-mechanics.silk-touch.minimal-level", minimumSilkTouchSpawnerRequire);
+ silkTouchSpawnerLore.clear();
+ getList("gameplay-mechanics.silk-touch.spawner-lore", List.of("Spawns a <mob>"))
+ .forEach(line -> silkTouchSpawnerLore.add(line.toString()));
+ silkTouchTools.clear();
+ getList("gameplay-mechanics.silk-touch.tools", List.of(
+ "minecraft:iron_pickaxe",
+ "minecraft:golden_pickaxe",
+ "minecraft:diamond_pickaxe",
+ "minecraft:netherite_pickaxe"
+ )).forEach(key -> {
+ Item item = Registry.ITEM.get(new ResourceLocation(key.toString()));
+ if (item != Items.AIR) silkTouchTools.add(item);
+ });
+ }
+
public boolean babiesAreRidable = true;
public boolean untamedTamablesAreRidable = true;
public boolean useNightVisionWhenRiding = false;
diff --git a/src/main/java/net/pl3x/purpur/item/SpawnerItem.java b/src/main/java/net/pl3x/purpur/item/SpawnerItem.java
new file mode 100644
index 0000000000000000000000000000000000000000..728da3d75ec957ee789f9625483565e38649acd5
--- /dev/null
+++ b/src/main/java/net/pl3x/purpur/item/SpawnerItem.java
@@ -0,0 +1,36 @@
+package net.pl3x.purpur.item;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.BlockItem;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.entity.SpawnerBlockEntity;
+import net.minecraft.world.level.block.state.BlockState;
+
+public class SpawnerItem extends BlockItem {
+
+ public SpawnerItem(Block block, Properties settings) {
+ super(block, settings);
+ }
+
+ @Override
+ protected boolean updateCustomBlockEntityTag(BlockPos pos, Level level, Player player, ItemStack stack, BlockState state) {
+ boolean handled = super.updateCustomBlockEntityTag(pos, level, player, stack, state);
+ if (level.purpurConfig.silkTouchEnabled && player.getBukkitEntity().hasPermission("purpur.place.spawners")) {
+ BlockEntity spawner = level.getBlockEntity(pos);
+ if (spawner instanceof SpawnerBlockEntity && stack.hasTag()) {
+ CompoundTag tag = stack.getTag();
+ if (tag.contains("Purpur.mob_type")) {
+ EntityType.byString(tag.getString("Purpur.mob_type")).ifPresent(type ->
+ ((SpawnerBlockEntity) spawner).getSpawner().setEntityId(type));
+ }
+ }
+ }
+ return handled;
+ }
+}

View File

@@ -0,0 +1,77 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 6 Jun 2019 22:15:46 -0500
Subject: [PATCH] MC-168772 Fix - Add turtle egg block options
diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
index fdb3ab919a78221605257ae82bfd026346ce2ffb..e98fc3c235f9160f1928a8afb0d7991a6d3430cb 100644
--- a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
@@ -10,11 +10,15 @@ import net.minecraft.tags.BlockTags;
import net.minecraft.tags.Tag;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.ExperienceOrb;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ambient.Bat;
import net.minecraft.world.entity.animal.Turtle;
+import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.entity.vehicle.AbstractMinecart;
+import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
@@ -187,6 +191,23 @@ public class TurtleEggBlock extends Block {
}
private boolean canDestroyEgg(Level world, Entity entity) {
- return !(entity instanceof Turtle) && !(entity instanceof Bat) ? (!(entity instanceof LivingEntity) ? false : entity instanceof Player || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) : false;
+ // Purpur start - fix MC-168772
+ if (entity instanceof Turtle) {
+ return false;
+ }
+ if (!world.purpurConfig.turtleEggsBreakFromExpOrbs && entity instanceof ExperienceOrb) {
+ return false;
+ }
+ if (!world.purpurConfig.turtleEggsBreakFromItems && entity instanceof ItemEntity) {
+ return false;
+ }
+ if (!world.purpurConfig.turtleEggsBreakFromMinecarts && entity instanceof AbstractMinecart) {
+ return false;
+ }
+ if (entity instanceof LivingEntity && !(entity instanceof Player)) {
+ return world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
+ }
+ return true;
+ // Purpur end
}
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 8920b47610a323ceb6b19a05b7592d8acf809bc4..5b82c82da88f95190f8d7dc1f635fd27c8b513df 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1079,7 +1079,10 @@ public class PurpurWorldConfig {
public boolean turtleRidable = false;
public boolean turtleRidableInWater = false;
public double turtleMaxHealth = 30.0D;
- private void turtleSettings() {
+ public boolean turtleEggsBreakFromExpOrbs = true;
+ public boolean turtleEggsBreakFromItems = true;
+ public boolean turtleEggsBreakFromMinecarts = true;
+ private void turtleEggSettings() {
turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable);
turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater);
if (PurpurConfig.version < 10) {
@@ -1088,6 +1091,9 @@ public class PurpurWorldConfig {
set("mobs.turtle.attributes.max_health", oldValue);
}
turtleMaxHealth = getDouble("mobs.turtle.attributes.max_health", turtleMaxHealth);
+ turtleEggsBreakFromExpOrbs = getBoolean("blocks.turtle_egg.break-from-exp-orbs", turtleEggsBreakFromExpOrbs);
+ turtleEggsBreakFromItems = getBoolean("blocks.turtle_egg.break-from-items", turtleEggsBreakFromItems);
+ turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts);
}
public boolean vexRidable = false;

View File

@@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 28 Mar 2020 01:51:32 -0500
Subject: [PATCH] Fix vanilla command permission handler
diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
index f64aa22ed6fcb4af67317b99f459ee5296392548..36c91793e0aa4895193623cf8cba7820d31f4eca 100644
--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java
+++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
@@ -34,6 +34,7 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
private final RedirectModifier<S> modifier;
private final boolean forks;
private Command<S> command;
+ private String permission = null; public String getPermission() { return permission; } public void setPermission(String permission) { this.permission = permission; } // Purpur
// CraftBukkit start
public void removeCommand(String name) {
this.children.remove(name);
diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
index 4aa1dc543950b5de64345b3403a6d0bc41c521df..1c19a64da230268ceb9124bb7e1a141d78ac3393 100644
--- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
+++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
@@ -89,6 +89,7 @@ public final class VanillaCommandWrapper extends BukkitCommand {
}
public static String getPermission(CommandNode<CommandSourceStack> vanillaCommand) {
+ if (vanillaCommand.getPermission() != null) return vanillaCommand.getPermission(); // Purpur
// Paper start
final String commandName;
if (vanillaCommand.getRedirect() == null) {

View File

@@ -0,0 +1,60 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 19 Oct 2019 00:52:12 -0500
Subject: [PATCH] Logger settings (suppressing pointless logs)
diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java
index f7959fe8d5247504dd79a18010470d98781c7cfe..945fb3200d52b83eaee2e62d6db5c43e088218eb 100644
--- a/src/main/java/net/minecraft/server/PlayerAdvancements.java
+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java
@@ -186,6 +186,7 @@ public class PlayerAdvancements {
if (advancement == null) {
// CraftBukkit start
if (entry.getKey().getNamespace().equals("minecraft")) {
+ if (!net.pl3x.purpur.PurpurConfig.loggerSuppressIgnoredAdvancementWarnings) // Purpur
PlayerAdvancements.LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", entry.getKey(), this.file);
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/stats/ServerRecipeBook.java b/src/main/java/net/minecraft/stats/ServerRecipeBook.java
index 63a4fa2408edf84b490ca39e824977135d78eff0..461796c9c559f43bd2e0126b12a46bfc41c830a5 100644
--- a/src/main/java/net/minecraft/stats/ServerRecipeBook.java
+++ b/src/main/java/net/minecraft/stats/ServerRecipeBook.java
@@ -122,6 +122,7 @@ public class ServerRecipeBook extends RecipeBook {
Optional<? extends Recipe<?>> optional = recipeManager.byKey(minecraftkey);
if (!optional.isPresent()) {
+ if (!net.pl3x.purpur.PurpurConfig.loggerSuppressUnrecognizedRecipeErrors) // Purpur
ServerRecipeBook.LOGGER.error("Tried to load unrecognized recipe: {} removed now.", minecraftkey);
} else {
handler.accept((Recipe) optional.get());
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index 4b6bb477db0af506508e73dd42155429777b49d0..7f08a6a0e92300825ca90aeb55379a07474b76e5 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -232,4 +232,13 @@ public class PurpurConfig {
org.bukkit.event.inventory.InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27);
enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows);
}
+
+ public static boolean loggerSuppressInitLegacyMaterialError = false;
+ public static boolean loggerSuppressIgnoredAdvancementWarnings = false;
+ public static boolean loggerSuppressUnrecognizedRecipeErrors = false;
+ private static void loggerSettings() {
+ loggerSuppressInitLegacyMaterialError = getBoolean("settings.logger.suppress-init-legacy-material-errors", loggerSuppressInitLegacyMaterialError);
+ loggerSuppressIgnoredAdvancementWarnings = getBoolean("settings.logger.suppress-ignored-advancement-warnings", loggerSuppressIgnoredAdvancementWarnings);
+ loggerSuppressUnrecognizedRecipeErrors = getBoolean("settings.logger.suppress-unrecognized-recipe-errors", loggerSuppressUnrecognizedRecipeErrors);
+ }
}
diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java
index b2a15c986c7500a0ce227a54cb61ec3f5378f6f3..6d5f030b678dbc86dceddcbb050b4aaed4102c50 100644
--- a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java
+++ b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java
@@ -255,6 +255,7 @@ public final class CraftLegacy {
}
static {
+ if (!net.pl3x.purpur.PurpurConfig.loggerSuppressInitLegacyMaterialError) // Purpur
System.err.println("Initializing Legacy Material Support. Unless you have legacy plugins and/or data this is a bug!");
if (MinecraftServer.getServer() != null && MinecraftServer.getServer().isDebugging()) {
new Exception().printStackTrace();

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sun, 15 Dec 2019 12:53:59 -0600
Subject: [PATCH] Disable outdated build check
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index 5b527a32f56a82131168879106f76c1f6cbb7b30..56674053351962a75b2731dde137dbbc0c70dbde 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -269,7 +269,7 @@ public class Main {
System.setProperty(TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper
}
- if (Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) {
+ if (false && Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) { // Purpur
Date buildDate = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z").parse(Main.class.getPackage().getImplementationVendor()); // Paper
Calendar deadline = Calendar.getInstance();

View File

@@ -0,0 +1,147 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sun, 12 May 2019 00:43:12 -0500
Subject: [PATCH] Giants AI settings
diff --git a/src/main/java/net/minecraft/world/entity/monster/Giant.java b/src/main/java/net/minecraft/world/entity/monster/Giant.java
index a8ffdc8810152d77668aad7bad15a00c4d194d4c..91e28c414545d2bbb4e2f22c516d0f683e8b04ec 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Giant.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Giant.java
@@ -1,13 +1,36 @@
package net.minecraft.world.entity.monster;
import net.minecraft.core.BlockPos;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.world.Difficulty;
+import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.EquipmentSlot;
+import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.Pose;
+import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
+import net.minecraft.world.entity.ai.goal.FloatGoal;
+import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
+import net.minecraft.world.entity.ai.goal.MeleeAttackGoal;
+import net.minecraft.world.entity.ai.goal.MoveTowardsRestrictionGoal;
+import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
+import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
+import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
+import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
+import net.minecraft.world.entity.animal.IronGolem;
+import net.minecraft.world.entity.animal.Turtle;
+import net.minecraft.world.entity.npc.Villager;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
+import net.minecraft.world.level.ServerLevelAccessor;
+
+import javax.annotation.Nullable;
public class Giant extends Monster {
public Giant(EntityType<? extends Giant> type, Level world) {
@@ -26,18 +49,59 @@ public class Giant extends Monster {
return level.purpurConfig.giantRidableInWater;
}
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this));
- this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this));
- }
-
@Override
protected void initAttributes() {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level.purpurConfig.giantMaxHealth);
this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level.purpurConfig.giantMovementSpeed);
this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(this.level.purpurConfig.giantAttackDamage);
}
+
+ @Override
+ protected void registerGoals() {
+ if (level.purpurConfig.giantHaveAI) {
+ this.goalSelector.addGoal(0, new FloatGoal(this));
+ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this));
+ this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D));
+ this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 16.0F));
+ this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
+ this.goalSelector.addGoal(5, new MoveTowardsRestrictionGoal(this, 1.0D));
+ if (level.purpurConfig.giantHaveHostileAI) {
+ this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0D, false));
+ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this));
+ this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers(ZombifiedPiglin.class));
+ this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
+ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Villager.class, false));
+ this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
+ this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, true));
+ }
+ }
+ }
+
+ @Override
+ public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) {
+ SpawnGroupData groupData = super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt);
+ if (groupData == null) {
+ populateDefaultEquipmentSlots(difficulty);
+ populateDefaultEquipmentEnchantments(difficulty);
+ }
+ return groupData;
+ }
+
+ @Override
+ protected void populateDefaultEquipmentSlots(DifficultyInstance difficulty) {
+ super.populateDefaultEquipmentSlots(difficulty);
+ // TODO make configurable
+ if (random.nextFloat() < (level.getDifficulty() == Difficulty.HARD ? 0.1F : 0.05F)) {
+ this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.IRON_SWORD));
+ }
+ }
+
+ @Override
+ public float getJumpPower() {
+ // make giants jump as high as everything else relative to their size
+ // 1.0 makes bottom of feet about as high as their waist when they jump
+ return level.purpurConfig.giantJumpHeight;
+ }
// Purpur end
@Override
@@ -51,6 +115,6 @@ public class Giant extends Monster {
@Override
public float getWalkTargetValue(BlockPos pos, LevelReader world) {
- return world.getBrightness(pos) - 0.5F;
+ return super.getWalkTargetValue(pos, world); // Purpur - fix light requirements for natural spawns
}
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 5b82c82da88f95190f8d7dc1f635fd27c8b513df..01c33f5021905736b05fc33c268e42e4e82c2863 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -468,6 +468,10 @@ public class PurpurWorldConfig {
public double giantMovementSpeed = 0.5D;
public double giantAttackDamage = 50.0D;
public double giantMaxHealth = 100.0D;
+ public float giantStepHeight = 2.0F;
+ public float giantJumpHeight = 1.0F;
+ public boolean giantHaveAI = false;
+ public boolean giantHaveHostileAI = false;
private void giantSettings() {
giantRidable = getBoolean("mobs.giant.ridable", giantRidable);
giantRidableInWater = getBoolean("mobs.giant.ridable-in-water", giantRidableInWater);
@@ -483,6 +487,10 @@ public class PurpurWorldConfig {
set("mobs.giant.attributes.max_health", oldValue);
}
giantMaxHealth = getDouble("mobs.giant.attributes.max_health", giantMaxHealth);
+ giantStepHeight = (float) getDouble("mobs.giant.step-height", giantStepHeight);
+ giantJumpHeight = (float) getDouble("mobs.giant.jump-height", giantJumpHeight);
+ giantHaveAI = getBoolean("mobs.giant.have-ai", giantHaveAI);
+ giantHaveHostileAI = getBoolean("mobs.giant.have-hostile-ai", giantHaveHostileAI);
}
public boolean glowSquidRidable = false;

View File

@@ -0,0 +1,49 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sun, 7 Jul 2019 19:52:16 -0500
Subject: [PATCH] Zombie horse naturally spawn
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index ab4424acd2ef444da0dee575c5ce270a21a00532..168caca104d6ee4b4cca6dde973166d8e47a29ba 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -851,9 +851,15 @@ public class ServerLevel extends Level implements WorldGenLevel {
boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * paperConfig.skeleHorseSpawnChance && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper
if (flag1) {
- SkeletonHorse entityhorseskeleton = (SkeletonHorse) EntityType.SKELETON_HORSE.create((Level) this);
-
- entityhorseskeleton.setTrap(true);
+ // Purpur start
+ net.minecraft.world.entity.animal.horse.AbstractHorse entityhorseskeleton = EntityType.SKELETON_HORSE.create(this);
+ if (purpurConfig.zombieHorseSpawnChance > 0D && random.nextDouble() <= purpurConfig.zombieHorseSpawnChance) {
+ entityhorseskeleton = EntityType.ZOMBIE_HORSE.create(this);
+ } else {
+ entityhorseskeleton = EntityType.SKELETON_HORSE.create(this);
+ ((SkeletonHorse) entityhorseskeleton).setTrap(true);
+ }
+ // Purpur end
entityhorseskeleton.setAge(0);
entityhorseskeleton.setPos((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ());
this.addEntity(entityhorseskeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 01c33f5021905736b05fc33c268e42e4e82c2863..9db45abd1963ae7f48fe06f29fc4e3bf9e2cd983 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1266,6 +1266,7 @@ public class PurpurWorldConfig {
public double zombieHorseJumpStrengthMax = 1.0D;
public double zombieHorseMovementSpeedMin = 0.2D;
public double zombieHorseMovementSpeedMax = 0.2D;
+ public double zombieHorseSpawnChance = 0.0D;
private void zombieHorseSettings() {
zombieHorseRidableInWater = getBoolean("mobs.zombie_horse.ridable-in-water", zombieHorseRidableInWater);
zombieHorseCanSwim = getBoolean("mobs.zombie_horse.can-swim", zombieHorseCanSwim);
@@ -1281,6 +1282,7 @@ public class PurpurWorldConfig {
zombieHorseJumpStrengthMax = getDouble("mobs.zombie_horse.attributes.jump_strength.max", zombieHorseJumpStrengthMax);
zombieHorseMovementSpeedMin = getDouble("mobs.zombie_horse.attributes.movement_speed.min", zombieHorseMovementSpeedMin);
zombieHorseMovementSpeedMax = getDouble("mobs.zombie_horse.attributes.movement_speed.max", zombieHorseMovementSpeedMax);
+ zombieHorseSpawnChance = getDouble("mobs.zombie_horse.spawn-chance", zombieHorseSpawnChance);
}
public boolean zombieVillagerRidable = false;

View File

@@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 29 Nov 2019 22:37:44 -0600
Subject: [PATCH] Charged creeper naturally spawn
diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java
index 20d9da3ddd2bc85954b9bcdab238d902238ba518..7fbe8fb2b59fe2f578beed8b13cbbbe96011719f 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java
@@ -138,6 +138,14 @@ public class Creeper extends Monster implements PowerableMob {
public void initAttributes() {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level.purpurConfig.creeperMaxHealth);
}
+
+ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, @Nullable net.minecraft.world.entity.SpawnGroupData entityData, @Nullable CompoundTag entityNbt) {
+ double chance = world.getMinecraftWorld().purpurConfig.creeperChargedChance;
+ if (chance > 0D && random.nextDouble() <= chance) {
+ setPowered(true);
+ }
+ return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt);
+ }
// Purpur end
@Override
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 9db45abd1963ae7f48fe06f29fc4e3bf9e2cd983..17952c0f39deeed6c333289f35705c5ae49e0596 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -290,6 +290,7 @@ public class PurpurWorldConfig {
public boolean creeperRidable = false;
public boolean creeperRidableInWater = false;
public double creeperMaxHealth = 20.0D;
+ public double creeperChargedChance = 0.0D;
private void creeperSettings() {
creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable);
creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater);
@@ -299,6 +300,7 @@ public class PurpurWorldConfig {
set("mobs.creeper.attributes.max_health", oldValue);
}
creeperMaxHealth = getDouble("mobs.creeper.attributes.max_health", creeperMaxHealth);
+ creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance);
}
public boolean dolphinRidable = false;

View File

@@ -0,0 +1,61 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 31 Aug 2019 17:47:11 -0500
Subject: [PATCH] Rabbit naturally spawn toast and killer
diff --git a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java
index fd81c6ad5b7e36e013fd36d72f8db716ad9cae20..a046bcf35717b156141dfa041a44d32b1512d708 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java
@@ -426,7 +426,11 @@ public class Rabbit extends Animal {
if (!this.hasCustomName()) {
this.setCustomName(new TranslatableComponent(Util.makeDescriptionId("entity", Rabbit.KILLER_BUNNY)));
}
+ // Purpur start
+ } else if (rabbitType == 98) {
+ setCustomName(new TranslatableComponent("Toast"));
}
+ // Purpur end
this.entityData.set(Rabbit.DATA_TYPE_ID, rabbitType);
}
@@ -447,6 +451,16 @@ public class Rabbit extends Animal {
}
private int getRandomRabbitType(LevelAccessor world) {
+ // Purpur start
+ Level level = world.getMinecraftWorld();
+ if (level.purpurConfig.rabbitNaturalKiller > 0D && random.nextDouble() <= level.purpurConfig.rabbitNaturalKiller) {
+ return 99;
+ }
+ if (level.purpurConfig.rabbitNaturalToast > 0D && random.nextDouble() <= level.purpurConfig.rabbitNaturalToast) {
+ return 98;
+ }
+ // Purpur end
+
Biome biomebase = world.getBiome(this.blockPosition());
int i = this.random.nextInt(100);
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 17952c0f39deeed6c333289f35705c5ae49e0596..5dbec1b5662df093394e9159fb11e401444da19a 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -844,6 +844,8 @@ public class PurpurWorldConfig {
public boolean rabbitRidable = false;
public boolean rabbitRidableInWater = false;
public double rabbitMaxHealth = 3.0D;
+ public double rabbitNaturalToast = 0.0D;
+ public double rabbitNaturalKiller = 0.0D;
private void rabbitSettings() {
rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable);
rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater);
@@ -853,6 +855,8 @@ public class PurpurWorldConfig {
set("mobs.rabbit.attributes.max_health", oldValue);
}
rabbitMaxHealth = getDouble("mobs.rabbit.attributes.max_health", rabbitMaxHealth);
+ rabbitNaturalToast = getDouble("mobs.rabbit.spawn-toast-chance", rabbitNaturalToast);
+ rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller);
}
public boolean ravagerRidable = false;

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Tue, 4 Jun 2019 15:50:08 -0500
Subject: [PATCH] Fix 'outdated server' showing in ping before server fully
boots
diff --git a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
index d65191a50349ec86fe35df4ac1070f94fbb77b4c..9c57dfd72ef559d8052aac4e073cd36e76079ed7 100644
--- a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
@@ -145,6 +145,7 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
this.connection.send(new ClientboundStatusResponsePacket(ping));
*/
+ if (this.server.getStatus().getVersion() == null) return; // Purpur - do not respond to pings before we know the protocol version
com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.processRequest(this.server, this.connection);
// Paper end
}

View File

@@ -0,0 +1,57 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 6 Jul 2019 17:00:04 -0500
Subject: [PATCH] Dont send useless entity packets
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index 1c6bf5a3014beaf5f9c1c38aed4cf3225e50b8bb..e158c9bf0fb527105da9dc3f28d88e0ba7337e65 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -188,6 +188,7 @@ public class ServerEntity {
this.teleportDelay = 0;
packet1 = new ClientboundTeleportEntityPacket(this.entity);
}
+ if (net.pl3x.purpur.PurpurConfig.dontSendUselessEntityPackets && isUselessPacket(packet1)) packet1 = null; // Purpur
}
if ((this.trackDelta || this.entity.hasImpulse || this.entity instanceof LivingEntity && ((LivingEntity) this.entity).isFallFlying()) && this.tickCount > 0) {
@@ -256,6 +257,22 @@ public class ServerEntity {
}
+ // Purpur start
+ private boolean isUselessPacket(Packet<?> possibleUselessPacket) {
+ if (possibleUselessPacket instanceof ClientboundMoveEntityPacket) {
+ ClientboundMoveEntityPacket packet = (ClientboundMoveEntityPacket) possibleUselessPacket;
+ if (possibleUselessPacket instanceof ClientboundMoveEntityPacket.Pos) {
+ return packet.getXa() == 0 && packet.getYa() == 0 && packet.getZa() == 0;
+ } else if (possibleUselessPacket instanceof ClientboundMoveEntityPacket.PosRot) {
+ return packet.getXa() == 0 && packet.getYa() == 0 && packet.getZa() == 0 && packet.getyRot() == 0 && packet.getxRot() == 0;
+ } else if (possibleUselessPacket instanceof ClientboundMoveEntityPacket.Rot) {
+ return packet.getyRot() == 0 && packet.getxRot() == 0;
+ }
+ }
+ return false;
+ }
+ // Purpur end
+
public void removePairing(ServerPlayer player) {
this.entity.stopSeenByPlayer(player);
player.connection.send(new ClientboundRemoveEntitiesPacket(new int[]{this.entity.getId()}));
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index 7f08a6a0e92300825ca90aeb55379a07474b76e5..504e8d2f9c0a2c8c8f6a710c0ad1d438f53d1439 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -233,6 +233,11 @@ public class PurpurConfig {
enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows);
}
+ public static boolean dontSendUselessEntityPackets = false;
+ private static void dontSendUselessEntityPackets() {
+ dontSendUselessEntityPackets = getBoolean("settings.dont-send-useless-entity-packets", dontSendUselessEntityPackets);
+ }
+
public static boolean loggerSuppressInitLegacyMaterialError = false;
public static boolean loggerSuppressIgnoredAdvancementWarnings = false;
public static boolean loggerSuppressUnrecognizedRecipeErrors = false;

View File

@@ -0,0 +1,96 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 13 Jul 2019 15:56:22 -0500
Subject: [PATCH] Tulips change fox type
diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java
index c8198d49ca0e159a2d87e21cf73fc901ea79310c..04fddf897c52f041324bcef19c84bff3aa675d8a 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java
@@ -34,6 +34,7 @@ import net.minecraft.tags.Tag;
import net.minecraft.util.Mth;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.InteractionHand;
+import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.AgeableMob;
import net.minecraft.world.entity.Entity;
@@ -85,6 +86,7 @@ import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.CaveVines;
import net.minecraft.world.level.block.SweetBerryBushBlock;
import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.pathfinder.BlockPathTypes;
import net.minecraft.world.phys.Vec3;
@@ -368,6 +370,11 @@ public class Fox extends Animal {
}
private void setTargetGoals() {
+ // Purpur start - do not add duplicate goals
+ this.targetSelector.removeGoal(this.landTargetGoal);
+ this.targetSelector.removeGoal(this.turtleEggTargetGoal);
+ this.targetSelector.removeGoal(this.fishTargetGoal);
+ // Purpur end
if (this.getFoxType() == Fox.Type.RED) {
this.targetSelector.addGoal(4, this.landTargetGoal);
this.targetSelector.addGoal(4, this.turtleEggTargetGoal);
@@ -400,6 +407,7 @@ public class Fox extends Animal {
public void setFoxType(Fox.Type type) {
this.entityData.set(Fox.DATA_TYPE_ID, type.getId());
+ this.setTargetGoals(); // Purpur - fix API bug not updating pathfinders on type change
}
List<UUID> getTrustedUUIDs() {
@@ -730,6 +738,29 @@ public class Fox extends Animal {
return this.getTrustedUUIDs().contains(uuid);
}
+ // Purpur start
+ @Override
+ public InteractionResult mobInteract(Player player, InteractionHand hand) {
+ if (level.purpurConfig.foxTypeChangesWithTulips) {
+ ItemStack itemstack = player.getItemInHand(hand);
+ if (getFoxType() == Type.RED && itemstack.getItem() == Items.WHITE_TULIP) {
+ setFoxType(Type.SNOW);
+ if (!player.getAbilities().instabuild) {
+ itemstack.shrink(1);
+ }
+ return InteractionResult.SUCCESS;
+ } else if (getFoxType() == Type.SNOW && itemstack.getItem() == Items.ORANGE_TULIP) {
+ setFoxType(Type.RED);
+ if (!player.getAbilities().instabuild) {
+ itemstack.shrink(1);
+ }
+ return InteractionResult.SUCCESS;
+ }
+ }
+ return super.mobInteract(player, hand);
+ }
+ // Purpur end
+
@Override
// Paper start - Cancellable death event
protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(DamageSource source) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 5dbec1b5662df093394e9159fb11e401444da19a..b14853de709d9d083e2c349f398d81f629ebf6eb 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -438,6 +438,7 @@ public class PurpurWorldConfig {
public boolean foxRidable = false;
public boolean foxRidableInWater = false;
public double foxMaxHealth = 10.0D;
+ public boolean foxTypeChangesWithTulips = false;
private void foxSettings() {
foxRidable = getBoolean("mobs.fox.ridable", foxRidable);
foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater);
@@ -447,6 +448,7 @@ public class PurpurWorldConfig {
set("mobs.fox.attributes.max_health", oldValue);
}
foxMaxHealth = getDouble("mobs.fox.attributes.max_health", foxMaxHealth);
+ foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips);
}
public boolean ghastRidable = false;

View File

@@ -0,0 +1,83 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 26 Mar 2020 19:46:44 -0500
Subject: [PATCH] Breedable Polar Bears
diff --git a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java
index 62c76aace42a948a117aee3d209fbaac72661740..6b09e8adcd38acb92072838bb2869458dae1cb50 100644
--- a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java
+++ b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java
@@ -93,6 +93,27 @@ public class PolarBear extends Animal implements NeutralMob {
public void initAttributes() {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level.purpurConfig.polarBearMaxHealth);
}
+
+ public boolean canMate(Animal other) {
+ if (other == this) {
+ return false;
+ } else if (this.isStanding()) {
+ return false;
+ } else if (this.getTarget() != null) {
+ return false;
+ } else if (!(other instanceof PolarBear)) {
+ return false;
+ } else {
+ PolarBear bear = (PolarBear) other;
+ if (bear.isStanding()) {
+ return false;
+ }
+ if (bear.getTarget() != null) {
+ return false;
+ }
+ return this.isInLove() && bear.isInLove();
+ }
+ }
// Purpur end
@Override
@@ -102,7 +123,7 @@ public class PolarBear extends Animal implements NeutralMob {
@Override
public boolean isFood(ItemStack stack) {
- return false;
+ return level.purpurConfig.polarBearBreedableItem != null && stack.getItem() == level.purpurConfig.polarBearBreedableItem; // Purpur
}
@Override
@@ -112,6 +133,12 @@ public class PolarBear extends Animal implements NeutralMob {
this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur
this.goalSelector.addGoal(1, new PolarBear.PolarBearMeleeAttackGoal());
this.goalSelector.addGoal(1, new PolarBear.PolarBearPanicGoal());
+ // Purpur start
+ if (level.purpurConfig.polarBearBreedableItem != null) {
+ this.goalSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.BreedGoal(this, 1.0D));
+ this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.TemptGoal(this, 1.0D, net.minecraft.world.item.crafting.Ingredient.of(level.purpurConfig.polarBearBreedableItem), false));
+ }
+ // Purpur end
this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25D));
this.goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0D));
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F));
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index b14853de709d9d083e2c349f398d81f629ebf6eb..241ba6a10eda5bf97adb09cc2ae423da6036d55f 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -820,6 +820,8 @@ public class PurpurWorldConfig {
public boolean polarBearRidable = false;
public boolean polarBearRidableInWater = false;
public double polarBearMaxHealth = 30.0D;
+ public String polarBearBreedableItemString = "";
+ public Item polarBearBreedableItem = null;
private void polarBearSettings() {
polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable);
polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater);
@@ -829,6 +831,9 @@ public class PurpurWorldConfig {
set("mobs.polar_bear.attributes.max_health", oldValue);
}
polarBearMaxHealth = getDouble("mobs.polar_bear.attributes.max_health", polarBearMaxHealth);
+ polarBearBreedableItemString = getString("mobs.polar_bear.breedable-item", polarBearBreedableItemString);
+ Item item = Registry.ITEM.get(new ResourceLocation(polarBearBreedableItemString));
+ if (item != Items.AIR) polarBearBreedableItem = item;
}
public boolean pufferfishRidable = false;

View File

@@ -0,0 +1,72 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sun, 12 Apr 2020 13:19:34 -0500
Subject: [PATCH] Chickens can retaliate
diff --git a/src/main/java/net/minecraft/world/entity/animal/Chicken.java b/src/main/java/net/minecraft/world/entity/animal/Chicken.java
index 63790e717f11f8cc28f734f81998542164461ee2..b3a6da8b1a221281d9f4d31cfb00ff525a8fdc65 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Chicken.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Chicken.java
@@ -66,6 +66,9 @@ public class Chicken extends Animal {
@Override
public void initAttributes() {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level.purpurConfig.chickenMaxHealth);
+ if (level.purpurConfig.chickenRetaliate) {
+ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(2.0D);
+ }
}
// Purpur end
@@ -73,13 +76,21 @@ public class Chicken extends Animal {
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur
- this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D));
+ // this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D)); // Purpur - moved down
this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D));
this.goalSelector.addGoal(3, new TemptGoal(this, 1.0D, Chicken.FOOD_ITEMS, false));
this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.1D));
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D));
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F));
this.goalSelector.addGoal(7, new RandomLookAroundGoal(this));
+ // Purpur start
+ if (level.purpurConfig.chickenRetaliate) {
+ this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.0D, false));
+ this.targetSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal(this));
+ } else {
+ this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D));
+ }
+ // Purpur end
}
@Override
@@ -88,7 +99,7 @@ public class Chicken extends Animal {
}
public static AttributeSupplier.Builder createAttributes() {
- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 4.0D).add(Attributes.MOVEMENT_SPEED, 0.25D);
+ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 4.0D).add(Attributes.MOVEMENT_SPEED, 0.25D).add(Attributes.ATTACK_DAMAGE, 0.0D); // Purpur
}
@Override
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 241ba6a10eda5bf97adb09cc2ae423da6036d55f..8692ca2751ba6ed6ad989843261b13d2eeba669e 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -250,6 +250,7 @@ public class PurpurWorldConfig {
public boolean chickenRidable = false;
public boolean chickenRidableInWater = false;
public double chickenMaxHealth = 4.0D;
+ public boolean chickenRetaliate = false;
private void chickenSettings() {
chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable);
chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater);
@@ -259,6 +260,7 @@ public class PurpurWorldConfig {
set("mobs.chicken.attributes.max_health", oldValue);
}
chickenMaxHealth = getDouble("mobs.chicken.attributes.max_health", chickenMaxHealth);
+ chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate);
}
public boolean codRidable = false;

View File

@@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sun, 6 Oct 2019 12:46:35 -0500
Subject: [PATCH] Add option to set armorstand step height
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
index 02bce120fc93caa9e1e92b61e74c28209a1b2385..fee2bd03d007e6d69706f8cb953a2f6ae59cac35 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
@@ -669,6 +669,7 @@ public class ArmorStand extends LivingEntity {
@Override
public void tick() {
+ maxUpStep = level.purpurConfig.armorstandStepHeight;
// Paper start
if (!this.canTick) {
if (this.noTickPoseDirty) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 8692ca2751ba6ed6ad989843261b13d2eeba669e..7eead3ef93dd4e8d912809a2c47062b95cb80168 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -94,6 +94,11 @@ public class PurpurWorldConfig {
return value.isEmpty() ? fallback : value;
}
+ public float armorstandStepHeight = 0.0F;
+ private void armorstandSettings() {
+ armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight);
+ }
+
public boolean idleTimeoutKick = true;
public boolean idleTimeoutTickNearbyEntities = true;
public boolean idleTimeoutCountAsSleeping = false;

View File

@@ -0,0 +1,74 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 26 Dec 2019 18:52:55 -0600
Subject: [PATCH] Cat spawning options
diff --git a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java
index 4cab98b5e441a174482893d3d289bbafa1f7a5fc..fa3cdff99a16b67ed86c8f7940ffa139930c3448 100644
--- a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java
+++ b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java
@@ -30,7 +30,7 @@ public class CatSpawner implements CustomSpawner {
if (this.nextTick > 0) {
return 0;
} else {
- this.nextTick = 1200;
+ this.nextTick = world.purpurConfig.catSpawnDelay; // Purpur
Player player = world.getRandomPlayer();
if (player == null) {
return 0;
@@ -63,9 +63,13 @@ public class CatSpawner implements CustomSpawner {
}
private int spawnInVillage(ServerLevel world, BlockPos pos) {
- int i = 48;
- if (world.getPoiManager().getCountInRange(PoiType.HOME.getPredicate(), pos, 48, PoiManager.Occupancy.IS_OCCUPIED) > 4L) {
- List<Cat> list = world.getEntitiesOfClass(Cat.class, (new AABB(pos)).inflate(48.0D, 8.0D, 48.0D));
+ // Purpur start
+ int range = world.purpurConfig.catSpawnVillageScanRange;
+ if (range <= 0) return 0;
+
+ if (world.getPoiManager().getCountInRange(PoiType.HOME.getPredicate(), pos, range, PoiManager.Occupancy.IS_OCCUPIED) > 4L) {
+ List<Cat> list = world.getEntitiesOfClass(Cat.class, (new AABB(pos)).inflate(range, 8.0D, range));
+ // Purpur end
if (list.size() < 5) {
return this.spawnCat(pos, world);
}
@@ -75,8 +79,11 @@ public class CatSpawner implements CustomSpawner {
}
private int spawnInHut(ServerLevel world, BlockPos pos) {
- int i = 16;
- List<Cat> list = world.getEntitiesOfClass(Cat.class, (new AABB(pos)).inflate(16.0D, 8.0D, 16.0D));
+ // Purpur start
+ int range = world.purpurConfig.catSpawnSwampHutScanRange;
+ if (range <= 0) return 0;
+ List<Cat> list = world.getEntitiesOfClass(Cat.class, (new AABB(pos)).inflate(range, 8.0D, range));
+ // Purpur end
return list.size() < 1 ? this.spawnCat(pos, world) : 0;
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 7eead3ef93dd4e8d912809a2c47062b95cb80168..8f7e7007633ee30f3f943d583623c122d5bc7de3 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -227,6 +227,9 @@ public class PurpurWorldConfig {
public boolean catRidable = false;
public boolean catRidableInWater = false;
public double catMaxHealth = 10.0D;
+ public int catSpawnDelay = 1200;
+ public int catSpawnSwampHutScanRange = 16;
+ public int catSpawnVillageScanRange = 48;
private void catSettings() {
catRidable = getBoolean("mobs.cat.ridable", catRidable);
catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater);
@@ -236,6 +239,9 @@ public class PurpurWorldConfig {
set("mobs.cat.attributes.max_health", oldValue);
}
catMaxHealth = getDouble("mobs.cat.attributes.max_health", catMaxHealth);
+ catSpawnDelay = getInt("mobs.cat.spawn-delay", catSpawnDelay);
+ catSpawnSwampHutScanRange = getInt("mobs.cat.scan-range-for-other-cats.swamp-hut", catSpawnSwampHutScanRange);
+ catSpawnVillageScanRange = getInt("mobs.cat.scan-range-for-other-cats.village", catSpawnVillageScanRange);
}
public boolean caveSpiderRidable = false;

View File

@@ -0,0 +1,21 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 2 Jan 2020 01:23:22 -0600
Subject: [PATCH] MC-147659 - Fix non black cats spawning in swamp huts
diff --git a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java
index fa3cdff99a16b67ed86c8f7940ffa139930c3448..89defd6b6d64e9048b0b2e7c872f1a199876457f 100644
--- a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java
+++ b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java
@@ -92,8 +92,9 @@ public class CatSpawner implements CustomSpawner {
if (cat == null) {
return 0;
} else {
+ cat.moveTo(pos, 0.0F, 0.0F); // Purpur
cat.finalizeSpawn(world, world.getCurrentDifficultyAt(pos), MobSpawnType.NATURAL, (SpawnGroupData)null, (CompoundTag)null);
- cat.moveTo(pos, 0.0F, 0.0F);
+ // cat.moveTo(pos, 0.0F, 0.0F); // Purpur - move up - fixes non black cat types spawning inside swamp huts
world.addFreshEntityWithPassengers(cat);
return 1;
}

View File

@@ -0,0 +1,135 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 4 May 2019 01:10:30 -0500
Subject: [PATCH] Cows eat mushrooms
diff --git a/src/main/java/net/minecraft/world/entity/animal/Cow.java b/src/main/java/net/minecraft/world/entity/animal/Cow.java
index 205b740eeb3ad2c63a3524948bdfb43a3a7c373e..35c1de1cb74a38b414b4bf0516fa89c1c1a22a9f 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Cow.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Cow.java
@@ -1,6 +1,7 @@
package net.minecraft.world.entity.animal;
import net.minecraft.core.BlockPos;
+import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
@@ -28,6 +29,7 @@ import net.minecraft.world.item.ItemUtils;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
// CraftBukkit start
import org.bukkit.craftbukkit.event.CraftEventFactory;
@@ -63,6 +65,7 @@ public class Cow extends Animal {
this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur
this.goalSelector.addGoal(1, new PanicGoal(this, 2.0D));
this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D));
+ if (level.purpurConfig.cowFeedMushrooms > 0) this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, Ingredient.of(Items.WHEAT, Blocks.RED_MUSHROOM.asItem(), Blocks.BROWN_MUSHROOM.asItem()), false)); else // Purpur
this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, Ingredient.of(Items.WHEAT), false));
this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25D));
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D));
@@ -118,11 +121,80 @@ public class Cow extends Animal {
player.setItemInHand(hand, itemstack1);
return InteractionResult.sidedSuccess(this.level.isClientSide);
+ // Purpur start - feed mushroom to change to mooshroom
+ } else if (level.purpurConfig.cowFeedMushrooms > 0 && this.getType() != EntityType.MOOSHROOM && isMushroom(itemstack)) {
+ return this.feedMushroom(player, itemstack);
+ // Purpur end
} else {
return super.mobInteract(player, hand);
}
}
+ // Purpur start - feed mushroom to change to mooshroom
+ private int redMushroomsFed = 0;
+ private int brownMushroomsFed = 0;
+
+ private boolean isMushroom(ItemStack stack) {
+ return stack.getItem() == Blocks.RED_MUSHROOM.asItem() || stack.getItem() == Blocks.BROWN_MUSHROOM.asItem();
+ }
+
+ private int incrementFeedCount(ItemStack stack) {
+ if (stack.getItem() == Blocks.RED_MUSHROOM.asItem()) {
+ return ++redMushroomsFed;
+ } else {
+ return ++brownMushroomsFed;
+ }
+ }
+
+ private InteractionResult feedMushroom(Player player, ItemStack stack) {
+ level.broadcastEntityEvent(this, (byte) 18); // hearts
+ playSound(SoundEvents.COW_MILK, 1.0F, 1.0F);
+ if (incrementFeedCount(stack) < level.purpurConfig.cowFeedMushrooms) {
+ if (!player.getAbilities().instabuild) {
+ stack.shrink(1);
+ }
+ return InteractionResult.CONSUME; // require 5 mushrooms to transform (prevents mushroom duping)
+ }
+ MushroomCow mooshroom = EntityType.MOOSHROOM.create(level);
+ if (mooshroom == null) {
+ return InteractionResult.PASS;
+ }
+ if (stack.getItem() == Blocks.BROWN_MUSHROOM.asItem()) {
+ mooshroom.setMushroomType(MushroomCow.MushroomType.BROWN);
+ } else {
+ mooshroom.setMushroomType(MushroomCow.MushroomType.RED);
+ }
+ mooshroom.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
+ mooshroom.setHealth(this.getHealth());
+ mooshroom.setAge(getAge());
+ mooshroom.copyPosition(this);
+ mooshroom.setYBodyRot(this.yBodyRot);
+ mooshroom.setYHeadRot(this.getYHeadRot());
+ mooshroom.yRotO = this.yRotO;
+ mooshroom.xRotO = this.xRotO;
+ if (this.hasCustomName()) {
+ mooshroom.setCustomName(this.getCustomName());
+ }
+ if (CraftEventFactory.callEntityTransformEvent(this, mooshroom, org.bukkit.event.entity.EntityTransformEvent.TransformReason.INFECTION).isCancelled()) {
+ return InteractionResult.PASS;
+ }
+ if (!new com.destroystokyo.paper.event.entity.EntityTransformedEvent(this.getBukkitEntity(), mooshroom.getBukkitEntity(), com.destroystokyo.paper.event.entity.EntityTransformedEvent.TransformedReason.INFECTED).callEvent()) {
+ return InteractionResult.PASS;
+ }
+ this.level.addFreshEntity(mooshroom);
+ this.remove(RemovalReason.DISCARDED);
+ if (!player.getAbilities().instabuild) {
+ stack.shrink(1);
+ }
+ for (int i = 0; i < 15; ++i) {
+ ((ServerLevel) level).sendParticles(((ServerLevel) level).players, null, ParticleTypes.HAPPY_VILLAGER,
+ getX() + random.nextFloat(), getY() + (random.nextFloat() * 2), getZ() + random.nextFloat(), 1,
+ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0, true);
+ }
+ return InteractionResult.SUCCESS;
+ }
+ // Purpur end
+
@Override
public Cow getBreedOffspring(ServerLevel world, AgeableMob entity) {
return (Cow) EntityType.COW.create((Level) world);
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 8f7e7007633ee30f3f943d583623c122d5bc7de3..c5124c7beff61ea1a60db0b0e14f99f3302831b9 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -289,6 +289,7 @@ public class PurpurWorldConfig {
public boolean cowRidable = false;
public boolean cowRidableInWater = false;
public double cowMaxHealth = 10.0D;
+ public int cowFeedMushrooms = 0;
private void cowSettings() {
cowRidable = getBoolean("mobs.cow.ridable", cowRidable);
cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater);
@@ -298,6 +299,7 @@ public class PurpurWorldConfig {
set("mobs.cow.attributes.max_health", oldValue);
}
cowMaxHealth = getDouble("mobs.cow.attributes.max_health", cowMaxHealth);
+ cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms);
}
public boolean creeperRidable = false;

View File

@@ -0,0 +1,24 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 3 May 2019 23:53:16 -0500
Subject: [PATCH] Fix cow rotation when shearing mooshroom
diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java
index b9aeb196f61582801416dab21c12d50e2e68d39e..9dde33111658b2b80dfe9609114067332ec7df27 100644
--- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java
+++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java
@@ -194,7 +194,13 @@ public class MushroomCow extends Cow implements Shearable {
entitycow.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
entitycow.setHealth(this.getHealth());
+ // Purpur start
+ entitycow.copyPosition(this);
entitycow.yBodyRot = this.yBodyRot;
+ entitycow.setYHeadRot(this.getYHeadRot());
+ entitycow.yRotO = this.yRotO;
+ entitycow.xRotO = this.xRotO;
+ // Purpur end
if (this.hasCustomName()) {
entitycow.setCustomName(this.getCustomName());
entitycow.setCustomNameVisible(this.isCustomNameVisible());

View File

@@ -0,0 +1,49 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sun, 12 May 2019 01:14:46 -0500
Subject: [PATCH] Pigs give saddle back
diff --git a/src/main/java/net/minecraft/world/entity/animal/Pig.java b/src/main/java/net/minecraft/world/entity/animal/Pig.java
index 6842ed6eeeaf2785efd7518d1143c75de3240114..88dba06737af2157e1efc0fe355c4cbb3515edf1 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Pig.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Pig.java
@@ -173,6 +173,18 @@ public class Pig extends Animal implements ItemSteerable, Saddleable {
if (!flag && this.isSaddled() && !this.isVehicle() && !player.isSecondaryUseActive()) {
if (!this.level.isClientSide) {
+ // Purpur start
+ if (level.purpurConfig.pigGiveSaddleBack && player.isCrouching()) {
+ this.steering.setSaddle(false);
+ if (!player.getAbilities().instabuild) {
+ ItemStack saddle = new ItemStack(Items.SADDLE);
+ if (!player.getInventory().add(saddle)) {
+ player.drop(saddle, false);
+ }
+ }
+ return InteractionResult.SUCCESS;
+ }
+ // Purpur end
player.startRiding(this);
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index c5124c7beff61ea1a60db0b0e14f99f3302831b9..91d62888b6012b51b1eeb29b864d7d560397b7c1 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -779,6 +779,7 @@ public class PurpurWorldConfig {
public boolean pigRidable = false;
public boolean pigRidableInWater = false;
public double pigMaxHealth = 10.0D;
+ public boolean pigGiveSaddleBack = false;
private void pigSettings() {
pigRidable = getBoolean("mobs.pig.ridable", pigRidable);
pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater);
@@ -788,6 +789,7 @@ public class PurpurWorldConfig {
set("mobs.pig.attributes.max_health", oldValue);
}
pigMaxHealth = getDouble("mobs.pig.attributes.max_health", pigMaxHealth);
+ pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack);
}
public boolean piglinRidable = false;

View File

@@ -0,0 +1,55 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 3 May 2019 23:58:44 -0500
Subject: [PATCH] Snowman drop and put back pumpkin
diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java
index dac6b75f6b489c880fa2093594102778b675d8ac..9ea7682c7cb4c4be1c44d3dd12dc6954d44d659e 100644
--- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java
+++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java
@@ -184,6 +184,14 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
}
return InteractionResult.sidedSuccess(this.level.isClientSide);
+ // Purpur start
+ } else if (level.purpurConfig.snowGolemPutPumpkinBack && !hasPumpkin() && itemstack.getItem() == Blocks.CARVED_PUMPKIN.asItem()) {
+ setPumpkin(false);
+ if (!player.getAbilities().instabuild) {
+ itemstack.shrink(1);
+ }
+ return InteractionResult.SUCCESS;
+ // Purpur end
} else {
return tryRide(player, hand); // Purpur
}
@@ -195,6 +203,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
if (!this.level.isClientSide()) {
this.setPumpkin(false);
this.forceDrops = true; // CraftBukkit
+ if (level.purpurConfig.snowGolemDropsPumpkin) // Purpur
this.spawnAtLocation(new ItemStack(Items.CARVED_PUMPKIN), 1.7F);
this.forceDrops = false; // CraftBukkit
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 91d62888b6012b51b1eeb29b864d7d560397b7c1..94b7f06779eda71e7e14458d1e1eacc1969e899c 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1010,6 +1010,8 @@ public class PurpurWorldConfig {
public boolean snowGolemRidableInWater = false;
public boolean snowGolemLeaveTrailWhenRidden = false;
public double snowGolemMaxHealth = 4.0D;
+ public boolean snowGolemDropsPumpkin = true;
+ public boolean snowGolemPutPumpkinBack = false;
private void snowGolemSettings() {
snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable);
snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater);
@@ -1020,6 +1022,8 @@ public class PurpurWorldConfig {
set("mobs.snow_golem.attributes.max_health", oldValue);
}
snowGolemMaxHealth = getDouble("mobs.snow_golem.attributes.max_health", snowGolemMaxHealth);
+ snowGolemDropsPumpkin = getBoolean("mobs.snow_golem.drop-pumpkin-when-sheared", snowGolemDropsPumpkin);
+ snowGolemPutPumpkinBack = getBoolean("mobs.snow_golem.pumpkin-can-be-added-back", snowGolemPutPumpkinBack);
}
public boolean squidRidable = false;

View File

@@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 24 Aug 2019 14:42:54 -0500
Subject: [PATCH] Ender dragon always drop full exp
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
index d3caa18f5de2d96eae691655dd13e83f82c61e0c..f637cd740ec3801ce1c387473b5c4ff6080e76ec 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
@@ -709,7 +709,7 @@ public class EnderDragon extends Mob implements Enemy {
boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT);
short short0 = 500;
- if (this.dragonFight != null && !this.dragonFight.hasPreviouslyKilledDragon()) {
+ if (this.dragonFight != null && (level.purpurConfig.enderDragonAlwaysDropsFullExp || !this.dragonFight.hasPreviouslyKilledDragon())) {
short0 = 12000;
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 94b7f06779eda71e7e14458d1e1eacc1969e899c..12407ab2b99b9d4aa00ddd73f9257d6de493f524 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -392,6 +392,7 @@ public class PurpurWorldConfig {
public boolean enderDragonRidableInWater = false;
public double enderDragonMaxY = 256D;
public double enderDragonMaxHealth = 200.0D;
+ public boolean enderDragonAlwaysDropsFullExp = false;
private void enderDragonSettings() {
enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable);
enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater);
@@ -406,6 +407,7 @@ public class PurpurWorldConfig {
set("mobs.ender_dragon.attributes.max_health", oldValue);
}
enderDragonMaxHealth = getDouble("mobs.ender_dragon.attributes.max_health", enderDragonMaxHealth);
+ enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp);
}
public boolean endermanRidable = false;

View File

@@ -0,0 +1,52 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 24 May 2019 02:39:25 -0500
Subject: [PATCH] Signs editable on right click
diff --git a/src/main/java/net/minecraft/world/level/block/SignBlock.java b/src/main/java/net/minecraft/world/level/block/SignBlock.java
index 1844ea93f8cea420f01937f85ed17c0ec1bb8bf0..9e80ba8970cad91ea22ac701f76e1413551a591f 100644
--- a/src/main/java/net/minecraft/world/level/block/SignBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SignBlock.java
@@ -14,6 +14,7 @@ import net.minecraft.world.item.DyeItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
+import net.minecraft.world.item.SignItem;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
@@ -108,6 +109,17 @@ public abstract class SignBlock extends BaseEntityBlock implements SimpleWaterlo
}
}
+ // Purpur start - right click to open sign editor
+ if (world.purpurConfig.signRightClickEdit && itemStack.getItem() instanceof SignItem &&
+ !player.isCrouching() && player.getAbilities().mayBuild &&
+ player.getBukkitEntity().hasPermission("purpur.sign.edit")) {
+ signBlockEntity.setEditable(true);
+ signBlockEntity.setAllowedPlayerEditor(player.getUUID());
+ player.openTextEdit(signBlockEntity);
+ return InteractionResult.SUCCESS;
+ }
+ // Purpur end
+
return signBlockEntity.executeClickCommands((ServerPlayer)player) ? InteractionResult.SUCCESS : InteractionResult.PASS;
} else {
return InteractionResult.PASS;
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 12407ab2b99b9d4aa00ddd73f9257d6de493f524..5cfccc5a7ee50b24151d6886a1f336c6b217c24e 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -153,6 +153,11 @@ public class PurpurWorldConfig {
});
}
+ public boolean signRightClickEdit = false;
+ private void signSettings() {
+ signRightClickEdit = getBoolean("blocks.sign.right-click-edit", signRightClickEdit);
+ }
+
public boolean babiesAreRidable = true;
public boolean untamedTamablesAreRidable = true;
public boolean useNightVisionWhenRiding = false;

View File

@@ -0,0 +1,86 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 6 Jun 2019 17:40:30 -0500
Subject: [PATCH] Signs allow color codes
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 7368e7df44c95aa5daa84e617d13ef140c3f96ed..dd8d1a7d634dd02050022ea178882b849c824c03 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1462,6 +1462,7 @@ public class ServerPlayer extends Player {
@Override
public void openTextEdit(SignBlockEntity sign) {
+ if (level.purpurConfig.signAllowColors) this.connection.send(sign.getTranslatedUpdatePacket(textFilteringEnabled)); // Purpur
sign.setAllowedPlayerEditor(this.getUUID());
this.connection.send(new ClientboundBlockUpdatePacket(this.level, sign.getBlockPos()));
this.connection.send(new ClientboundOpenSignEditorPacket(sign.getBlockPos()));
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 68d51846987f4c5707cfc9dec737728770a66f11..367876813fcf772baf6542e1422b5c9572056a18 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -3102,11 +3102,16 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
}
// Paper end
- if (this.player.isTextFilteringEnabled()) {
- lines.add(net.kyori.adventure.text.Component.text(SharedConstants.filterText(currentLine.getFiltered())));
- } else {
- lines.add(net.kyori.adventure.text.Component.text(SharedConstants.filterText(currentLine.getRaw())));
- }
+ // Purpur start
+ String line = SharedConstants.filterText(this.player.isTextFilteringEnabled() ? currentLine.getFiltered() : currentLine.getRaw());
+ if (worldserver.purpurConfig.signAllowColors) {
+ if (player.hasPermission("purpur.sign.color")) line = line.replaceAll("(?i)&([0-9a-fr])", "\u00a7$1");
+ if (player.hasPermission("purpur.sign.style")) line = line.replaceAll("(?i)&([l-or])", "\u00a7$1");
+ if (player.hasPermission("purpur.sign.magic")) line = line.replaceAll("(?i)&([kr])", "\u00a7$1");
+ lines.add(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(line));
+ } else
+ lines.add(net.kyori.adventure.text.Component.text(line));
+ // Purpur end
}
SignChangeEvent event = new SignChangeEvent((org.bukkit.craftbukkit.block.CraftBlock) player.getWorld().getBlockAt(x, y, z), this.player.getBukkitEntity(), lines);
this.cserver.getPluginManager().callEvent(event);
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
index 344d3a8c1162f1a4ab5fc2b7676680ddace46649..156a153abe59f86db7f942155d8a21de2fd83ce2 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
@@ -181,6 +181,22 @@ public class SignBlockEntity extends BlockEntity implements CommandSource { // C
return filtered ? this.filteredMessages : this.messages;
}
+ // Purpur start
+ public ClientboundBlockEntityDataPacket getTranslatedUpdatePacket(boolean filtered) {
+ final CompoundTag nbt = save(new CompoundTag());
+ final Component[] lines = getMessages(filtered);
+ for (int i = 0; i < 4; ++i) {
+ final var component = io.papermc.paper.adventure.PaperAdventure.asAdventure(lines[i]);
+ final String line = io.papermc.paper.adventure.PaperAdventure.LEGACY_AMPERSAND.serialize(component);
+ final var text = net.kyori.adventure.text.Component.text(line);
+ final String json = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(text);
+ nbt.putString("Text" + (i + 1), json);
+ }
+ nbt.putString("PurpurEditor", "true");
+ return new ClientboundBlockEntityDataPacket(worldPosition, 9, nbt);
+ }
+ // Purpur end
+
@Nullable
@Override
public ClientboundBlockEntityDataPacket getUpdatePacket() {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 5cfccc5a7ee50b24151d6886a1f336c6b217c24e..ea387b513f86249a6ceaa67cb6358dc56ed4b16d 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -153,8 +153,10 @@ public class PurpurWorldConfig {
});
}
+ public boolean signAllowColors = false;
public boolean signRightClickEdit = false;
private void signSettings() {
+ signAllowColors = getBoolean("blocks.sign.allow-colors", signAllowColors);
signRightClickEdit = getBoolean("blocks.sign.right-click-edit", signRightClickEdit);
}

View File

@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 21 Jun 2019 14:37:10 -0500
Subject: [PATCH] Allow soil to moisten from water directly under it
diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
index 5955c95efbfa3e614ecf03de3e485a1ea88b7859..f638c7b27a846bf9db73e98ce9eb5d579bc25cac 100644
--- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
@@ -159,7 +159,7 @@ public class FarmBlock extends Block {
}
}
- return false;
+ return ((ServerLevel) world).purpurConfig.farmlandGetsMoistFromBelow && world.getFluidState(pos.relative(Direction.DOWN)).is(FluidTags.WATER); // Purpur
// Paper end - remove abstract block iteration
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index ea387b513f86249a6ceaa67cb6358dc56ed4b16d..35fbc48c6396f23add351063a9df12f15643a3a8 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -153,6 +153,11 @@ public class PurpurWorldConfig {
});
}
+ public boolean farmlandGetsMoistFromBelow = false;
+ private void farmlandSettings() {
+ farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow);
+ }
+
public boolean signAllowColors = false;
public boolean signRightClickEdit = false;
private void signSettings() {

View File

@@ -0,0 +1,222 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 29 Jun 2019 02:32:40 -0500
Subject: [PATCH] Minecart settings and WASD controls
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index dd8d1a7d634dd02050022ea178882b849c824c03..c488f0c2db28b5eff7209fe900ca27408fc1ce0e 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -989,6 +989,7 @@ public class ServerPlayer extends Player {
if (this.isInvulnerableTo(source)) {
return false;
} else {
+ if (source == DamageSource.FALL && getRootVehicle() instanceof net.minecraft.world.entity.vehicle.AbstractMinecart && level.purpurConfig.minecartControllable && !level.purpurConfig.minecartControllableFallDamage) return false; // Purpur
boolean flag = this.server.isDedicatedServer() && this.isPvpAllowed() && "fall".equals(source.msgId);
if (!flag && isSpawnInvulnerable() && source != DamageSource.OUT_OF_WORLD) { // Purpur
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java
index 309bafd257d4932cfd69c2c212b32306938cd234..1e3077a22d9d3d26356b865001dcce81c9c1d7e5 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java
@@ -110,11 +110,13 @@ public abstract class AbstractMinecart extends Entity {
private double flyingY = 0.949999988079071D; // Paper - restore vanilla precision
private double flyingZ = 0.949999988079071D; // Paper - restore vanilla precision
public double maxSpeed = 0.4D;
+ public double storedMaxSpeed; // Purpur
// CraftBukkit end
protected AbstractMinecart(EntityType<?> type, Level world) {
super(type, world);
this.blocksBuilding = true;
+ if (world != null) maxSpeed = storedMaxSpeed = world.purpurConfig.minecartMaxSpeed; // Purpur
}
protected AbstractMinecart(EntityType<?> type, Level world, double x, double y, double z) {
@@ -327,6 +329,12 @@ public abstract class AbstractMinecart extends Entity {
@Override
public void tick() {
+ // Purpur start
+ if (storedMaxSpeed != level.purpurConfig.minecartMaxSpeed) {
+ maxSpeed = storedMaxSpeed = level.purpurConfig.minecartMaxSpeed;
+ }
+ // Purpur end
+
// CraftBukkit start
double prevX = this.getX();
double prevY = this.getY();
@@ -490,16 +498,62 @@ public abstract class AbstractMinecart extends Entity {
public void activateMinecart(int x, int y, int z, boolean powered) {}
+ // Purpur start
+ private Double lastSpeed;
+
+ public double getControllableSpeed() {
+ BlockPos pos = new BlockPos(this);
+ Block block = level.getBlockState(pos).getBlock();
+ if (!block.material.isSolid()) {
+ block = level.getBlockState(pos.relative(Direction.DOWN)).getBlock();
+ }
+ Double speed = level.purpurConfig.minecartControllableBlockSpeeds.get(block);
+ if (!block.material.isSolid()) {
+ speed = lastSpeed;
+ } else if (speed == null) {
+ speed = level.purpurConfig.minecartControllableBaseSpeed;
+ }
+ return lastSpeed = speed;
+ }
+ // Purpur end
+
protected void comeOffTrack() {
double d0 = this.getMaxSpeed();
Vec3 vec3d = this.getDeltaMovement();
this.setDeltaMovement(Mth.clamp(vec3d.x, -d0, d0), vec3d.y, Mth.clamp(vec3d.z, -d0, d0));
+
+ // Purpur start
+ if (level.purpurConfig.minecartControllable && !isInWater() && !isInLava() && !passengers.isEmpty()) {
+ Entity passenger = passengers.get(0);
+ if (passenger instanceof Player) {
+ Player player = (Player) passenger;
+ if (player.jumping && this.onGround) {
+ setDeltaMovement(new Vec3(getDeltaMovement().x, level.purpurConfig.minecartControllableHopBoost, getDeltaMovement().z));
+ }
+ if (player.zza != 0.0F) {
+ Vector velocity = player.getBukkitEntity().getEyeLocation().getDirection().normalize().multiply(getControllableSpeed());
+ if (player.zza < 0.0) {
+ velocity.multiply(-0.5);
+ }
+ setDeltaMovement(new Vec3(velocity.getX(), getDeltaMovement().y, velocity.getZ()));
+ }
+ this.setYRot(passenger.getYRot() - 90);
+ maxUpStep = level.purpurConfig.minecartControllableStepHeight;
+ } else {
+ maxUpStep = 0.0F;
+ }
+ } else {
+ maxUpStep = 0.0F;
+ }
+ // Purpur end
+
if (this.onGround) {
// CraftBukkit start - replace magic numbers with our variables
this.setDeltaMovement(new Vec3(this.getDeltaMovement().x * this.derailedX, this.getDeltaMovement().y * this.derailedY, this.getDeltaMovement().z * this.derailedZ));
// CraftBukkit end
}
+ else if (level.purpurConfig.minecartControllable) setDeltaMovement(new Vec3(getDeltaMovement().x * derailedX, getDeltaMovement().y, getDeltaMovement().z * derailedZ)); // Purpur
this.move(MoverType.SELF, this.getDeltaMovement());
if (!this.onGround) {
diff --git a/src/main/java/net/minecraft/world/item/MinecartItem.java b/src/main/java/net/minecraft/world/item/MinecartItem.java
index 9ea3837acc315e5c57f28c63c356efd633f1e6cf..e8b76b67f972c2f44e7611434246a822d549a129 100644
--- a/src/main/java/net/minecraft/world/item/MinecartItem.java
+++ b/src/main/java/net/minecraft/world/item/MinecartItem.java
@@ -123,8 +123,9 @@ public class MinecartItem extends Item {
BlockState iblockdata = world.getBlockState(blockposition);
if (!iblockdata.is((Tag) BlockTags.RAILS)) {
- return InteractionResult.FAIL;
- } else {
+ if (!world.purpurConfig.minecartPlaceAnywhere) return InteractionResult.FAIL;
+ if (iblockdata.getMaterial().isSolid()) blockposition = blockposition.relative(context.getClickedFace());
+ } // else { // Purpur - place minecarts anywhere
ItemStack itemstack = context.getItemInHand();
if (!world.isClientSide) {
@@ -152,6 +153,6 @@ public class MinecartItem extends Item {
itemstack.shrink(1);
return InteractionResult.sidedSuccess(world.isClientSide);
- }
+ // } // Purpur - place minecarts anywhere
}
}
diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
index 83d813025efca5846538e36508a5d4fe38b02108..8a6fdccb7db4234d9557f3b63f7761feb15bbed7 100644
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
@@ -70,7 +70,7 @@ import net.minecraft.world.phys.shapes.VoxelShape;
public abstract class BlockBehaviour {
protected static final Direction[] UPDATE_SHAPE_ORDER = new Direction[]{Direction.WEST, Direction.EAST, Direction.NORTH, Direction.SOUTH, Direction.DOWN, Direction.UP};
- protected final Material material;
+ public final Material material; // Purpur - protected -> public
public final boolean hasCollision;
protected final float explosionResistance;
protected final boolean isRandomlyTicking;
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 35fbc48c6396f23add351063a9df12f15643a3a8..77d19b9bea9fce62c1438f399574393f7282e849 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -99,6 +99,68 @@ public class PurpurWorldConfig {
armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight);
}
+ public double minecartMaxSpeed = 0.4D;
+ public boolean minecartPlaceAnywhere = false;
+ public boolean minecartControllable = false;
+ public float minecartControllableStepHeight = 1.0F;
+ public double minecartControllableHopBoost = 0.5D;
+ public boolean minecartControllableFallDamage = true;
+ public double minecartControllableBaseSpeed = 0.1D;
+ public Map<Block, Double> minecartControllableBlockSpeeds = new HashMap<>();
+ private void minecartSettings() {
+ if (PurpurConfig.version < 12) {
+ boolean oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.place-anywhere", minecartPlaceAnywhere);
+ set("gameplay-mechanics.controllable-minecarts.place-anywhere", null);
+ set("gameplay-mechanics.minecart.place-anywhere", oldBool);
+ oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.enabled", minecartControllable);
+ set("gameplay-mechanics.controllable-minecarts.enabled", null);
+ set("gameplay-mechanics.minecart.controllable.enabled", oldBool);
+ double oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.step-height", minecartControllableStepHeight);
+ set("gameplay-mechanics.controllable-minecarts.step-height", null);
+ set("gameplay-mechanics.minecart.controllable.step-height", oldDouble);
+ oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.hop-boost", minecartControllableHopBoost);
+ set("gameplay-mechanics.controllable-minecarts.hop-boost", null);
+ set("gameplay-mechanics.minecart.controllable.hop-boost", oldDouble);
+ oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.fall-damage", minecartControllableFallDamage);
+ set("gameplay-mechanics.controllable-minecarts.fall-damage", null);
+ set("gameplay-mechanics.minecart.controllable.fall-damage", oldBool);
+ oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.base-speed", minecartControllableBaseSpeed);
+ set("gameplay-mechanics.controllable-minecarts.base-speed", null);
+ set("gameplay-mechanics.minecart.controllable.base-speed", oldDouble);
+ ConfigurationSection section = getConfigurationSection("gameplay-mechanics.controllable-minecarts.block-speed");
+ if (section != null) {
+ for (String key : section.getKeys(false)) {
+ if ("grass-block".equals(key)) key = "grass_block"; // oopsie
+ oldDouble = section.getDouble(key, minecartControllableBaseSpeed);
+ set("gameplay-mechanics.controllable-minecarts.block-speed." + key, null);
+ set("gameplay-mechanics.minecart.controllable.block-speed." + key, oldDouble);
+ }
+ set("gameplay-mechanics.controllable-minecarts.block-speed", null);
+ }
+ set("gameplay-mechanics.controllable-minecarts", null);
+ }
+
+ minecartMaxSpeed = getDouble("gameplay-mechanics.minecart.max-speed", minecartMaxSpeed);
+ minecartPlaceAnywhere = getBoolean("gameplay-mechanics.minecart.place-anywhere", minecartPlaceAnywhere);
+ minecartControllable = getBoolean("gameplay-mechanics.minecart.controllable.enabled", minecartControllable);
+ minecartControllableStepHeight = (float) getDouble("gameplay-mechanics.minecart.controllable.step-height", minecartControllableStepHeight);
+ minecartControllableHopBoost = getDouble("gameplay-mechanics.minecart.controllable.hop-boost", minecartControllableHopBoost);
+ minecartControllableFallDamage = getBoolean("gameplay-mechanics.minecart.controllable.fall-damage", minecartControllableFallDamage);
+ minecartControllableBaseSpeed = getDouble("gameplay-mechanics.minecart.controllable.base-speed", minecartControllableBaseSpeed);
+ ConfigurationSection section = getConfigurationSection("gameplay-mechanics.minecart.controllable.block-speed");
+ if (section != null) {
+ for (String key : section.getKeys(false)) {
+ Block block = Registry.BLOCK.get(new ResourceLocation(key));
+ if (block != Blocks.AIR) {
+ minecartControllableBlockSpeeds.put(block, section.getDouble(key, minecartControllableBaseSpeed));
+ }
+ }
+ } else {
+ set("gameplay-mechanics.minecart.controllable.block-speed.grass_block", 0.3D);
+ set("gameplay-mechanics.minecart.controllable.block-speed.stone", 0.5D);
+ }
+ }
+
public boolean idleTimeoutKick = true;
public boolean idleTimeoutTickNearbyEntities = true;
public boolean idleTimeoutCountAsSleeping = false;

View File

@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Wed, 3 Jul 2019 23:58:31 -0500
Subject: [PATCH] Disable loot drops on death by cramming
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index a0b8154c44401dde57a729e202ba59688aea54bd..0cac4def285ae94dec2e9320183eabfe69342ff2 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1709,8 +1709,10 @@ public abstract class LivingEntity extends Entity {
this.dropEquipment(); // CraftBukkit - from below
if (this.shouldDropLoot() && this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
+ if (!(source == DamageSource.CRAMMING && level.purpurConfig.disableDropsOnCrammingDeath)) { // Purpur
this.dropFromLootTable(source, flag);
this.dropCustomDeathLoot(source, i, flag);
+ } // Purpur
}
// CraftBukkit start - Call death event
org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, this.drops); // Paper
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 77d19b9bea9fce62c1438f399574393f7282e849..209c269d0a5351a206451ab9724307d811c16a11 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -215,6 +215,11 @@ public class PurpurWorldConfig {
});
}
+ public boolean disableDropsOnCrammingDeath = false;
+ private void miscGameplayMechanicsSettings() {
+ disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath);
+ }
+
public boolean farmlandGetsMoistFromBelow = false;
private void farmlandSettings() {
farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow);

View File

@@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Wed, 10 Jul 2019 20:43:05 -0500
Subject: [PATCH] Option to toggle milk curing bad omen
diff --git a/src/main/java/net/minecraft/world/item/MilkBucketItem.java b/src/main/java/net/minecraft/world/item/MilkBucketItem.java
index f33977d95b6db473be4f95075ba99caf90ad0220..56dc04d8875971ee9a5d077a695509af74fe2473 100644
--- a/src/main/java/net/minecraft/world/item/MilkBucketItem.java
+++ b/src/main/java/net/minecraft/world/item/MilkBucketItem.java
@@ -5,6 +5,8 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stats;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
+import net.minecraft.world.effect.MobEffectInstance;
+import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
@@ -31,7 +33,9 @@ public class MilkBucketItem extends Item {
}
if (!world.isClientSide) {
+ MobEffectInstance badOmen = user.getEffect(MobEffects.BAD_OMEN);
user.removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.MILK); // CraftBukkit
+ if (!world.purpurConfig.milkCuresBadOmen && badOmen != null) user.addEffect(badOmen); // Purpur
}
return stack.isEmpty() ? new ItemStack(Items.BUCKET) : stack;
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 209c269d0a5351a206451ab9724307d811c16a11..ba2d49771e317d52b46868372572f59bf2fc3394 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -216,8 +216,10 @@ public class PurpurWorldConfig {
}
public boolean disableDropsOnCrammingDeath = false;
+ public boolean milkCuresBadOmen = true;
private void miscGameplayMechanicsSettings() {
disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath);
+ milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen);
}
public boolean farmlandGetsMoistFromBelow = false;

View File

@@ -0,0 +1,18 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 21 Mar 2020 18:33:05 -0500
Subject: [PATCH] End gateway should check if entity can use portal
diff --git a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
index 0b238666a506816b8948d1db7397c26ca50b89d3..b2c098a02008b860b2fb17323831ab8af27751ae 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
@@ -178,6 +178,7 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity {
public static void teleportEntity(Level world, BlockPos pos, BlockState state, Entity entity, TheEndGatewayBlockEntity blockEntity) {
if (world instanceof ServerLevel && !blockEntity.isCoolingDown()) {
+ if (!entity.canChangeDimensions()) return; // Purpur
ServerLevel worldserver = (ServerLevel) world;
blockEntity.teleportCooldown = 100;

View File

@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 6 Mar 2020 13:37:26 -0600
Subject: [PATCH] Fix the dead lagging the server
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 0db5317b1d06ecdf0b9d199fd36fdd26e856230b..9080bac56a64cb13a316374798fb5c5298a2475b 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -1743,6 +1743,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
this.yRotO = this.getYRot();
this.xRotO = this.getXRot();
this.setYHeadRot(yaw); // Paper - Update head rotation
+ if (valid && !this.isRemoved()) level.getChunk((int) Math.floor(this.getX()) >> 4, (int) Math.floor(this.getZ()) >> 4); // CraftBukkit // Paper // Purpur
}
public void absMoveTo(double x, double y, double z) {
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 0cac4def285ae94dec2e9320183eabfe69342ff2..27a07aa2b1a85267b2012eb882acb36b04fded66 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -2896,7 +2896,7 @@ public abstract class LivingEntity extends Entity {
}
}
- this.aiStep();
+ if (!this.isRemoved()) this.aiStep(); // Purpur
double d0 = this.getX() - this.xo;
double d1 = this.getZ() - this.zo;
float f = (float) (d0 * d0 + d1 * d1);

View File

@@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 4 Apr 2020 03:07:59 -0500
Subject: [PATCH] Skip events if there's no listeners
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
index b7c24a7ff4dc50d03f74b21a0b353d0ce559b4d4..dc0d785432b8e511a738bebb5c7335432b69427f 100644
--- a/src/main/java/net/minecraft/commands/Commands.java
+++ b/src/main/java/net/minecraft/commands/Commands.java
@@ -382,6 +382,7 @@ public class Commands {
}
private void runSync(ServerPlayer player, Collection<String> bukkit, RootCommandNode<SharedSuggestionProvider> rootcommandnode) {
+ if (PlayerCommandSendEvent.getHandlerList().getRegisteredListeners().length > 0) { // Purpur - skip all this crap if there's nothing listening
// Paper end - Async command map building
new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent<CommandSourceStack>(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper
PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit));
@@ -394,6 +395,7 @@ public class Commands {
}
}
// CraftBukkit end
+ } // Purpur - skip event
player.connection.send(new ClientboundCommandsPacket(rootcommandnode));
}

View File

@@ -0,0 +1,18 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 28 Dec 2019 04:21:54 -0600
Subject: [PATCH] Add permission for F3+N debug
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 8e4c01a9b8994c3467bbb64661d457ce64ba3a6b..7880893c132f95df4dcfea564b4c40c2b8256ea4 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -1163,6 +1163,7 @@ public abstract class PlayerList {
} else {
b0 = (byte) (24 + permissionLevel);
}
+ if (b0 < 28 && player.getBukkitEntity().hasPermission("purpur.debug.f3n")) b0 = 28; // Purpur
player.connection.send(new ClientboundEntityEventPacket(player, b0));
}

View File

@@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 26 Mar 2020 19:06:22 -0500
Subject: [PATCH] Configurable TPS Catchup
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 1049f5f40d07f0c0fde965b1ab927607651b3e38..d894903c3f5c8b12b759896d8dd315a0f4c69d19 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1284,7 +1284,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.tickServer(this::haveTime);
this.profiler.popPush("nextTickWait");
this.mayHaveDelayedTasks = true;
- this.delayedTasksMaxNextTickTime = Math.max(Util.getMillis() + 50L, this.nextTickTime);
+ // Purpur start - tps catchup
+ if (net.pl3x.purpur.PurpurConfig.tpsCatchup) {
+ this.delayedTasksMaxNextTickTime = Math.max(Util.getMillis() + 50L, this.nextTickTime);
+ } else {
+ this.delayedTasksMaxNextTickTime = this.nextTickTime = curTime / 1000000L + 50L;
+ }
+ // Purpur end - tps catchup
this.waitUntilNextTick();
this.profiler.pop();
this.endMetricsRecordingTick();
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index 504e8d2f9c0a2c8c8f6a710c0ad1d438f53d1439..c27088998dca02124c0381dd4166d63e75a634f6 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -246,4 +246,9 @@ public class PurpurConfig {
loggerSuppressIgnoredAdvancementWarnings = getBoolean("settings.logger.suppress-ignored-advancement-warnings", loggerSuppressIgnoredAdvancementWarnings);
loggerSuppressUnrecognizedRecipeErrors = getBoolean("settings.logger.suppress-unrecognized-recipe-errors", loggerSuppressUnrecognizedRecipeErrors);
}
+
+ public static boolean tpsCatchup = true;
+ private static void tpsCatchup() {
+ tpsCatchup = getBoolean("settings.tps-catchup", tpsCatchup);
+ }
}

View File

@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 19 Mar 2020 19:39:34 -0500
Subject: [PATCH] Add option to allow loyalty on tridents to work in the void
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java
index c95eef8596fe3e1ca83e620a6c54b164c797cbe1..1e6a5404d767318de29184b3e3a2bc41c1ee2602 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java
@@ -61,7 +61,7 @@ public class ThrownTrident extends AbstractArrow {
Entity entity = this.getOwner();
byte b0 = (Byte) this.entityData.get(ThrownTrident.ID_LOYALTY);
- if (b0 > 0 && (this.dealtDamage || this.isNoPhysics()) && entity != null) {
+ if (b0 > 0 && (this.dealtDamage || this.isNoPhysics() || (level.purpurConfig.tridentLoyaltyVoidReturnHeight < 0.0D && getY() < level.purpurConfig.tridentLoyaltyVoidReturnHeight)) && entity != null) { // Purpur
if (!this.isAcceptibleReturnOwner()) {
if (!this.level.isClientSide && this.pickup == AbstractArrow.Pickup.ALLOWED) {
this.spawnAtLocation(this.getPickupItem(), 0.1F);
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index ba2d49771e317d52b46868372572f59bf2fc3394..1ff4e926accf8029315d5d2ffd209f62b16fd729 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -217,9 +217,11 @@ public class PurpurWorldConfig {
public boolean disableDropsOnCrammingDeath = false;
public boolean milkCuresBadOmen = true;
+ public double tridentLoyaltyVoidReturnHeight = 0.0D;
private void miscGameplayMechanicsSettings() {
disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath);
milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen);
+ tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight);
}
public boolean farmlandGetsMoistFromBelow = false;

View File

@@ -0,0 +1,75 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sun, 26 Apr 2020 16:28:38 -0500
Subject: [PATCH] Add enderman and creeper griefing controls
diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java
index 7fbe8fb2b59fe2f578beed8b13cbbbe96011719f..96858c10ad219a47187d3008387355f1bcfdc789 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java
@@ -344,7 +344,7 @@ public class Creeper extends Monster implements PowerableMob {
public void explodeCreeper() {
if (!this.level.isClientSide) {
- Explosion.BlockInteraction explosion_effect = this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.NONE;
+ Explosion.BlockInteraction explosion_effect = this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && level.purpurConfig.creeperAllowGriefing ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.NONE; // Purpur
float f = this.isPowered() ? 2.0F : 1.0F;
// CraftBukkit start
diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
index cb904b7822cfe645626d3306302afe1085cddce5..ec772f1ec312c3e51287d86eb2023cee80e55d7b 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
@@ -474,6 +474,7 @@ public class EnderMan extends Monster implements NeutralMob {
@Override
public boolean canUse() {
+ if (!enderman.level.purpurConfig.endermanAllowGriefing) return false; // Purpur
return this.enderman.getCarriedBlock() == null ? false : (!this.enderman.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? false : this.enderman.getRandom().nextInt(2000) == 0);
}
@@ -521,6 +522,7 @@ public class EnderMan extends Monster implements NeutralMob {
@Override
public boolean canUse() {
+ if (!enderman.level.purpurConfig.endermanAllowGriefing) return false; // Purpur
return this.enderman.getCarriedBlock() != null ? false : (!this.enderman.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? false : this.enderman.getRandom().nextInt(20) == 0);
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 1ff4e926accf8029315d5d2ffd209f62b16fd729..cd77b51e3cc64f34e0f1cb163c17d2f3bf054880 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -389,6 +389,7 @@ public class PurpurWorldConfig {
public boolean creeperRidableInWater = false;
public double creeperMaxHealth = 20.0D;
public double creeperChargedChance = 0.0D;
+ public boolean creeperAllowGriefing = true;
private void creeperSettings() {
creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable);
creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater);
@@ -399,6 +400,7 @@ public class PurpurWorldConfig {
}
creeperMaxHealth = getDouble("mobs.creeper.attributes.max_health", creeperMaxHealth);
creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance);
+ creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing);
}
public boolean dolphinRidable = false;
@@ -496,6 +498,7 @@ public class PurpurWorldConfig {
public boolean endermanRidable = false;
public boolean endermanRidableInWater = false;
public double endermanMaxHealth = 40.0D;
+ public boolean endermanAllowGriefing = true;
private void endermanSettings() {
endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable);
endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater);
@@ -505,6 +508,7 @@ public class PurpurWorldConfig {
set("mobs.enderman.attributes.max_health", oldValue);
}
endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth);
+ endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing);
}
public boolean endermiteRidable = false;

View File

@@ -0,0 +1,91 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 29 Nov 2019 22:10:12 -0600
Subject: [PATCH] Villagers follow emerald blocks
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java
index 30ef9d0a431b393b7238e497d16e8013f90036ef..90f8434100893d577544f7f5fbbc4503223390c0 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java
@@ -60,7 +60,7 @@ public class TemptGoal extends Goal {
}
private boolean shouldFollow(LivingEntity entity) {
- return this.items.test(entity.getMainHandItem()) || this.items.test(entity.getOffhandItem());
+ return (this.items.test(entity.getMainHandItem()) || this.items.test(entity.getOffhandItem())) && (!(this.mob instanceof net.minecraft.world.entity.npc.Villager villager) || !villager.isSleeping()); // Purpur Fix #512
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
index c75fa3274dedfafa11b94704695a2313f11c22cc..f22ec35a7960bbc2f205d972dbe78d87eb9a7e25 100644
--- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
@@ -43,6 +43,7 @@ import org.bukkit.event.entity.VillagerAcquireTradeEvent;
// CraftBukkit end
public abstract class AbstractVillager extends AgeableMob implements InventoryCarrier, Npc, Merchant {
+ static final net.minecraft.world.item.crafting.Ingredient TEMPT_ITEMS = net.minecraft.world.item.crafting.Ingredient.of(net.minecraft.world.level.block.Blocks.EMERALD_BLOCK.asItem()); // Purpur
// CraftBukkit start
private CraftMerchant craftMerchant;
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index 136b6f0f19c9ece222eedbf2b20b118e206ee3e9..4bc275fed808978d4645f814028a4f11a70375b2 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -171,6 +171,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this));
+ if (level.purpurConfig.villagerFollowEmeraldBlock) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.TemptGoal(this, 1.0D, TEMPT_ITEMS, false));
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
index 0bcfece84ac11f04671ed38a99b31da9f8b03858..2f0bcf917af26fb7628bda134b650a8b296091ea 100644
--- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
@@ -104,6 +104,7 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
this.goalSelector.addGoal(1, new PanicGoal(this, 0.5D));
this.goalSelector.addGoal(1, new LookAtTradingPlayerGoal(this));
this.goalSelector.addGoal(2, new WanderingTrader.WanderToPositionGoal(this, 2.0D, 0.35D));
+ if (level.purpurConfig.wanderingTraderFollowEmeraldBlock) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.TemptGoal(this, 1.0D, TEMPT_ITEMS, false)); // Purpur
this.goalSelector.addGoal(4, new MoveTowardsRestrictionGoal(this, 0.35D));
this.goalSelector.addGoal(8, new WaterAvoidingRandomStrollGoal(this, 0.35D));
this.goalSelector.addGoal(9, new InteractGoal(this, Player.class, 3.0F, 1.0F));
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index cd77b51e3cc64f34e0f1cb163c17d2f3bf054880..714ad964c90d8fb8244787899be1338c8ab445f8 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1248,6 +1248,7 @@ public class PurpurWorldConfig {
public double villagerMaxHealth = 20.0D;
public int villagerBrainTicks = 1;
public boolean villagerUseBrainTicksOnlyWhenLagging = true;
+ public boolean villagerFollowEmeraldBlock = false;
private void villagerSettings() {
villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable);
villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater);
@@ -1259,6 +1260,7 @@ public class PurpurWorldConfig {
villagerMaxHealth = getDouble("mobs.villager.attributes.max_health", villagerMaxHealth);
villagerBrainTicks = getInt("mobs.villager.brain-ticks", villagerBrainTicks);
villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging);
+ villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock);
}
public boolean vindicatorRidable = false;
@@ -1278,6 +1280,7 @@ public class PurpurWorldConfig {
public boolean wanderingTraderRidable = false;
public boolean wanderingTraderRidableInWater = false;
public double wanderingTraderMaxHealth = 20.0D;
+ public boolean wanderingTraderFollowEmeraldBlock = false;
private void wanderingTraderSettings() {
wanderingTraderRidable = getBoolean("mobs.wandering_trader.ridable", wanderingTraderRidable);
wanderingTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", wanderingTraderRidableInWater);
@@ -1287,6 +1290,7 @@ public class PurpurWorldConfig {
set("mobs.wandering_trader.attributes.max_health", oldValue);
}
wanderingTraderMaxHealth = getDouble("mobs.wandering_trader.attributes.max_health", wanderingTraderMaxHealth);
+ wanderingTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", wanderingTraderFollowEmeraldBlock);
}
public boolean witchRidable = false;

View File

@@ -0,0 +1,86 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 3 Oct 2019 18:08:03 -0500
Subject: [PATCH] Allow leashing villagers
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index 8bb0634e249b1ffc5b692719738b05281cf26a87..91960c5777fc026053cde1b7487a82d407b69369 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -1219,6 +1219,7 @@ public abstract class Mob extends LivingEntity {
if (!this.isAlive()) {
return InteractionResult.PASS;
} else if (this.getLeashHolder() == player) {
+ if (hand == InteractionHand.OFF_HAND && (level.purpurConfig.villagerCanBeLeashed || level.purpurConfig.wanderingTraderCanBeLeashed) && this instanceof net.minecraft.world.entity.npc.AbstractVillager) return InteractionResult.CONSUME; // Purpur
// CraftBukkit start - fire PlayerUnleashEntityEvent
// Paper start - drop leash variable
org.bukkit.event.player.PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(this, player, !player.getAbilities().instabuild);
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index 4bc275fed808978d4645f814028a4f11a70375b2..773015751a9e220e4b23bb9f6889aa1e085b567c 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -178,6 +178,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
public void initAttributes() {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level.purpurConfig.villagerMaxHealth);
}
+
+ @Override
+ public boolean canBeLeashed(Player player) {
+ return level.purpurConfig.villagerCanBeLeashed && !this.isLeashed();
+ }
// Purpur end
@Override
diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
index 2f0bcf917af26fb7628bda134b650a8b296091ea..c5dbb1c8210b71f7d9d91089cb139f65605573a8 100644
--- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
@@ -82,6 +82,11 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
public void initAttributes() {
this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level.purpurConfig.wanderingTraderMaxHealth);
}
+
+ @Override
+ public boolean canBeLeashed(Player player) {
+ return level.purpurConfig.wanderingTraderCanBeLeashed && !this.isLeashed();
+ }
// Purpur end
@Override
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 714ad964c90d8fb8244787899be1338c8ab445f8..66198aa053072cf95b6d8f988ae839ec72fa67f0 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1249,6 +1249,7 @@ public class PurpurWorldConfig {
public int villagerBrainTicks = 1;
public boolean villagerUseBrainTicksOnlyWhenLagging = true;
public boolean villagerFollowEmeraldBlock = false;
+ public boolean villagerCanBeLeashed = false;
private void villagerSettings() {
villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable);
villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater);
@@ -1261,6 +1262,7 @@ public class PurpurWorldConfig {
villagerBrainTicks = getInt("mobs.villager.brain-ticks", villagerBrainTicks);
villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging);
villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock);
+ villagerCanBeLeashed = getBoolean("mobs.villager.can-be-leashed", villagerCanBeLeashed);
}
public boolean vindicatorRidable = false;
@@ -1281,6 +1283,7 @@ public class PurpurWorldConfig {
public boolean wanderingTraderRidableInWater = false;
public double wanderingTraderMaxHealth = 20.0D;
public boolean wanderingTraderFollowEmeraldBlock = false;
+ public boolean wanderingTraderCanBeLeashed = false;
private void wanderingTraderSettings() {
wanderingTraderRidable = getBoolean("mobs.wandering_trader.ridable", wanderingTraderRidable);
wanderingTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", wanderingTraderRidableInWater);
@@ -1291,6 +1294,7 @@ public class PurpurWorldConfig {
}
wanderingTraderMaxHealth = getDouble("mobs.wandering_trader.attributes.max_health", wanderingTraderMaxHealth);
wanderingTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", wanderingTraderFollowEmeraldBlock);
+ wanderingTraderCanBeLeashed = getBoolean("mobs.wandering_trader.can-be-leashed", wanderingTraderCanBeLeashed);
}
public boolean witchRidable = false;

View File

@@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Mon, 22 Jul 2019 17:32:17 -0500
Subject: [PATCH] Implement configurable search radius for villagers to spawn
iron golems
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index 773015751a9e220e4b23bb9f6889aa1e085b567c..f5a24c2be1c9c4148594130107981ad7434bb835 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -1029,6 +1029,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
@Nullable
private IronGolem trySpawnGolem(ServerLevel world) {
+ if (world.purpurConfig.villagerSpawnIronGolemRadius > 0 && world.getEntitiesOfClass(IronGolem.class, getBoundingBox().inflate(world.purpurConfig.villagerSpawnIronGolemRadius)).size() > world.purpurConfig.villagerSpawnIronGolemLimit) return null; // Purpur
BlockPos blockposition = this.blockPosition();
for (int i = 0; i < 10; ++i) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 66198aa053072cf95b6d8f988ae839ec72fa67f0..999d98cb67fa14427b5a16a46ea047fc90444f7c 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1250,6 +1250,8 @@ public class PurpurWorldConfig {
public boolean villagerUseBrainTicksOnlyWhenLagging = true;
public boolean villagerFollowEmeraldBlock = false;
public boolean villagerCanBeLeashed = false;
+ public int villagerSpawnIronGolemRadius = 0;
+ public int villagerSpawnIronGolemLimit = 0;
private void villagerSettings() {
villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable);
villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater);
@@ -1263,6 +1265,8 @@ public class PurpurWorldConfig {
villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging);
villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock);
villagerCanBeLeashed = getBoolean("mobs.villager.can-be-leashed", villagerCanBeLeashed);
+ villagerSpawnIronGolemRadius = getInt("mobs.villager.spawn-iron-golem.radius", villagerSpawnIronGolemRadius);
+ villagerSpawnIronGolemLimit = getInt("mobs.villager.spawn-iron-golem.limit", villagerSpawnIronGolemLimit);
}
public boolean vindicatorRidable = false;

View File

@@ -0,0 +1,107 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 23 Nov 2019 17:55:42 -0600
Subject: [PATCH] Implement infinite liquids
diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
index 7fda7da544b2d0bbd3803d88ee34c92350a8b8ef..cf3f08e9dd65b88e1377bbf96cf2beb0888ca864 100644
--- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
@@ -217,7 +217,7 @@ public abstract class FlowingFluid extends Fluid {
}
}
- if (this.canConvertToSource() && j >= 2) {
+ if (this.canConvertToSource(world) && j >= getRequiredSources(world)) {
BlockState iblockdata2 = world.getBlockState(pos.below());
FluidState fluid1 = iblockdata2.getFluidState();
@@ -288,6 +288,16 @@ public abstract class FlowingFluid extends Fluid {
return (FluidState) this.getSource().defaultFluidState().setValue(FlowingFluid.FALLING, falling);
}
+ // Purpur start
+ protected boolean canConvertToSource(LevelReader world) {
+ return canConvertToSource();
+ }
+
+ protected int getRequiredSources(LevelReader world) {
+ return 2;
+ }
+ // Purpur end
+
protected abstract boolean canConvertToSource();
protected void spreadTo(LevelAccessor world, BlockPos pos, BlockState state, Direction direction, FluidState fluidState) {
diff --git a/src/main/java/net/minecraft/world/level/material/LavaFluid.java b/src/main/java/net/minecraft/world/level/material/LavaFluid.java
index 695783e64564b1d2a178d57a89737d2a97ab9014..cd1a33a1f10d04a91358f51d736bda34110324c4 100644
--- a/src/main/java/net/minecraft/world/level/material/LavaFluid.java
+++ b/src/main/java/net/minecraft/world/level/material/LavaFluid.java
@@ -199,6 +199,18 @@ public abstract class LavaFluid extends FlowingFluid {
world.levelEvent(1501, pos, 0);
}
+ // Purpur start
+ @Override
+ protected boolean canConvertToSource(LevelReader world) {
+ return world.getWorldBorder().world.purpurConfig.lavaInfinite;
+ }
+
+ @Override
+ protected int getRequiredSources(LevelReader world) {
+ return world.getWorldBorder().world.purpurConfig.lavaInfiniteRequiredSources;
+ }
+ // Purpur end
+
@Override
protected boolean canConvertToSource() {
return false;
diff --git a/src/main/java/net/minecraft/world/level/material/WaterFluid.java b/src/main/java/net/minecraft/world/level/material/WaterFluid.java
index 56d50b9310d30e0f81f3d2549ff5c256eb07cc2a..4cc6d665c7d52b6edcaaa5f9ed1314077f68c224 100644
--- a/src/main/java/net/minecraft/world/level/material/WaterFluid.java
+++ b/src/main/java/net/minecraft/world/level/material/WaterFluid.java
@@ -63,6 +63,18 @@ public abstract class WaterFluid extends FlowingFluid {
return true;
}
+ // Purpur start
+ @Override
+ protected boolean canConvertToSource(LevelReader world) {
+ return world.getWorldBorder().world.purpurConfig.waterInfinite;
+ }
+
+ @Override
+ protected int getRequiredSources(LevelReader world) {
+ return world.getWorldBorder().world.purpurConfig.waterInfiniteRequiredSources;
+ }
+ // Purpur end
+
// Paper start
@Override
protected void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state, BlockPos source) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 999d98cb67fa14427b5a16a46ea047fc90444f7c..078899d049fc0cc9b8823764dd2a3cf57b60ed40 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -229,6 +229,20 @@ public class PurpurWorldConfig {
farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow);
}
+ public boolean lavaInfinite = false;
+ public int lavaInfiniteRequiredSources = 2;
+ private void lavaSettings() {
+ lavaInfinite = getBoolean("blocks.lava.infinite-source", lavaInfinite);
+ lavaInfiniteRequiredSources = getInt("blocks.lava.infinite-required-sources", lavaInfiniteRequiredSources);
+ }
+
+ public boolean waterInfinite = true;
+ public int waterInfiniteRequiredSources = 2;
+ private void waterSources() {
+ waterInfinite = getBoolean("blocks.water.infinite-source", waterInfinite);
+ waterInfiniteRequiredSources = getInt("blocks.water.infinite-required-sources", waterInfiniteRequiredSources);
+ }
+
public boolean signAllowColors = false;
public boolean signRightClickEdit = false;
private void signSettings() {

View File

@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 2 Jan 2020 11:31:36 -0600
Subject: [PATCH] Make lava flow speed configurable
diff --git a/src/main/java/net/minecraft/world/level/material/LavaFluid.java b/src/main/java/net/minecraft/world/level/material/LavaFluid.java
index cd1a33a1f10d04a91358f51d736bda34110324c4..b0d671ba015d1ad37fdf600b8e70def2d7a0fa2e 100644
--- a/src/main/java/net/minecraft/world/level/material/LavaFluid.java
+++ b/src/main/java/net/minecraft/world/level/material/LavaFluid.java
@@ -181,7 +181,7 @@ public abstract class LavaFluid extends FlowingFluid {
@Override
public int getTickDelay(LevelReader world) {
- return world.dimensionType().ultraWarm() ? 10 : 30;
+ return world.dimensionType().ultraWarm() ? world.getWorldBorder().world.purpurConfig.lavaSpeedNether : world.getWorldBorder().world.purpurConfig.lavaSpeedNotNether; // Purpur
}
@Override
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 078899d049fc0cc9b8823764dd2a3cf57b60ed40..41550ce0b5577ae80761732144e908325bb04695 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -231,9 +231,13 @@ public class PurpurWorldConfig {
public boolean lavaInfinite = false;
public int lavaInfiniteRequiredSources = 2;
+ public int lavaSpeedNether = 10;
+ public int lavaSpeedNotNether = 30;
private void lavaSettings() {
lavaInfinite = getBoolean("blocks.lava.infinite-source", lavaInfinite);
lavaInfiniteRequiredSources = getInt("blocks.lava.infinite-required-sources", lavaInfiniteRequiredSources);
+ lavaSpeedNether = getInt("blocks.lava.speed.nether", lavaSpeedNether);
+ lavaSpeedNotNether = getInt("blocks.lava.speed.not-nether", lavaSpeedNotNether);
}
public boolean waterInfinite = true;

View File

@@ -0,0 +1,54 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 26 Dec 2019 22:08:37 -0600
Subject: [PATCH] Add player death exp control options
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index 3d66d2e86cef17bcd8813d4c2b29078beebf23fe..f991ed65d27d15a6eb32533f32da0bb9b69f331d 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -1907,9 +1907,18 @@ public abstract class Player extends LivingEntity {
@Override
protected int getExperienceReward(Player player) {
if (!this.level.getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) && !this.isSpectator()) {
- int i = this.experienceLevel * 7;
-
- return i > 100 ? 100 : i;
+ // Purpur start
+ int toDrop;
+ try {
+ scriptEngine.eval("expLevel = " + experienceLevel);
+ scriptEngine.eval("expTotal = " + totalExperience);
+ scriptEngine.eval("exp = " + experienceProgress);
+ toDrop = (int) Math.round((Double) scriptEngine.eval(level.purpurConfig.playerDeathExpDropEquation));
+ } catch (Exception ignore) {
+ toDrop = experienceLevel * 7;
+ }
+ return Math.min(toDrop, level.purpurConfig.playerDeathExpDropMax);
+ // Purpur end
} else {
return 0;
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 41550ce0b5577ae80761732144e908325bb04695..61e417c7c3113ce2515da09761d977a4fc766e64 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -168,6 +168,8 @@ public class PurpurWorldConfig {
public boolean idleTimeoutTargetPlayer = true;
public int playerSpawnInvulnerableTicks = 60;
public boolean playerInvulnerableWhileAcceptingResourcePack = false;
+ public String playerDeathExpDropEquation = "expLevel * 7";
+ public int playerDeathExpDropMax = 100;
private void playerSettings() {
if (PurpurConfig.version < 19) {
boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer);
@@ -181,6 +183,8 @@ public class PurpurWorldConfig {
idleTimeoutTargetPlayer = getBoolean("gameplay-mechanics.player.idle-timeout.mobs-target", idleTimeoutTargetPlayer);
playerSpawnInvulnerableTicks = getInt("gameplay-mechanics.player.spawn-invulnerable-ticks", playerSpawnInvulnerableTicks);
playerInvulnerableWhileAcceptingResourcePack = getBoolean("gameplay-mechanics.player.invulnerable-while-accepting-resource-pack", playerInvulnerableWhileAcceptingResourcePack);
+ playerDeathExpDropEquation = getString("gameplay-mechanics.player.exp-dropped-on-death.equation", playerDeathExpDropEquation);
+ playerDeathExpDropMax = getInt("gameplay-mechanics.player.exp-dropped-on-death.maximum", playerDeathExpDropMax);
}
public boolean silkTouchEnabled = false;

View File

@@ -0,0 +1,51 @@
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
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 9080bac56a64cb13a316374798fb5c5298a2475b..5fb24a823e1aa5d761063f527736c68b7c373e15 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -773,7 +773,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
public void checkOutOfWorld() {
// Paper start - Configurable nether ceiling damage
- if (this.getY() < (double) (this.level.getMinBuildHeight() - 64) || (this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER
+ if (this.getY() < (double) (this.level.getMinBuildHeight() + level.purpurConfig.voidDamageHeight) || (this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER // Purpur
&& level.paperConfig.doNetherTopVoidDamage()
&& this.getY() >= this.level.paperConfig.netherVoidTopDamageHeight)) {
// Paper end
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 27a07aa2b1a85267b2012eb882acb36b04fded66..2553fe5fa89d353d4e41c04c178eb57174b2750a 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -2389,7 +2389,7 @@ public abstract class LivingEntity extends Entity {
@Override
protected void outOfWorld() {
- this.hurt(DamageSource.OUT_OF_WORLD, 4.0F);
+ this.hurt(DamageSource.OUT_OF_WORLD, (float) level.purpurConfig.voidDamageDealt); // Purpur
}
protected void updateSwingTime() {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 61e417c7c3113ce2515da09761d977a4fc766e64..c86f1d00b7ae613f2575a98ce6824c72c60c0f47 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -222,10 +222,14 @@ public class PurpurWorldConfig {
public boolean disableDropsOnCrammingDeath = false;
public boolean milkCuresBadOmen = true;
public double tridentLoyaltyVoidReturnHeight = 0.0D;
+ public double voidDamageHeight = -64.0D;
+ public double voidDamageDealt = 4.0D;
private void miscGameplayMechanicsSettings() {
disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath);
milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen);
tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight);
+ voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight);
+ voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt);
}
public boolean farmlandGetsMoistFromBelow = false;

View File

@@ -0,0 +1,80 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Tue, 18 Feb 2020 20:07:08 -0600
Subject: [PATCH] Add canSaveToDisk to Entity
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 5fb24a823e1aa5d761063f527736c68b7c373e15..87b9812c7c879403792c9a5a91366af7a63bc683 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -4316,5 +4316,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
public boolean processClick(InteractionHand hand) {
return false;
}
+
+ public boolean canSaveToDisk() {
+ return true;
+ }
// Purpur end
}
diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
index 8a4440f766ea39857c1f1ededeed18313e0f38cb..43de1fa753e54ae09d43a9aef8dda22c27c67b81 100644
--- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
@@ -192,6 +192,11 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob
// do not hit rider
return target != rider && super.canHitEntity(target);
}
+
+ @Override
+ public boolean canSaveToDisk() {
+ return false;
+ }
};
skull.setPosRaw(headX, headY, headZ);
level.addFreshEntity(skull);
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java
index 1c77959518039e4b4fb2ffa8b93f5f69e8587ade..ea27bf92ff04155990871109ebf1f5b9d3796f28 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java
@@ -109,6 +109,7 @@ public class EntityStorage implements EntityPersistentStorage<Entity> {
final java.util.Map<net.minecraft.world.entity.EntityType<?>, Integer> savedEntityCounts = new java.util.HashMap<>(); // Paper
dataList.getEntities().forEach((entity) -> {
+ if (!entity.canSaveToDisk()) return; // Purpur
// Paper start
final EntityType<?> entityType = entity.getType();
final int saveLimit = this.level.paperConfig.entityPerChunkSaveLimits.getOrDefault(entityType, -1);
diff --git a/src/main/java/net/pl3x/purpur/entity/DolphinSpit.java b/src/main/java/net/pl3x/purpur/entity/DolphinSpit.java
index fda24d4ecff91cc28d2a7a45fbb55ea734261153..3cabafb00c293cbbcc60a0cc98479c2d62ddaa2d 100644
--- a/src/main/java/net/pl3x/purpur/entity/DolphinSpit.java
+++ b/src/main/java/net/pl3x/purpur/entity/DolphinSpit.java
@@ -35,6 +35,11 @@ public class DolphinSpit extends LlamaSpit {
dolphin.getZ() + (double) (dolphin.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(dolphin.yBodyRot * 0.017453292F));
}
+ @Override
+ public boolean canSaveToDisk() {
+ return false;
+ }
+
public void tick() {
super_tick();
diff --git a/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java b/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java
index b196bee2ea6e67897b367d2be1800f16a89a6167..d8a9f3296c46f12e156f1611811cb55470703b03 100644
--- a/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java
+++ b/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java
@@ -38,6 +38,11 @@ public class PhantomFlames extends LlamaSpit {
phantom.getZ() + (double) (phantom.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(phantom.yBodyRot * 0.017453292F));
}
+ @Override
+ public boolean canSaveToDisk() {
+ return false;
+ }
+
public void tick() {
super_tick();

View File

@@ -0,0 +1,60 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sun, 25 Aug 2019 00:09:52 -0500
Subject: [PATCH] Dispenser curse of binding protection
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index 91960c5777fc026053cde1b7487a82d407b69369..7be2798a1b190b44445e3abd55c0598e3432bf27 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -62,6 +62,7 @@ import net.minecraft.world.item.ProjectileWeaponItem;
import net.minecraft.world.item.SpawnEggItem;
import net.minecraft.world.item.SwordItem;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
+import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.ItemLike;
@@ -1075,6 +1076,12 @@ public abstract class Mob extends LivingEntity {
}
+ // Purpur start
+ public static @Nullable EquipmentSlot getSlotForDispenser(ItemStack itemstack) {
+ return EnchantmentHelper.getItemEnchantmentLevel(Enchantments.BINDING_CURSE, itemstack) > 0 ? null : getEquipmentSlotForItem(itemstack);
+ }
+ // Purpur end
+
@Nullable
public static Item getEquipmentForSlot(EquipmentSlot equipmentSlot, int equipmentLevel) {
switch (equipmentSlot) {
diff --git a/src/main/java/net/minecraft/world/item/ArmorItem.java b/src/main/java/net/minecraft/world/item/ArmorItem.java
index e566a6ee8eda9d6e9bc7b0ce153d016ddc0b2797..043ea496bd04bbf4571ec9d16e5362257b3658c8 100644
--- a/src/main/java/net/minecraft/world/item/ArmorItem.java
+++ b/src/main/java/net/minecraft/world/item/ArmorItem.java
@@ -56,7 +56,7 @@ public class ArmorItem extends Item implements Wearable {
return false;
} else {
LivingEntity entityliving = (LivingEntity) list.get(0);
- EquipmentSlot enumitemslot = Mob.getEquipmentSlotForItem(armor);
+ EquipmentSlot enumitemslot = pointer.getLevel().purpurConfig.dispenserApplyCursedArmor ? Mob.getEquipmentSlotForItem(armor) : Mob.getSlotForDispenser(armor); if (enumitemslot == null) return false; // Purpur
ItemStack itemstack1 = armor.split(1);
// CraftBukkit start
Level world = pointer.getLevel();
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index c86f1d00b7ae613f2575a98ce6824c72c60c0f47..573904ac2403496c31af399b3f3bbb61d43e7a08 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -232,6 +232,11 @@ public class PurpurWorldConfig {
voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt);
}
+ public boolean dispenserApplyCursedArmor = true;
+ private void dispenserSettings() {
+ dispenserApplyCursedArmor = getBoolean("blocks.dispenser.apply-cursed-to-armor-slots", dispenserApplyCursedArmor);
+ }
+
public boolean farmlandGetsMoistFromBelow = false;
private void farmlandSettings() {
farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow);

View File

@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 7 Sep 2019 22:47:59 -0500
Subject: [PATCH] Add option for boats to eject players on land
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java
index 391454a58d18d7373b974e094fd62514ca0d0b6b..6acd2dc6ec9c3761fa330c74df8c7e7b19266f8e 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java
@@ -520,6 +520,7 @@ public class Boat extends Entity {
if (f > 0.0F) {
this.landFriction = f;
+ if (level.purpurConfig.boatEjectPlayersOnLand) ejectPassengers(); // Purpur
return Boat.Status.ON_LAND;
} else {
return Boat.Status.IN_AIR;
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 573904ac2403496c31af399b3f3bbb61d43e7a08..4894b0654a81950ec926e448757a2fb379f70daa 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -219,12 +219,14 @@ public class PurpurWorldConfig {
});
}
+ public boolean boatEjectPlayersOnLand = false;
public boolean disableDropsOnCrammingDeath = false;
public boolean milkCuresBadOmen = true;
public double tridentLoyaltyVoidReturnHeight = 0.0D;
public double voidDamageHeight = -64.0D;
public double voidDamageDealt = 4.0D;
private void miscGameplayMechanicsSettings() {
+ boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand);
disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath);
milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen);
tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight);

View File

@@ -0,0 +1,94 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sun, 14 Jul 2019 19:52:47 -0500
Subject: [PATCH] Mending mends most damages equipment first
diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
index ec7d011fa5df0b4775bedc01632ba549d3803693..bc2000c27395618d1816719a862aa9829128d863 100644
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
@@ -319,7 +319,7 @@ public class ExperienceOrb extends Entity {
}
private int repairPlayerItems(Player player, int amount) {
- Entry<EquipmentSlot, ItemStack> entry = EnchantmentHelper.getRandomItemWith(Enchantments.MENDING, (LivingEntity) player, ItemStack::isDamaged);
+ Entry<EquipmentSlot, ItemStack> entry = level.purpurConfig.useBetterMending ? EnchantmentHelper.getMostDamagedEquipment(Enchantments.MENDING, player) : EnchantmentHelper.getRandomItemWith(Enchantments.MENDING, (LivingEntity) player, ItemStack::isDamaged); // Purpur
if (entry != null) {
ItemStack itemstack = (ItemStack) entry.getValue();
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 7695a5ec88023720d873f81fc36f78ad60fb9589..47b8b3df98eb775f7e642924fd36005d542a10c6 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -513,6 +513,16 @@ public final class ItemStack {
return this.isDamageableItem() && this.getDamageValue() > 0;
}
+ // Purpur start
+ public float getDamagePercent() {
+ if (isDamaged()) {
+ return (float) getDamageValue() / (float) getItem().getMaxDamage();
+ } else {
+ return 0F;
+ }
+ }
+ // Purpur end
+
public int getDamageValue() {
return this.tag == null ? 0 : this.tag.getInt("Damage");
}
diff --git a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java
index d439e8ce87bf7da03683a336941c7673b8b166e4..955e482e4bc83f2b777cd2e4254c40beef08853b 100644
--- a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java
+++ b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java
@@ -270,6 +270,29 @@ public class EnchantmentHelper {
return getItemEnchantmentLevel(Enchantments.CHANNELING, stack) > 0;
}
+ // Purpur start
+ @Nullable
+ public static Entry<EquipmentSlot, ItemStack> getMostDamagedEquipment(Enchantment enchantment, LivingEntity entity) {
+ Map<EquipmentSlot, ItemStack> map = enchantment.getSlotItems(entity);
+ if (map.isEmpty()) {
+ return null;
+ }
+ Entry<EquipmentSlot, ItemStack> item = null;
+ float maxPercent = 0F;
+ for (Entry<EquipmentSlot, ItemStack> entry : map.entrySet()) {
+ ItemStack itemstack = entry.getValue();
+ if (!itemstack.isEmpty() && itemstack.isDamaged() && getItemEnchantmentLevel(enchantment, itemstack) > 0) {
+ float percent = itemstack.getDamagePercent();
+ if (item == null || percent > maxPercent) {
+ item = entry;
+ maxPercent = percent;
+ }
+ }
+ }
+ return item;
+ }
+ // Purpur end
+
@Deprecated public static @javax.annotation.Nonnull ItemStack getRandomEquippedItemWithEnchant(Enchantment enchantment, LivingEntity entityliving) {
Entry<EquipmentSlot, ItemStack> entry = getRandomItemWith(enchantment, entityliving);
return entry != null ? entry.getValue() : ItemStack.EMPTY;
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 4894b0654a81950ec926e448757a2fb379f70daa..42e4c17030054fa75619c3db7c5f4db113b8f6e8 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -219,6 +219,7 @@ public class PurpurWorldConfig {
});
}
+ public boolean useBetterMending = false;
public boolean boatEjectPlayersOnLand = false;
public boolean disableDropsOnCrammingDeath = false;
public boolean milkCuresBadOmen = true;
@@ -226,6 +227,7 @@ public class PurpurWorldConfig {
public double voidDamageHeight = -64.0D;
public double voidDamageDealt = 4.0D;
private void miscGameplayMechanicsSettings() {
+ useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending);
boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand);
disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath);
milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen);

View File

@@ -0,0 +1,95 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sun, 28 Jul 2019 01:27:37 -0500
Subject: [PATCH] Add 5 second tps average in /tps
diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
index fa56cd09102a89692b42f1d14257990508c5c720..f9251183df72ddc56662fd3f02acf21641a2200c 100644
--- a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
+++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
@@ -58,7 +58,7 @@ public class RAMDetails extends JList<String> {
GraphData data = RAMGraph.DATA.peekLast();
Vector<String> vector = new Vector<>();
- double[] tps = new double[] {server.tps1.getAverage(), server.tps5.getAverage(), server.tps15.getAverage()};
+ double[] tps = new double[] {server.tps5s.getAverage(), server.tps1.getAverage(), server.tps5.getAverage(), server.tps15.getAverage()}; // Purpur
String[] tpsAvg = new String[tps.length];
for ( int g = 0; g < tps.length; g++) {
@@ -67,7 +67,7 @@ public class RAMDetails extends JList<String> {
vector.add("Memory use: " + (data.getUsedMem() / 1024L / 1024L) + " mb (" + (data.getFree() * 100L / data.getMax()) + "% free)");
vector.add("Heap: " + (data.getTotal() / 1024L / 1024L) + " / " + (data.getMax() / 1024L / 1024L) + " mb");
vector.add("Avg tick: " + DECIMAL_FORMAT.format(getAverage(server.tickTimes)) + " ms");
- vector.add("TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg));
+ vector.add("TPS from last 5s, 1m, 5m, 15m: " + String.join(", ", tpsAvg)); // Purpur
setListData(vector);
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index d894903c3f5c8b12b759896d8dd315a0f4c69d19..688a80485ae28361b993a4de4019ae9794989982 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -305,7 +305,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public static final int TPS = 20;
public static final int TICK_TIME = 1000000000 / MinecraftServer.TPS;
private static final int SAMPLE_INTERVAL = 20; // Paper
- public final double[] recentTps = new double[ 3 ];
+ public final double[] recentTps = new double[ 4 ]; // Purpur
public boolean lagging = false; // Purpur
public final SlackActivityAccountant slackActivityAccountant = new SlackActivityAccountant();
// Spigot end
@@ -1168,6 +1168,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
private static final long MAX_CATCHUP_BUFFER = TICK_TIME * TPS * 60L;
private long lastTick = 0;
private long catchupTime = 0;
+ public final RollingAverage tps5s = new RollingAverage(5); // Purpur
public final RollingAverage tps1 = new RollingAverage(60);
public final RollingAverage tps5 = new RollingAverage(60 * 5);
public final RollingAverage tps15 = new RollingAverage(60 * 15);
@@ -1258,13 +1259,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
{
final long diff = curTime - tickSection;
java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP);
+ tps5s.add(currentTps, diff); // Purpur
tps1.add(currentTps, diff);
tps5.add(currentTps, diff);
tps15.add(currentTps, diff);
// Backwards compat with bad plugins
- this.recentTps[0] = tps1.getAverage();
- this.recentTps[1] = tps5.getAverage();
- this.recentTps[2] = tps15.getAverage();
+ // Purpur start
+ this.recentTps[0] = tps5s.getAverage();
+ this.recentTps[1] = tps1.getAverage();
+ this.recentTps[2] = tps5.getAverage();
+ this.recentTps[3] = tps15.getAverage();
+ // Purpur end
// Paper end
lagging = recentTps[0] < net.pl3x.purpur.PurpurConfig.laggingThreshold; // Purpur
tickSection = curTime;
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 895799585e1a6964b709094d4aa4dfe8fe6470d4..d6c1c46e56ad39ec7fde5448120c8750d3ce3fa5 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2523,6 +2523,7 @@ public final class CraftServer implements Server {
@Override
public double[] getTPS() {
return new double[] {
+ net.minecraft.server.MinecraftServer.getServer().tps5s.getAverage(), // Purpur
net.minecraft.server.MinecraftServer.getServer().tps1.getAverage(),
net.minecraft.server.MinecraftServer.getServer().tps5.getAverage(),
net.minecraft.server.MinecraftServer.getServer().tps15.getAverage()
diff --git a/src/main/java/org/spigotmc/TicksPerSecondCommand.java b/src/main/java/org/spigotmc/TicksPerSecondCommand.java
index 9bede6a26c08ede063c7a38f1149c811df14b258..088239d17aa8178cf8af09ec23cfd4deaaf2bbb6 100644
--- a/src/main/java/org/spigotmc/TicksPerSecondCommand.java
+++ b/src/main/java/org/spigotmc/TicksPerSecondCommand.java
@@ -31,7 +31,7 @@ public class TicksPerSecondCommand extends Command
for ( int i = 0; i < tps.length; i++) {
tpsAvg[i] = TicksPerSecondCommand.format( tps[i] );
}
- sender.sendMessage(ChatColor.GOLD + "TPS from last 1m, 5m, 15m: " + org.apache.commons.lang.StringUtils.join(tpsAvg, ", "));
+ sender.sendMessage(ChatColor.GOLD + "TPS from last 5s, 1m, 5m, 15m: " + org.apache.commons.lang.StringUtils.join(tpsAvg, ", ")); // Purpur
if (args.length > 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) {
sender.sendMessage(ChatColor.GOLD + "Current Memory Usage: " + ChatColor.GREEN + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)");
if (!hasShownMemoryWarning) {

View File

@@ -0,0 +1,124 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 25 Jul 2019 18:07:37 -0500
Subject: [PATCH] Implement elytra settings
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 2553fe5fa89d353d4e41c04c178eb57174b2750a..71ef80e636ac7c208b362410eaaffa497dd9ceca 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3297,7 +3297,16 @@ public abstract class LivingEntity extends Entity {
int j = i / 10;
if (j % 2 == 0) {
- itemstack.hurtAndBreak(1, this, (entityliving) -> {
+ // Purpur start
+ int damage = level.purpurConfig.elytraDamagePerSecond;
+ if (level.purpurConfig.elytraDamageMultiplyBySpeed > 0) {
+ double speed = getDeltaMovement().lengthSqr();
+ if (speed > level.purpurConfig.elytraDamageMultiplyBySpeed) {
+ damage *= (int) speed;
+ }
+ }
+ itemstack.hurtAndBreak(damage, this, (entityliving) -> {
+ // Purpur end
entityliving.broadcastBreakEvent(EquipmentSlot.CHEST);
});
}
diff --git a/src/main/java/net/minecraft/world/item/FireworkRocketItem.java b/src/main/java/net/minecraft/world/item/FireworkRocketItem.java
index 543a08f920319a2547258640bafebb1e70af65c4..dd211aa7c4ef1e158933a89898b9e5bc1451ee14 100644
--- a/src/main/java/net/minecraft/world/item/FireworkRocketItem.java
+++ b/src/main/java/net/minecraft/world/item/FireworkRocketItem.java
@@ -17,6 +17,7 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
+import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
import net.minecraft.world.item.context.UseOnContext;
@@ -70,6 +71,14 @@ public class FireworkRocketItem extends Item {
com.destroystokyo.paper.event.player.PlayerElytraBoostEvent event = new com.destroystokyo.paper.event.player.PlayerElytraBoostEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Firework) fireworkRocketEntity.getBukkitEntity());
if (event.callEvent() && world.addFreshEntity(fireworkRocketEntity)) {
user.awardStat(Stats.ITEM_USED.get(this));
+ // Purpur start
+ if (world.purpurConfig.elytraDamagePerFireworkBoost > 0) {
+ ItemStack chestItem = user.getItemBySlot(EquipmentSlot.CHEST);
+ if (chestItem.getItem() == Items.ELYTRA) {
+ chestItem.hurtAndBreak(world.purpurConfig.elytraDamagePerFireworkBoost, user, (entityliving) -> entityliving.broadcastBreakEvent(EquipmentSlot.CHEST));
+ }
+ }
+ // Purpur end
if (event.shouldConsume() && !user.getAbilities().instabuild) {
itemStack.shrink(1);
} else ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 47b8b3df98eb775f7e642924fd36005d542a10c6..3bd63474205bf7982af291d973a2a71a8490f20b 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -542,7 +542,7 @@ public final class ItemStack {
int j;
if (amount > 0) {
- j = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.UNBREAKING, this);
+ j = (getItem() == Items.ELYTRA && player != null && player.level.purpurConfig.elytraIgnoreUnbreaking) ? 0 : EnchantmentHelper.getItemEnchantmentLevel(Enchantments.UNBREAKING, this);
int k = 0;
for (int l = 0; j > 0 && l < amount; ++l) {
@@ -596,6 +596,12 @@ public final class ItemStack {
if (this.hurt(amount, entity.getRandom(), entity /*instanceof ServerPlayer ? (ServerPlayer) entity : null*/)) { // Paper - pass LivingEntity for EntityItemDamageEvent
breakCallback.accept(entity);
Item item = this.getItem();
+ // Purpur start
+ if (item == Items.ELYTRA) {
+ setDamageValue(item.getMaxDamage() - 1);
+ return;
+ }
+ // Purpur end
// CraftBukkit start - Check for item breaking
if (this.count == 1 && entity instanceof net.minecraft.world.entity.player.Player) {
org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent((net.minecraft.world.entity.player.Player) entity, this);
diff --git a/src/main/java/net/minecraft/world/item/TridentItem.java b/src/main/java/net/minecraft/world/item/TridentItem.java
index 510ed67a7de2b503ab8b01db57ed09ee33b0d825..3f53dc8f250ad3f7616ce7ef0a2353caa0ab1879 100644
--- a/src/main/java/net/minecraft/world/item/TridentItem.java
+++ b/src/main/java/net/minecraft/world/item/TridentItem.java
@@ -126,6 +126,14 @@ public class TridentItem extends Item implements Vanishable {
f2 *= f6 / f5;
f3 *= f6 / f5;
f4 *= f6 / f5;
+
+ // Purpur start
+ ItemStack chestItem = entityhuman.getItemBySlot(EquipmentSlot.CHEST);
+ if (chestItem.getItem() == Items.ELYTRA && world.purpurConfig.elytraDamagePerTridentBoost > 0) {
+ chestItem.hurtAndBreak(world.purpurConfig.elytraDamagePerTridentBoost, entityhuman, (entity) -> entity.broadcastBreakEvent(EquipmentSlot.CHEST));
+ }
+ // Purpur end
+
entityhuman.push((double) f2, (double) f3, (double) f4);
entityhuman.startAutoSpinAttack(20);
if (entityhuman.isOnGround()) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 42e4c17030054fa75619c3db7c5f4db113b8f6e8..c80a13bce7998f8dbcd1684724bb5aa4b07d9479 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -99,6 +99,19 @@ public class PurpurWorldConfig {
armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight);
}
+ public int elytraDamagePerSecond = 1;
+ public double elytraDamageMultiplyBySpeed = 0;
+ public boolean elytraIgnoreUnbreaking = false;
+ public int elytraDamagePerFireworkBoost = 0;
+ public int elytraDamagePerTridentBoost = 0;
+ private void elytraSettings() {
+ elytraDamagePerSecond = getInt("gameplay-mechanics.elytra.damage-per-second", elytraDamagePerSecond);
+ elytraDamageMultiplyBySpeed = getDouble("gameplay-mechanics.elytra.damage-multiplied-by-speed", elytraDamageMultiplyBySpeed);
+ elytraIgnoreUnbreaking = getBoolean("gameplay-mechanics.elytra.ignore-unbreaking", elytraIgnoreUnbreaking);
+ elytraDamagePerFireworkBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.firework", elytraDamagePerFireworkBoost);
+ elytraDamagePerTridentBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.trident", elytraDamagePerTridentBoost);
+ }
+
public double minecartMaxSpeed = 0.4D;
public boolean minecartPlaceAnywhere = false;
public boolean minecartControllable = false;

View File

@@ -0,0 +1,202 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 22 Feb 2020 15:54:08 -0600
Subject: [PATCH] Item entity immunities
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 7bb12a30d8b4a817f5a85969c6200306fd45a43d..cf94a78d15873f851bf7d79d8e846c66cf45d646 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -2283,7 +2283,7 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
public class TrackedEntity {
- final ServerEntity serverEntity;
+ public final ServerEntity serverEntity; // Purpur -> package -> public
final Entity entity;
private final int range;
SectionPos lastSectionPos;
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index e158c9bf0fb527105da9dc3f28d88e0ba7337e65..47f5c6726e620072d76f1fa028d7ae51f79cccfb 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -68,7 +68,7 @@ public class ServerEntity {
private boolean wasRiding;
private boolean wasOnGround;
// CraftBukkit start
- final Set<ServerPlayerConnection> trackedPlayers; // Paper - private -> package
+ public final Set<ServerPlayerConnection> trackedPlayers; // Paper - private -> package // Purpur - package -> public
public ServerEntity(ServerLevel worldserver, Entity entity, int i, boolean flag, Consumer<Packet<?>> consumer, Set<ServerPlayerConnection> trackedPlayers) {
this.trackedPlayers = trackedPlayers;
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
index 063f3e4c67e6716c9a03dbe4b72eafd32e4f0d53..f3e642e27dc1e122199088dd1e4b3de5fa13180d 100644
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
@@ -53,6 +53,12 @@ public class ItemEntity extends Entity {
public final float bobOffs;
private int lastTick = MinecraftServer.currentTick - 1; // CraftBukkit
public boolean canMobPickup = true; // Paper
+ // Purpur start
+ public boolean immuneToCactus = false;
+ public boolean immuneToExplosion = false;
+ public boolean immuneToFire = false;
+ public boolean immuneToLightning = false;
+ // Purpur end
public ItemEntity(EntityType<? extends ItemEntity> type, Level world) {
super(type, world);
@@ -322,6 +328,16 @@ public class ItemEntity extends Entity {
return false;
} else if (!this.getItem().getItem().canBeHurtBy(source)) {
return false;
+ // Purpur start
+ } else if (
+ (immuneToCactus && source == DamageSource.CACTUS) ||
+ (immuneToFire && (source.isFire() || source == DamageSource.IN_FIRE)) ||
+ (immuneToLightning && source == DamageSource.LIGHTNING_BOLT) ||
+ (immuneToExplosion && source.isExplosion())
+ ) {
+ respawnOnClient();
+ return false;
+ // Purpur end
} else {
// CraftBukkit start
if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, amount)) {
@@ -504,6 +520,12 @@ public class ItemEntity extends Entity {
com.google.common.base.Preconditions.checkArgument(!stack.isEmpty(), "Cannot drop air"); // CraftBukkit
this.getEntityData().set(ItemEntity.DATA_ITEM, stack);
this.getEntityData().markDirty(ItemEntity.DATA_ITEM); // CraftBukkit - SPIGOT-4591, must mark dirty
+ // Purpur start
+ if (level.purpurConfig.itemImmuneToCactus.contains(stack.getItem())) immuneToCactus = true;
+ if (level.purpurConfig.itemImmuneToExplosion.contains(stack.getItem())) immuneToExplosion = true;
+ if (level.purpurConfig.itemImmuneToFire.contains(stack.getItem())) immuneToFire = true;
+ if (level.purpurConfig.itemImmuneToLightning.contains(stack.getItem())) immuneToLightning = true;
+ // level end
}
@Override
@@ -594,4 +616,17 @@ public class ItemEntity extends Entity {
public SoundSource getSoundSource() {
return SoundSource.AMBIENT;
}
+
+ // Purpur start
+ public void respawnOnClient() {
+ Packet<?> spawnPacket = new ClientboundAddEntityPacket(this);
+ Packet<?> metadataPacket = new net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket(getId(), getEntityData(), true);
+ for (net.minecraft.server.network.ServerPlayerConnection connection : this.tracker.serverEntity.trackedPlayers) {
+ if (!connection.getPlayer().purpurClient) {
+ connection.send(spawnPacket);
+ connection.send(metadataPacket);
+ }
+ }
+ }
+ // Purpur end
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index c80a13bce7998f8dbcd1684724bb5aa4b07d9479..3d88ccc1ff7c87815bac2e9f573333e63caea223 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -112,6 +112,49 @@ public class PurpurWorldConfig {
elytraDamagePerTridentBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.trident", elytraDamagePerTridentBoost);
}
+ public List<Item> itemImmuneToCactus = new ArrayList<>();
+ public List<Item> itemImmuneToExplosion = new ArrayList<>();
+ public List<Item> itemImmuneToFire = new ArrayList<>();
+ public List<Item> itemImmuneToLightning = new ArrayList<>();
+ private void itemSettings() {
+ itemImmuneToCactus.clear();
+ getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> {
+ if (key.toString().equals("*")) {
+ Registry.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToCactus.add(item));
+ return;
+ }
+ Item item = Registry.ITEM.get(new ResourceLocation(key.toString()));
+ if (item != Items.AIR) itemImmuneToCactus.add(item);
+ });
+ itemImmuneToExplosion.clear();
+ getList("gameplay-mechanics.item.immune.explosion", new ArrayList<>()).forEach(key -> {
+ if (key.toString().equals("*")) {
+ Registry.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToExplosion.add(item));
+ return;
+ }
+ Item item = Registry.ITEM.get(new ResourceLocation(key.toString()));
+ if (item != Items.AIR) itemImmuneToExplosion.add(item);
+ });
+ itemImmuneToFire.clear();
+ getList("gameplay-mechanics.item.immune.fire", new ArrayList<>()).forEach(key -> {
+ if (key.toString().equals("*")) {
+ Registry.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToFire.add(item));
+ return;
+ }
+ Item item = Registry.ITEM.get(new ResourceLocation(key.toString()));
+ if (item != Items.AIR) itemImmuneToFire.add(item);
+ });
+ itemImmuneToLightning.clear();
+ getList("gameplay-mechanics.item.immune.lightning", new ArrayList<>()).forEach(key -> {
+ if (key.toString().equals("*")) {
+ Registry.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToLightning.add(item));
+ return;
+ }
+ Item item = Registry.ITEM.get(new ResourceLocation(key.toString()));
+ if (item != Items.AIR) itemImmuneToLightning.add(item);
+ });
+ }
+
public double minecartMaxSpeed = 0.4D;
public boolean minecartPlaceAnywhere = false;
public boolean minecartControllable = false;
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
index 342345eb04d00efb58392ccf209e3c51c1064173..5f5c37fb447a4c1790714158f4b41f15793002d1 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
@@ -116,4 +116,46 @@ public class CraftItem extends CraftEntity implements Item {
public EntityType getType() {
return EntityType.DROPPED_ITEM;
}
+
+ // Purpur start
+ @Override
+ public void setImmuneToCactus(boolean immuneToCactus) {
+ item.immuneToCactus = immuneToCactus;
+ }
+
+ @Override
+ public boolean isImmuneToCactus() {
+ return item.immuneToCactus;
+ }
+
+ @Override
+ public void setImmuneToExplosion(boolean immuneToExplosion) {
+ item.immuneToExplosion = immuneToExplosion;
+ }
+
+ @Override
+ public boolean isImmuneToExplosion() {
+ return item.immuneToExplosion;
+ }
+
+ @Override
+ public void setImmuneToFire(boolean immuneToFire) {
+ item.immuneToFire = immuneToFire;
+ }
+
+ @Override
+ public boolean isImmuneToFire() {
+ return item.immuneToFire;
+ }
+
+ @Override
+ public void setImmuneToLightning(boolean immuneToLightning) {
+ item.immuneToLightning = immuneToLightning;
+ }
+
+ @Override
+ public boolean isImmuneToLightning() {
+ return item.immuneToLightning;
+ }
+ // Purpur end
}

View File

@@ -0,0 +1,75 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 13 Mar 2020 22:29:10 -0500
Subject: [PATCH] Add ping command
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
index dc0d785432b8e511a738bebb5c7335432b69427f..47ee3e70021ce17beea4ee6ac967c3180045b804 100644
--- a/src/main/java/net/minecraft/commands/Commands.java
+++ b/src/main/java/net/minecraft/commands/Commands.java
@@ -198,6 +198,7 @@ public class Commands {
SetPlayerIdleTimeoutCommand.register(this.dispatcher);
StopCommand.register(this.dispatcher);
WhitelistCommand.register(this.dispatcher);
+ net.pl3x.purpur.command.PingCommand.register(this.dispatcher); // Purpur
}
if (environment.includeIntegrated) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index c27088998dca02124c0381dd4166d63e75a634f6..10a3bcd31f6cd2ec27c79c622fecc4a24fda9f17 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -162,12 +162,14 @@ public class PurpurConfig {
public static String afkBroadcastBack = "<yellow><italic>%s is no longer AFK";
public static String afkTabListPrefix = "[AFK] ";
public static String afkTabListSuffix = "";
+ public static String pingCommandOutput = "<green>%s's ping is %sms";
private static void messages() {
cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob);
afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway);
afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack);
afkTabListPrefix = getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix);
afkTabListSuffix = getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix);
+ pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput);
}
public static String serverModName = "Purpur";
diff --git a/src/main/java/net/pl3x/purpur/command/PingCommand.java b/src/main/java/net/pl3x/purpur/command/PingCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..6de4f71aa5d501f3f5da93cd631da654a6e264e0
--- /dev/null
+++ b/src/main/java/net/pl3x/purpur/command/PingCommand.java
@@ -0,0 +1,32 @@
+package net.pl3x.purpur.command;
+
+import com.mojang.brigadier.CommandDispatcher;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.commands.Commands;
+import net.minecraft.commands.arguments.EntityArgument;
+import net.minecraft.server.level.ServerPlayer;
+import net.pl3x.purpur.PurpurConfig;
+import org.bukkit.craftbukkit.util.CraftChatMessage;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public class PingCommand {
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
+ dispatcher.register(Commands.literal("ping")
+ .requires((listener) -> listener.hasPermission(2))
+ .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException())))
+ .then(Commands.argument("targets", EntityArgument.players())
+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets")))
+ )
+ ).setPermission("bukkit.command.ping");
+ }
+
+ private static int execute(CommandSourceStack sender, Collection<ServerPlayer> targets) {
+ for (ServerPlayer player : targets) {
+ String output = String.format(PurpurConfig.pingCommandOutput, player.getGameProfile().getName(), player.latency);
+ sender.sendSuccess(output, false);
+ }
+ return targets.size();
+ }
+}

View File

@@ -0,0 +1,78 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Mon, 30 Nov 2020 03:12:04 -0600
Subject: [PATCH] Add demo command
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
index 47ee3e70021ce17beea4ee6ac967c3180045b804..376768b272f70d1eb45d483c51dec22d91c9d325 100644
--- a/src/main/java/net/minecraft/commands/Commands.java
+++ b/src/main/java/net/minecraft/commands/Commands.java
@@ -198,6 +198,7 @@ public class Commands {
SetPlayerIdleTimeoutCommand.register(this.dispatcher);
StopCommand.register(this.dispatcher);
WhitelistCommand.register(this.dispatcher);
+ net.pl3x.purpur.command.DemoCommand.register(this.dispatcher); // Purpur
net.pl3x.purpur.command.PingCommand.register(this.dispatcher); // Purpur
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index 10a3bcd31f6cd2ec27c79c622fecc4a24fda9f17..196f57d3c7f1b9e57122c42c73de7157da477246 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -162,6 +162,7 @@ public class PurpurConfig {
public static String afkBroadcastBack = "<yellow><italic>%s is no longer AFK";
public static String afkTabListPrefix = "[AFK] ";
public static String afkTabListSuffix = "";
+ public static String demoCommandOutput = "<green>%s has been shown the demo screen";
public static String pingCommandOutput = "<green>%s's ping is %sms";
private static void messages() {
cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob);
@@ -169,6 +170,7 @@ public class PurpurConfig {
afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack);
afkTabListPrefix = getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix);
afkTabListSuffix = getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix);
+ demoCommandOutput = getString("settings.messages.demo-command-output", demoCommandOutput);
pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput);
}
diff --git a/src/main/java/net/pl3x/purpur/command/DemoCommand.java b/src/main/java/net/pl3x/purpur/command/DemoCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..63686e55d169a81c0c225f8dfb47973075c1e491
--- /dev/null
+++ b/src/main/java/net/pl3x/purpur/command/DemoCommand.java
@@ -0,0 +1,34 @@
+package net.pl3x.purpur.command;
+
+import com.mojang.brigadier.CommandDispatcher;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.commands.Commands;
+import net.minecraft.commands.arguments.EntityArgument;
+import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
+import net.minecraft.server.level.ServerPlayer;
+import net.pl3x.purpur.PurpurConfig;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public class DemoCommand {
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
+ dispatcher.register(Commands.literal("demo")
+ .requires((listener) -> listener.hasPermission(2))
+ .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException())))
+ .then(Commands.argument("targets", EntityArgument.players())
+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets")))
+ )
+ ).setPermission("bukkit.command.demo");
+ }
+
+ private static int execute(CommandSourceStack sender, Collection<ServerPlayer> targets) {
+ for (ServerPlayer player : targets) {
+ ClientboundGameEventPacket packet = new ClientboundGameEventPacket(ClientboundGameEventPacket.DEMO_EVENT, 0);
+ player.connection.send(packet);
+ String output = String.format(PurpurConfig.demoCommandOutput, player.getGameProfile().getName());
+ sender.sendSuccess(output, false);
+ }
+ return targets.size();
+ }
+}

View File

@@ -0,0 +1,79 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Encode42 <me@encode42.dev>
Date: Fri, 30 Apr 2021 14:03:06 -0400
Subject: [PATCH] Add credits command
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
index 376768b272f70d1eb45d483c51dec22d91c9d325..4308cf798c7f97532ee56369a11afe4dbf7a898f 100644
--- a/src/main/java/net/minecraft/commands/Commands.java
+++ b/src/main/java/net/minecraft/commands/Commands.java
@@ -198,6 +198,7 @@ public class Commands {
SetPlayerIdleTimeoutCommand.register(this.dispatcher);
StopCommand.register(this.dispatcher);
WhitelistCommand.register(this.dispatcher);
+ net.pl3x.purpur.command.CreditsCommand.register(this.dispatcher); // Purpur
net.pl3x.purpur.command.DemoCommand.register(this.dispatcher); // Purpur
net.pl3x.purpur.command.PingCommand.register(this.dispatcher); // Purpur
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index 196f57d3c7f1b9e57122c42c73de7157da477246..c202cb7e325b8ace1ed3aa3ba86419d7571d0f0e 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -162,6 +162,7 @@ public class PurpurConfig {
public static String afkBroadcastBack = "<yellow><italic>%s is no longer AFK";
public static String afkTabListPrefix = "[AFK] ";
public static String afkTabListSuffix = "";
+ public static String creditsCommandOutput = "<green>%s has been shown the end credits";
public static String demoCommandOutput = "<green>%s has been shown the demo screen";
public static String pingCommandOutput = "<green>%s's ping is %sms";
private static void messages() {
@@ -170,6 +171,7 @@ public class PurpurConfig {
afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack);
afkTabListPrefix = getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix);
afkTabListSuffix = getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix);
+ creditsCommandOutput = getString("settings.messages.credits-command-output", creditsCommandOutput);
demoCommandOutput = getString("settings.messages.demo-command-output", demoCommandOutput);
pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput);
}
diff --git a/src/main/java/net/pl3x/purpur/command/CreditsCommand.java b/src/main/java/net/pl3x/purpur/command/CreditsCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..282be3e0e0cb3137829a88bd40fa18772dc344c2
--- /dev/null
+++ b/src/main/java/net/pl3x/purpur/command/CreditsCommand.java
@@ -0,0 +1,35 @@
+package net.pl3x.purpur.command;
+
+import com.mojang.brigadier.CommandDispatcher;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.commands.Commands;
+import net.minecraft.commands.arguments.EntityArgument;
+import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
+import net.minecraft.server.level.ServerPlayer;
+import net.pl3x.purpur.PurpurConfig;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public class CreditsCommand {
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
+ dispatcher.register(Commands.literal("credits")
+ .requires((listener) -> listener.hasPermission(2))
+ .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException())))
+ .then(Commands.argument("targets", EntityArgument.players())
+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets")))
+ )
+ ).setPermission("bukkit.command.credits");
+ }
+
+ private static int execute(CommandSourceStack sender, Collection<ServerPlayer> targets) {
+ for (ServerPlayer player : targets) {
+ ClientboundGameEventPacket packet = new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, 1F);
+ player.wonGame = true;
+ player.connection.send(packet);
+ String output = String.format(PurpurConfig.creditsCommandOutput, player.getGameProfile().getName());
+ sender.sendSuccess(output, false);
+ }
+ return targets.size();
+ }
+}

View File

@@ -0,0 +1,270 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 26 Mar 2020 21:39:32 -0500
Subject: [PATCH] Configurable jockey options
diff --git a/src/main/java/net/minecraft/world/entity/monster/Drowned.java b/src/main/java/net/minecraft/world/entity/monster/Drowned.java
index 5c4e028d3a7620af1476f63a8ad000eb94ffb992..b2e3ad40cdc594b13eaf43e71e2e18edd1fbb1b7 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Drowned.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Drowned.java
@@ -89,6 +89,21 @@ public class Drowned extends Zombie implements RangedAttackMob {
protected void randomizeReinforcementsChance() {
this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level.purpurConfig.drownedSpawnReinforcements);
}
+
+ @Override
+ public boolean jockeyOnlyBaby() {
+ return level.purpurConfig.drownedJockeyOnlyBaby;
+ }
+
+ @Override
+ public double jockeyChance() {
+ return level.purpurConfig.drownedJockeyChance;
+ }
+
+ @Override
+ public boolean jockeyTryExistingChickens() {
+ return level.purpurConfig.drownedJockeyTryExistingChickens;
+ }
// Purpur end
@Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/Husk.java b/src/main/java/net/minecraft/world/entity/monster/Husk.java
index 81a3f6c1774b187be96b412dae44be623ce7f6cb..7bb8ef0bb2de9a0b0d5048f8a4089835c41de568 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Husk.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Husk.java
@@ -42,6 +42,21 @@ public class Husk extends Zombie {
protected void randomizeReinforcementsChance() {
this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level.purpurConfig.huskSpawnReinforcements);
}
+
+ @Override
+ public boolean jockeyOnlyBaby() {
+ return level.purpurConfig.huskJockeyOnlyBaby;
+ }
+
+ @Override
+ public double jockeyChance() {
+ return level.purpurConfig.huskJockeyChance;
+ }
+
+ @Override
+ public boolean jockeyTryExistingChickens() {
+ return level.purpurConfig.huskJockeyTryExistingChickens;
+ }
// Purpur end
public static boolean checkHuskSpawnRules(EntityType<Husk> type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random) {
diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
index dc16331adb1d02265617af9d19638d9d1a28668d..1341377c6fd5ada85831d46d71a6066e8cc2e5cd 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
@@ -122,6 +122,18 @@ public class Zombie extends Monster {
public void initAttributes() {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level.purpurConfig.drownedMaxHealth);
}
+
+ public boolean jockeyOnlyBaby() {
+ return level.purpurConfig.zombieJockeyOnlyBaby;
+ }
+
+ public double jockeyChance() {
+ return level.purpurConfig.zombieJockeyChance;
+ }
+
+ public boolean jockeyTryExistingChickens() {
+ return level.purpurConfig.zombieJockeyTryExistingChickens;
+ }
// Purpur end
@Override
@@ -528,19 +540,20 @@ public class Zombie extends Monster {
if (object instanceof Zombie.ZombieGroupData) {
Zombie.ZombieGroupData entityzombie_groupdatazombie = (Zombie.ZombieGroupData) object;
- if (entityzombie_groupdatazombie.isBaby) {
- this.setBaby(true);
+ // Purpur start
+ if (!jockeyOnlyBaby() || entityzombie_groupdatazombie.isBaby) {
+ this.setBaby(entityzombie_groupdatazombie.isBaby);
if (entityzombie_groupdatazombie.canSpawnJockey) {
- if ((double) world.getRandom().nextFloat() < 0.05D) {
- List<Chicken> list = world.getEntitiesOfClass(Chicken.class, this.getBoundingBox().inflate(5.0D, 3.0D, 5.0D), EntitySelector.ENTITY_NOT_BEING_RIDDEN);
+ if ((double) world.getRandom().nextFloat() < jockeyChance()) {
+ List<Chicken> list = jockeyTryExistingChickens() ? world.getEntitiesOfClass(Chicken.class, this.getBoundingBox().inflate(5.0D, 3.0D, 5.0D), EntitySelector.ENTITY_NOT_BEING_RIDDEN) : java.util.Collections.emptyList();
+ // Purpur end
if (!list.isEmpty()) {
Chicken entitychicken = (Chicken) list.get(0);
entitychicken.setChickenJockey(true);
this.startRiding(entitychicken);
- }
- } else if ((double) world.getRandom().nextFloat() < 0.05D) {
+ } else { // Purpur
Chicken entitychicken1 = (Chicken) EntityType.CHICKEN.create(this.level);
entitychicken1.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F);
@@ -548,6 +561,7 @@ public class Zombie extends Monster {
entitychicken1.setChickenJockey(true);
this.startRiding(entitychicken1);
world.addEntity(entitychicken1, CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit
+ } // Purpur
}
}
}
diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java
index 9c60e3b3e62a29d6898c82a4110ffd4d1c7cb5f2..7fda07f5fa756077dab59de95f15b9197e09581a 100644
--- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java
+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java
@@ -94,6 +94,21 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
protected void randomizeReinforcementsChance() {
this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level.purpurConfig.zombieVillagerSpawnReinforcements);
}
+
+ @Override
+ public boolean jockeyOnlyBaby() {
+ return level.purpurConfig.zombieVillagerJockeyOnlyBaby;
+ }
+
+ @Override
+ public double jockeyChance() {
+ return level.purpurConfig.zombieVillagerJockeyChance;
+ }
+
+ @Override
+ public boolean jockeyTryExistingChickens() {
+ return level.purpurConfig.zombieVillagerJockeyTryExistingChickens;
+ }
// Purpur end
@Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java
index cc5bd132bbd40aba8c910695f25a896c5f4fe635..96e727cd703a1da5f60ab07e47b6bc5265b309e4 100644
--- a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java
+++ b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java
@@ -73,6 +73,21 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
public void initAttributes() {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level.purpurConfig.zombifiedPiglinMaxHealth);
}
+
+ @Override
+ public boolean jockeyOnlyBaby() {
+ return level.purpurConfig.zombifiedPiglinJockeyOnlyBaby;
+ }
+
+ @Override
+ public double jockeyChance() {
+ return level.purpurConfig.zombifiedPiglinJockeyChance;
+ }
+
+ @Override
+ public boolean jockeyTryExistingChickens() {
+ return level.purpurConfig.zombifiedPiglinJockeyTryExistingChickens;
+ }
// Purpur end
@Override
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 3d88ccc1ff7c87815bac2e9f573333e63caea223..f15963106c5592e1ea7ef715ed79d7c62e35d308 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -540,6 +540,9 @@ public class PurpurWorldConfig {
public boolean drownedRidableInWater = false;
public double drownedMaxHealth = 20.0D;
public double drownedSpawnReinforcements = 0.1D;
+ public boolean drownedJockeyOnlyBaby = true;
+ public double drownedJockeyChance = 0.05D;
+ public boolean drownedJockeyTryExistingChickens = true;
private void drownedSettings() {
drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable);
drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater);
@@ -550,6 +553,9 @@ public class PurpurWorldConfig {
}
drownedMaxHealth = getDouble("mobs.drowned.attributes.max_health", drownedMaxHealth);
drownedSpawnReinforcements = getDouble("mobs.drowned.attributes.spawn_reinforcements", drownedSpawnReinforcements);
+ drownedJockeyOnlyBaby = getBoolean("mobs.drowned.jockey.only-babies", drownedJockeyOnlyBaby);
+ drownedJockeyChance = getDouble("mobs.drowned.jockey.chance", drownedJockeyChance);
+ drownedJockeyTryExistingChickens = getBoolean("mobs.drowned.jockey.try-existing-chickens", drownedJockeyTryExistingChickens);
}
public boolean elderGuardianRidable = false;
@@ -762,6 +768,9 @@ public class PurpurWorldConfig {
public boolean huskRidableInWater = false;
public double huskMaxHealth = 20.0D;
public double huskSpawnReinforcements = 0.1D;
+ public boolean huskJockeyOnlyBaby = true;
+ public double huskJockeyChance = 0.05D;
+ public boolean huskJockeyTryExistingChickens = true;
private void huskSettings() {
huskRidable = getBoolean("mobs.husk.ridable", huskRidable);
huskRidableInWater = getBoolean("mobs.husk.ridable-in-water", huskRidableInWater);
@@ -772,6 +781,9 @@ public class PurpurWorldConfig {
}
huskMaxHealth = getDouble("mobs.husk.attributes.max_health", huskMaxHealth);
huskSpawnReinforcements = getDouble("mobs.husk.attributes.spawn_reinforcements", huskSpawnReinforcements);
+ huskJockeyOnlyBaby = getBoolean("mobs.husk.jockey.only-babies", huskJockeyOnlyBaby);
+ huskJockeyChance = getDouble("mobs.husk.jockey.chance", huskJockeyChance);
+ huskJockeyTryExistingChickens = getBoolean("mobs.husk.jockey.try-existing-chickens", huskJockeyTryExistingChickens);
}
public boolean illusionerRidable = false;
@@ -1472,6 +1484,9 @@ public class PurpurWorldConfig {
public boolean zombieRidableInWater = false;
public double zombieMaxHealth = 20.0D;
public double zombieSpawnReinforcements = 0.1D;
+ public boolean zombieJockeyOnlyBaby = true;
+ public double zombieJockeyChance = 0.05D;
+ public boolean zombieJockeyTryExistingChickens = true;
private void zombieSettings() {
zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable);
zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater);
@@ -1482,6 +1497,9 @@ public class PurpurWorldConfig {
}
zombieMaxHealth = getDouble("mobs.zombie.attributes.max_health", zombieMaxHealth);
zombieSpawnReinforcements = getDouble("mobs.zombie.attributes.spawn_reinforcements", zombieSpawnReinforcements);
+ zombieJockeyOnlyBaby = getBoolean("mobs.zombie.jockey.only-babies", zombieJockeyOnlyBaby);
+ zombieJockeyChance = getDouble("mobs.zombie.jockey.chance", zombieJockeyChance);
+ zombieJockeyTryExistingChickens = getBoolean("mobs.zombie.jockey.try-existing-chickens", zombieJockeyTryExistingChickens);
}
public boolean zombieHorseRidableInWater = false;
@@ -1515,6 +1533,9 @@ public class PurpurWorldConfig {
public boolean zombieVillagerRidableInWater = false;
public double zombieVillagerMaxHealth = 20.0D;
public double zombieVillagerSpawnReinforcements = 0.1D;
+ public boolean zombieVillagerJockeyOnlyBaby = true;
+ public double zombieVillagerJockeyChance = 0.05D;
+ public boolean zombieVillagerJockeyTryExistingChickens = true;
private void zombieVillagerSettings() {
zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable);
zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater);
@@ -1525,12 +1546,18 @@ public class PurpurWorldConfig {
}
zombieVillagerMaxHealth = getDouble("mobs.zombie_villager.attributes.max_health", zombieVillagerMaxHealth);
zombieVillagerSpawnReinforcements = getDouble("mobs.zombie_villager.attributes.spawn_reinforcements", zombieVillagerSpawnReinforcements);
+ zombieVillagerJockeyOnlyBaby = getBoolean("mobs.zombie_villager.jockey.only-babies", zombieVillagerJockeyOnlyBaby);
+ zombieVillagerJockeyChance = getDouble("mobs.zombie_villager.jockey.chance", zombieVillagerJockeyChance);
+ zombieVillagerJockeyTryExistingChickens = getBoolean("mobs.zombie_villager.jockey.try-existing-chickens", zombieVillagerJockeyTryExistingChickens);
}
public boolean zombifiedPiglinRidable = false;
public boolean zombifiedPiglinRidableInWater = false;
public double zombifiedPiglinMaxHealth = 20.0D;
public double zombifiedPiglinSpawnReinforcements = 0.0D;
+ public boolean zombifiedPiglinJockeyOnlyBaby = true;
+ public double zombifiedPiglinJockeyChance = 0.05D;
+ public boolean zombifiedPiglinJockeyTryExistingChickens = true;
private void zombifiedPiglinSettings() {
zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable);
zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater);
@@ -1541,5 +1568,8 @@ public class PurpurWorldConfig {
}
zombifiedPiglinMaxHealth = getDouble("mobs.zombified_piglin.attributes.max_health", zombifiedPiglinMaxHealth);
zombifiedPiglinSpawnReinforcements = getDouble("mobs.zombified_piglin.attributes.spawn_reinforcements", zombifiedPiglinSpawnReinforcements);
+ zombifiedPiglinJockeyOnlyBaby = getBoolean("mobs.zombified_piglin.jockey.only-babies", zombifiedPiglinJockeyOnlyBaby);
+ zombifiedPiglinJockeyChance = getDouble("mobs.zombified_piglin.jockey.chance", zombifiedPiglinJockeyChance);
+ zombifiedPiglinJockeyTryExistingChickens = getBoolean("mobs.zombified_piglin.jockey.try-existing-chickens", zombifiedPiglinJockeyTryExistingChickens);
}
}

View File

@@ -0,0 +1,283 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 9 May 2019 18:26:06 -0500
Subject: [PATCH] Phantoms attracted to crystals and crystals shoot phantoms
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
index b643a2449e329560c936c0a06fb4cc494d0737a7..92e65f3fbc8f5d77bb8cc31e7a7780c2589f4227 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
@@ -32,6 +32,12 @@ public class EndCrystal extends Entity {
private static final EntityDataAccessor<Boolean> DATA_SHOW_BOTTOM = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.BOOLEAN);
public int time;
public boolean generatedByDragonFight = false; // Paper - Fix invulnerable end crystals
+ // Purpur start
+ private net.minecraft.world.entity.monster.Phantom targetPhantom;
+ private int phantomBeamTicks = 0;
+ private int phantomDamageCooldown = 0;
+ private int idleCooldown = 0;
+ // Purpur end
public EndCrystal(EntityType<? extends EndCrystal> type, Level world) {
super(type, world);
@@ -81,7 +87,50 @@ public class EndCrystal extends Entity {
// Paper end
}
+ // Purpur start
+ if (level.purpurConfig.phantomAttackedByCrystalRadius <= 0 || --idleCooldown > 0) {
+ return; // on cooldown
+ }
+
+ if (targetPhantom == null) {
+ for (net.minecraft.world.entity.monster.Phantom phantom : level.getEntitiesOfClass(net.minecraft.world.entity.monster.Phantom.class, getBoundingBox().inflate(level.purpurConfig.phantomAttackedByCrystalRadius))) {
+ if (phantom.hasLineOfSight(this)) {
+ attackPhantom(phantom);
+ break;
+ }
+ }
+ } else {
+ setBeamTarget(new BlockPos(targetPhantom).offset(0, -2, 0));
+ if (--phantomBeamTicks > 0 && targetPhantom.isAlive()) {
+ phantomDamageCooldown--;
+ if (targetPhantom.hasLineOfSight(this)) {
+ if (phantomDamageCooldown <= 0) {
+ phantomDamageCooldown = 20;
+ targetPhantom.hurt(DamageSource.indirectMagic(this, this), level.purpurConfig.phantomAttackedByCrystalDamage);
+ }
+ } else {
+ forgetPhantom(); // no longer in sight
+ }
+ } else {
+ forgetPhantom(); // attacked long enough
+ }
+ }
+ }
+
+ private void attackPhantom(net.minecraft.world.entity.monster.Phantom phantom) {
+ phantomDamageCooldown = 0;
+ phantomBeamTicks = 60;
+ targetPhantom = phantom;
+ }
+
+ private void forgetPhantom() {
+ targetPhantom = null;
+ setBeamTarget(null);
+ phantomBeamTicks = 0;
+ phantomDamageCooldown = 0;
+ idleCooldown = 60;
}
+ // Purpur end
@Override
protected void addAdditionalSaveData(CompoundTag nbt) {
diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
index 5e71b3d5126d30626fbc9bd4b9eefebd20916e60..c314cb61f2e643de7eb12478d265f0664858f935 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
@@ -50,6 +50,7 @@ public class Phantom extends FlyingMob implements Enemy {
Vec3 moveTargetPoint;
BlockPos anchorPoint;
Phantom.AttackPhase attackPhase;
+ Vec3 crystalPosition; // Purpur
public Phantom(EntityType<? extends Phantom> type, Level world) {
super(type, world);
@@ -117,6 +118,24 @@ public class Phantom extends FlyingMob implements Enemy {
public void initAttributes() {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level.purpurConfig.phantomMaxHealth);
}
+
+ @Override
+ protected net.minecraft.world.level.storage.loot.LootContext.Builder createLootContext(boolean causedByPlayer, DamageSource source) {
+ boolean dropped = false;
+ if (lastHurtByPlayer == null && source.getEntity() instanceof net.minecraft.world.entity.boss.enderdragon.EndCrystal) {
+ if (random.nextInt(5) < 1) {
+ dropped = spawnAtLocation(new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.PHANTOM_MEMBRANE)) != null;
+ }
+ }
+ if (!dropped) {
+ return super.createLootContext(causedByPlayer, source);
+ }
+ return new net.minecraft.world.level.storage.loot.LootContext.Builder((net.minecraft.server.level.ServerLevel) level);
+ }
+
+ public boolean isCirclingCrystal() {
+ return crystalPosition != null;
+ }
// Purpur end
@Override
@@ -131,11 +150,17 @@ public class Phantom extends FlyingMob implements Enemy {
@Override
protected void registerGoals() {
- this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur
- this.goalSelector.addGoal(1, new Phantom.PhantomAttackStrategyGoal());
- this.goalSelector.addGoal(2, new Phantom.PhantomSweepAttackGoal());
- this.goalSelector.addGoal(3, new Phantom.PhantomCircleAroundAnchorGoal());
- this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur
+ // Purpur start
+ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this));
+ if (level.purpurConfig.phantomOrbitCrystalRadius > 0) {
+ this.goalSelector.addGoal(1, new FindCrystalGoal(this));
+ this.goalSelector.addGoal(2, new OrbitCrystalGoal(this));
+ }
+ this.goalSelector.addGoal(3, new Phantom.PhantomAttackStrategyGoal());
+ this.goalSelector.addGoal(4, new Phantom.PhantomSweepAttackGoal());
+ this.goalSelector.addGoal(5, new Phantom.PhantomCircleAroundAnchorGoal());
+ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this));
+ // Purpur end
this.targetSelector.addGoal(1, new Phantom.PhantomAttackPlayerTargetGoal());
}
@@ -325,6 +350,124 @@ public class Phantom extends FlyingMob implements Enemy {
private AttackPhase() {}
}
+ // Purpur start
+ class FindCrystalGoal extends Goal {
+ private final Phantom phantom;
+ private net.minecraft.world.entity.boss.enderdragon.EndCrystal crystal;
+ private Comparator<net.minecraft.world.entity.boss.enderdragon.EndCrystal> comparator;
+
+ FindCrystalGoal(Phantom phantom) {
+ this.phantom = phantom;
+ this.comparator = Comparator.comparingDouble(phantom::distanceToSqr);
+ this.setFlags(EnumSet.of(Flag.LOOK));
+ }
+
+ @Override
+ public boolean canUse() {
+ double range = maxTargetRange();
+ List<net.minecraft.world.entity.boss.enderdragon.EndCrystal> crystals = level.getEntitiesOfClass(net.minecraft.world.entity.boss.enderdragon.EndCrystal.class, phantom.getBoundingBox().inflate(range));
+ if (crystals.isEmpty()) {
+ return false;
+ }
+ crystals.sort(comparator);
+ crystal = crystals.get(0);
+ if (phantom.distanceToSqr(crystal) > range * range) {
+ crystal = null;
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean canContinueToUse() {
+ if (crystal == null || !crystal.isAlive()) {
+ return false;
+ }
+ double range = maxTargetRange();
+ return phantom.distanceToSqr(crystal) <= (range * range) * 2;
+ }
+
+ @Override
+ public void start() {
+ phantom.crystalPosition = new Vec3(crystal.getX(), crystal.getY() + (phantom.random.nextInt(10) + 10), crystal.getZ());
+ }
+
+ @Override
+ public void stop() {
+ crystal = null;
+ phantom.crystalPosition = null;
+ super.stop();
+ }
+
+ private double maxTargetRange() {
+ return phantom.level.purpurConfig.phantomOrbitCrystalRadius;
+ }
+ }
+
+ class OrbitCrystalGoal extends Goal {
+ private final Phantom phantom;
+ private float offset;
+ private float radius;
+ private float verticalChange;
+ private float direction;
+
+ OrbitCrystalGoal(Phantom phantom) {
+ this.phantom = phantom;
+ this.setFlags(EnumSet.of(Flag.MOVE));
+ }
+
+ @Override
+ public boolean canUse() {
+ return phantom.isCirclingCrystal();
+ }
+
+ @Override
+ public void start() {
+ this.radius = 5.0F + phantom.random.nextFloat() * 10.0F;
+ this.verticalChange = -4.0F + phantom.random.nextFloat() * 9.0F;
+ this.direction = phantom.random.nextBoolean() ? 1.0F : -1.0F;
+ updateOffset();
+ }
+
+ @Override
+ public void tick() {
+ if (phantom.random.nextInt(350) == 0) {
+ this.verticalChange = -4.0F + phantom.random.nextFloat() * 9.0F;
+ }
+ if (phantom.random.nextInt(250) == 0) {
+ ++this.radius;
+ if (this.radius > 15.0F) {
+ this.radius = 5.0F;
+ this.direction = -this.direction;
+ }
+ }
+ if (phantom.random.nextInt(450) == 0) {
+ this.offset = phantom.random.nextFloat() * 2.0F * 3.1415927F;
+ updateOffset();
+ }
+ if (phantom.moveTargetPoint.distanceToSqr(phantom.getX(), phantom.getY(), phantom.getZ()) < 4.0D) {
+ updateOffset();
+ }
+ if (phantom.moveTargetPoint.y < phantom.getY() && !phantom.level.isEmptyBlock(new BlockPos(phantom).below(1))) {
+ this.verticalChange = Math.max(1.0F, this.verticalChange);
+ updateOffset();
+ }
+ if (phantom.moveTargetPoint.y > phantom.getY() && !phantom.level.isEmptyBlock(new BlockPos(phantom).above(1))) {
+ this.verticalChange = Math.min(-1.0F, this.verticalChange);
+ updateOffset();
+ }
+ }
+
+ private void updateOffset() {
+ this.offset += this.direction * 15.0F * 0.017453292F;
+ phantom.moveTargetPoint = phantom.crystalPosition.add(
+ this.radius * Mth.cos(this.offset),
+ -4.0F + this.verticalChange,
+ this.radius * Mth.sin(this.offset));
+ }
+ }
+ // Purpur end
+
private class PhantomMoveControl extends net.pl3x.purpur.controller.FlyingMoveControllerWASD { // Purpur
private float speed = 0.1F;
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index f15963106c5592e1ea7ef715ed79d7c62e35d308..96bb947390a3d9e0d37ddbce2ff621c53e2c3f58 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -953,6 +953,9 @@ public class PurpurWorldConfig {
public int phantomFlameFireTime = 8;
public boolean phantomAllowGriefing = false;
public double phantomMaxHealth = 20.0D;
+ public double phantomAttackedByCrystalRadius = 0.0D;
+ public float phantomAttackedByCrystalDamage = 1.0F;
+ public double phantomOrbitCrystalRadius = 0.0D;
private void phantomSettings() {
phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable);
phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater);
@@ -966,6 +969,9 @@ public class PurpurWorldConfig {
set("mobs.phantom.attributes.max_health", oldValue);
}
phantomMaxHealth = getDouble("mobs.phantom.attributes.max_health", phantomMaxHealth);
+ phantomAttackedByCrystalRadius = getDouble("mobs.phantom.attacked-by-crystal-range", phantomAttackedByCrystalRadius);
+ phantomAttackedByCrystalDamage = (float) getDouble("mobs.phantom.attacked-by-crystal-damage", phantomAttackedByCrystalDamage);
+ phantomOrbitCrystalRadius = getDouble("mobs.phantom.orbit-crystal-radius", phantomOrbitCrystalRadius);
}
public boolean pigRidable = false;

View File

@@ -0,0 +1,91 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Fri, 3 Jul 2020 00:03:52 -0500
Subject: [PATCH] Add phantom spawning options
diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
index 79504dc3448402e73b09c4232b1fd0488872cf68..300c9f136edace2babea4a574090b1849b2adf76 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
@@ -43,8 +43,8 @@ public class PhantomSpawner implements CustomSpawner {
if (this.nextTick > 0) {
return 0;
} else {
- this.nextTick += (60 + random.nextInt(60)) * 20;
- if (world.getSkyDarken() < 5 && world.dimensionType().hasSkyLight()) {
+ this.nextTick += world.purpurConfig.phantomSpawnDelayMin + world.random.nextInt(world.purpurConfig.phantomSpawnDelayMax - world.purpurConfig.phantomSpawnDelayMin + 1); // Purpur
+ if (world.getSkyDarken() < world.purpurConfig.phantomSpawnMinSkyDarkness && world.dimensionType().hasSkyLight()) { // Purpur
return 0;
} else {
int i = 0;
@@ -56,22 +56,22 @@ public class PhantomSpawner implements CustomSpawner {
if (!entityhuman.isSpectator() && (!world.paperConfig.phantomIgnoreCreative || !entityhuman.isCreative())) { // Paper
BlockPos blockposition = entityhuman.blockPosition();
- if (!world.dimensionType().hasSkyLight() || blockposition.getY() >= world.getSeaLevel() && world.canSeeSky(blockposition)) {
+ if (!world.dimensionType().hasSkyLight() || (!world.purpurConfig.phantomSpawnOnlyAboveSeaLevel || blockposition.getY() >= world.getSeaLevel()) && (!world.purpurConfig.phantomSpawnOnlyWithVisibleSky || world.canSeeSky(blockposition))) { // Purpur
DifficultyInstance difficultydamagescaler = world.getCurrentDifficultyAt(blockposition);
- if (difficultydamagescaler.isHarderThan(random.nextFloat() * 3.0F)) {
+ if (difficultydamagescaler.isHarderThan(random.nextFloat() * (float) world.purpurConfig.phantomSpawnLocalDifficultyChance)) { // Purpur
ServerStatsCounter serverstatisticmanager = ((ServerPlayer) entityhuman).getStats();
int j = Mth.clamp(serverstatisticmanager.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE);
boolean flag2 = true;
- if (random.nextInt(j) >= 72000) {
- BlockPos blockposition1 = blockposition.above(20 + random.nextInt(15)).east(-10 + random.nextInt(21)).south(-10 + random.nextInt(21));
+ if (random.nextInt(j) >= world.purpurConfig.phantomSpawnMinTimeSinceSlept) { // Purpur
+ BlockPos blockposition1 = blockposition.above(world.purpurConfig.phantomSpawnMinOverhead + random.nextInt(world.purpurConfig.phantomSpawnMaxOverhead - world.purpurConfig.phantomSpawnMinOverhead + 1)).east(-world.purpurConfig.phantomSpawnOverheadRadius + random.nextInt(world.purpurConfig.phantomSpawnOverheadRadius * 2 + 1)).south(-world.purpurConfig.phantomSpawnOverheadRadius + random.nextInt(world.purpurConfig.phantomSpawnOverheadRadius * 2 + 1)); // Purpur
BlockState iblockdata = world.getBlockState(blockposition1);
FluidState fluid = world.getFluidState(blockposition1);
if (NaturalSpawner.isValidEmptySpawnBlock((BlockGetter) world, blockposition1, iblockdata, fluid, EntityType.PHANTOM)) {
SpawnGroupData groupdataentity = null;
- int k = 1 + random.nextInt(difficultydamagescaler.getDifficulty().getId() + 1);
+ int k = world.purpurConfig.phantomSpawnMinPerAttempt + world.random.nextInt((world.purpurConfig.phantomSpawnMaxPerAttempt < 0 ? difficultydamagescaler.getDifficulty().getId() : world.purpurConfig.phantomSpawnMaxPerAttempt - world.purpurConfig.phantomSpawnMinPerAttempt) + 1); // Purpur
for (int l = 0; l < k; ++l) {
// Paper start
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 96bb947390a3d9e0d37ddbce2ff621c53e2c3f58..e92c0c732af5581c266b146f360bce05364d8a28 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -956,6 +956,18 @@ public class PurpurWorldConfig {
public double phantomAttackedByCrystalRadius = 0.0D;
public float phantomAttackedByCrystalDamage = 1.0F;
public double phantomOrbitCrystalRadius = 0.0D;
+ public int phantomSpawnDelayMin = 1200;
+ public int phantomSpawnDelayMax = 2400;
+ public int phantomSpawnMinSkyDarkness = 5;
+ public boolean phantomSpawnOnlyAboveSeaLevel = true;
+ public boolean phantomSpawnOnlyWithVisibleSky = true;
+ public double phantomSpawnLocalDifficultyChance = 3.0D;
+ public int phantomSpawnMinTimeSinceSlept = 72000;
+ public int phantomSpawnMinOverhead = 20;
+ public int phantomSpawnMaxOverhead = 35;
+ public int phantomSpawnOverheadRadius = 10;
+ public int phantomSpawnMinPerAttempt = 1;
+ public int phantomSpawnMaxPerAttempt = -1;
private void phantomSettings() {
phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable);
phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater);
@@ -972,6 +984,18 @@ public class PurpurWorldConfig {
phantomAttackedByCrystalRadius = getDouble("mobs.phantom.attacked-by-crystal-range", phantomAttackedByCrystalRadius);
phantomAttackedByCrystalDamage = (float) getDouble("mobs.phantom.attacked-by-crystal-damage", phantomAttackedByCrystalDamage);
phantomOrbitCrystalRadius = getDouble("mobs.phantom.orbit-crystal-radius", phantomOrbitCrystalRadius);
+ phantomSpawnDelayMin = getInt("mobs.phantom.spawn.delay.min", phantomSpawnDelayMin);
+ phantomSpawnDelayMax = getInt("mobs.phantom.spawn.delay.max", phantomSpawnDelayMax);
+ phantomSpawnMinSkyDarkness = getInt("mobs.phantom.spawn.min-sky-darkness", phantomSpawnMinSkyDarkness);
+ phantomSpawnOnlyAboveSeaLevel = getBoolean("mobs.phantom.spawn.only-above-sea-level", phantomSpawnOnlyAboveSeaLevel);
+ phantomSpawnOnlyWithVisibleSky = getBoolean("mobs.phantom.spawn.only-with-visible-sky", phantomSpawnOnlyWithVisibleSky);
+ phantomSpawnLocalDifficultyChance = getDouble("mobs.phantom.spawn.local-difficulty-chance", phantomSpawnLocalDifficultyChance);
+ phantomSpawnMinTimeSinceSlept = getInt("mobs.phantom.spawn.min-time-since-slept", phantomSpawnMinTimeSinceSlept);
+ phantomSpawnMinOverhead = getInt("mobs.phantom.spawn.overhead.min", phantomSpawnMinOverhead);
+ phantomSpawnMaxOverhead = getInt("mobs.phantom.spawn.overhead.max", phantomSpawnMaxOverhead);
+ phantomSpawnOverheadRadius = getInt("mobs.phantom.spawn.overhead.radius", phantomSpawnOverheadRadius);
+ phantomSpawnMinPerAttempt = getInt("mobs.phantom.spawn.per-attempt.min", phantomSpawnMinPerAttempt);
+ phantomSpawnMaxPerAttempt = getInt("mobs.phantom.spawn.per-attempt.max", phantomSpawnMaxPerAttempt);
}
public boolean pigRidable = false;

View File

@@ -0,0 +1,55 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 4 Jul 2020 13:12:43 -0500
Subject: [PATCH] Implement bed explosion options
diff --git a/src/main/java/net/minecraft/world/level/block/BedBlock.java b/src/main/java/net/minecraft/world/level/block/BedBlock.java
index e3ff04fe21761db65fb03c5e58ecd5823f0507c6..6362c9dcfbc980a0591ac6dfebe45e475b73d020 100644
--- a/src/main/java/net/minecraft/world/level/block/BedBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/BedBlock.java
@@ -97,7 +97,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock
world.removeBlock(blockposition1, false);
}
- world.explode((Entity) null, DamageSource.badRespawnPointExplosion(), (ExplosionDamageCalculator) null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, 5.0F, true, Explosion.BlockInteraction.DESTROY);
+ if (world.purpurConfig.bedExplode) world.explode((Entity) null, DamageSource.badRespawnPointExplosion(), null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (float) world.purpurConfig.bedExplosionPower, world.purpurConfig.bedExplosionFire, world.purpurConfig.bedExplosionEffect); // Purpur
return InteractionResult.SUCCESS;
} else if ((Boolean) state.getValue(BedBlock.OCCUPIED)) {
if (!this.kickVillagerOutOfBed(world, pos)) {
@@ -146,7 +146,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock
world.removeBlock(blockposition1, false);
}
- world.explode((Entity) null, DamageSource.badRespawnPointExplosion(), (ExplosionDamageCalculator) null, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, 5.0F, true, Explosion.BlockInteraction.DESTROY);
+ if (world.purpurConfig.bedExplode) world.explode((Entity) null, DamageSource.badRespawnPointExplosion(), null, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, (float) world.purpurConfig.bedExplosionPower, world.purpurConfig.bedExplosionFire, world.purpurConfig.bedExplosionEffect); // Purpur
return InteractionResult.SUCCESS;
}
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index e92c0c732af5581c266b146f360bce05364d8a28..4405108543e36b74be2678d6e5b1de9363db5151 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -292,6 +292,22 @@ public class PurpurWorldConfig {
voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt);
}
+ public boolean bedExplode = true;
+ public double bedExplosionPower = 5.0D;
+ public boolean bedExplosionFire = true;
+ public Explosion.BlockInteraction bedExplosionEffect = Explosion.BlockInteraction.DESTROY;
+ private void bedSettings() {
+ bedExplode = getBoolean("blocks.bed.explode", bedExplode);
+ bedExplosionPower = getDouble("blocks.bed.explosion-power", bedExplosionPower);
+ bedExplosionFire = getBoolean("blocks.bed.explosion-fire", bedExplosionFire);
+ try {
+ bedExplosionEffect = Explosion.BlockInteraction.valueOf(getString("blocks.bed.explosion-effect", bedExplosionEffect.name()));
+ } catch (IllegalArgumentException e) {
+ log(Level.SEVERE, "Unknown value for `blocks.bed.explosion-effect`! Using default of `DESTROY`");
+ bedExplosionEffect = Explosion.BlockInteraction.DESTROY;
+ }
+ }
+
public boolean dispenserApplyCursedArmor = true;
private void dispenserSettings() {
dispenserApplyCursedArmor = getBoolean("blocks.dispenser.apply-cursed-to-armor-slots", dispenserApplyCursedArmor);

View File

@@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 4 Jul 2020 13:23:19 -0500
Subject: [PATCH] Implement respawn anchor explosion options
diff --git a/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java b/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java
index 0a5d563700c9f806139001181f01fa9d0111f792..1aae3d27ed6c0433312502a59fe1eb70b7d14ac3 100644
--- a/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java
@@ -120,7 +120,7 @@ public class RespawnAnchorBlock extends Block {
return pos.equals(explodedPos) && bl2 ? Optional.of(Blocks.WATER.getExplosionResistance()) : super.getBlockExplosionResistance(explosion, world, pos, blockState, fluidState);
}
};
- world.explode((Entity)null, DamageSource.badRespawnPointExplosion(), explosionDamageCalculator, (double)explodedPos.getX() + 0.5D, (double)explodedPos.getY() + 0.5D, (double)explodedPos.getZ() + 0.5D, 5.0F, true, Explosion.BlockInteraction.DESTROY);
+ if (world.purpurConfig.respawnAnchorExplode) world.explode(null, DamageSource.badRespawnPointExplosion(), explosionDamageCalculator, (double) explodedPos.getX() + 0.5D, (double) explodedPos.getY() + 0.5D, (double) explodedPos.getZ() + 0.5D, (float) world.purpurConfig.respawnAnchorExplosionPower, world.purpurConfig.respawnAnchorExplosionFire, world.purpurConfig.respawnAnchorExplosionEffect); // Purpur
}
public static boolean canSetSpawn(Level world) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 4405108543e36b74be2678d6e5b1de9363db5151..45e2c201f4d6768e029d075dfcb3716c92d394a4 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -336,6 +336,22 @@ public class PurpurWorldConfig {
waterInfiniteRequiredSources = getInt("blocks.water.infinite-required-sources", waterInfiniteRequiredSources);
}
+ public boolean respawnAnchorExplode = true;
+ public double respawnAnchorExplosionPower = 5.0D;
+ public boolean respawnAnchorExplosionFire = true;
+ public Explosion.BlockInteraction respawnAnchorExplosionEffect = Explosion.BlockInteraction.DESTROY;
+ private void respawnAnchorSettings() {
+ respawnAnchorExplode = getBoolean("blocks.respawn_anchor.explode", respawnAnchorExplode);
+ respawnAnchorExplosionPower = getDouble("blocks.respawn_anchor.explosion-power", respawnAnchorExplosionPower);
+ respawnAnchorExplosionFire = getBoolean("blocks.respawn_anchor.explosion-fire", respawnAnchorExplosionFire);
+ try {
+ respawnAnchorExplosionEffect = Explosion.BlockInteraction.valueOf(getString("blocks.respawn_anchor.explosion-effect", respawnAnchorExplosionEffect.name()));
+ } catch (IllegalArgumentException e) {
+ log(Level.SEVERE, "Unknown value for `blocks.respawn_anchor.explosion-effect`! Using default of `DESTROY`");
+ respawnAnchorExplosionEffect = Explosion.BlockInteraction.DESTROY;
+ }
+ }
+
public boolean signAllowColors = false;
public boolean signRightClickEdit = false;
private void signSettings() {

View File

@@ -0,0 +1,85 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sun, 5 Jul 2020 23:40:16 -0500
Subject: [PATCH] Add allow water in end world option
diff --git a/src/main/java/net/minecraft/world/item/BucketItem.java b/src/main/java/net/minecraft/world/item/BucketItem.java
index 69c992ef0c526adf35907de7726832605187beb6..6356d5fdb349063071c9119ae776c22e0b321d77 100644
--- a/src/main/java/net/minecraft/world/item/BucketItem.java
+++ b/src/main/java/net/minecraft/world/item/BucketItem.java
@@ -170,7 +170,7 @@ public class BucketItem extends Item implements DispensibleContainerItem {
// CraftBukkit end
if (!flag1) {
return movingobjectpositionblock != null && this.emptyContents(entityhuman, world, movingobjectpositionblock.getBlockPos().relative(movingobjectpositionblock.getDirection()), (BlockHitResult) null, enumdirection, clicked, itemstack, enumhand); // CraftBukkit // Paper - add enumhand
- } else if (world.dimensionType().ultraWarm() && this.content.is((Tag) FluidTags.WATER)) {
+ } else if ((world.isNether() || (world.isTheEnd() && !net.pl3x.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) && this.content.is((Tag) FluidTags.WATER)) {
int i = blockposition.getX();
int j = blockposition.getY();
int k = blockposition.getZ();
@@ -178,7 +178,7 @@ public class BucketItem extends Item implements DispensibleContainerItem {
world.playSound(entityhuman, blockposition, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F);
for (int l = 0; l < 8; ++l) {
- world.addParticle(ParticleTypes.LARGE_SMOKE, (double) i + Math.random(), (double) j + Math.random(), (double) k + Math.random(), 0.0D, 0.0D, 0.0D);
+ ((ServerLevel) world).sendParticles(null, ParticleTypes.LARGE_SMOKE, (double) i + Math.random(), (double) j + Math.random(), (double) k + Math.random(), 1, 0.0D, 0.0D, 0.0D, 0.0D, true); // Purpur
}
return true;
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index c44dc4cefdd74437a39283800aa6e93372525fbd..a1d9e9caed9e922cc65512a36019a0993bf549c6 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -1486,4 +1486,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
}
}
+
+ // Purpur start
+ public boolean isNether() {
+ return getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER;
+ }
+
+ public boolean isTheEnd() {
+ return getWorld().getEnvironment() == org.bukkit.World.Environment.THE_END;
+ }
+ // Purpur end
}
diff --git a/src/main/java/net/minecraft/world/level/block/IceBlock.java b/src/main/java/net/minecraft/world/level/block/IceBlock.java
index df4f2c729f09d5229553308e4876f29de648543f..f2b0278679fa649bbc2904660e0dc9ab4ad54542 100644
--- a/src/main/java/net/minecraft/world/level/block/IceBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/IceBlock.java
@@ -27,7 +27,7 @@ public class IceBlock extends HalfTransparentBlock {
public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack) {
super.playerDestroy(world, player, pos, state, blockEntity, stack);
if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, stack) == 0) {
- if (world.dimensionType().ultraWarm()) {
+ if (world.isNether() || (world.isTheEnd() && !net.pl3x.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) { // Purpur
world.removeBlock(pos, false);
return;
}
@@ -55,7 +55,7 @@ public class IceBlock extends HalfTransparentBlock {
return;
}
// CraftBukkit end
- if (world.dimensionType().ultraWarm()) {
+ if (world.isNether() || (world.isTheEnd() && !net.pl3x.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) { // Purpur
world.removeBlock(pos, false);
} else {
world.setBlockAndUpdate(pos, Blocks.WATER.defaultBlockState());
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index c202cb7e325b8ace1ed3aa3ba86419d7571d0f0e..b2b7d0a89a6a0d3482caea8fcad1d46de7e4b8ee 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -244,6 +244,11 @@ public class PurpurConfig {
dontSendUselessEntityPackets = getBoolean("settings.dont-send-useless-entity-packets", dontSendUselessEntityPackets);
}
+ public static boolean allowWaterPlacementInTheEnd = true;
+ private static void allowWaterPlacementInEnd() {
+ allowWaterPlacementInTheEnd = getBoolean("settings.allow-water-placement-in-the-end", allowWaterPlacementInTheEnd);
+ }
+
public static boolean loggerSuppressInitLegacyMaterialError = false;
public static boolean loggerSuppressIgnoredAdvancementWarnings = false;
public static boolean loggerSuppressUnrecognizedRecipeErrors = false;

View File

@@ -0,0 +1,76 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Tue, 3 Nov 2020 01:25:06 -0600
Subject: [PATCH] Allow color codes in books
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 367876813fcf772baf6542e1422b5c9572056a18..ba6a674c2b18108390c7b9d2bb313a603d9909b4 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1219,13 +1219,16 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
itemstack1.setTag(nbttagcompound.copy());
}
+ // Purpur start
+ boolean hasPerm = getCraftPlayer().hasPermission("purpur.book.color.edit") || getCraftPlayer().hasPermission("purpur.book.color.sign"); // Purpur
itemstack1.addTagElement("author", (Tag) StringTag.valueOf(this.player.getName().getString()));
if (this.player.isTextFilteringEnabled()) {
- itemstack1.addTagElement("title", (Tag) StringTag.valueOf(title.getFiltered()));
+ itemstack1.addTagElement("title", (Tag) StringTag.valueOf(color(title.getFiltered(), hasPerm)));
} else {
- itemstack1.addTagElement("filtered_title", (Tag) StringTag.valueOf(title.getFiltered()));
- itemstack1.addTagElement("title", (Tag) StringTag.valueOf(title.getRaw()));
+ itemstack1.addTagElement("filtered_title", (Tag) StringTag.valueOf(color(title.getFiltered(), hasPerm)));
+ itemstack1.addTagElement("title", (Tag) StringTag.valueOf(color(title.getRaw(), hasPerm)));
}
+ // Purpur end
this.updateBookPages(pages, (s) -> {
return Component.Serializer.toJson((Component) (new TextComponent(s)));
@@ -1237,10 +1240,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
private void updateBookPages(List<TextFilter.FilteredText> list, UnaryOperator<String> unaryoperator, ItemStack itemstack, int slot, ItemStack handItem) { // CraftBukkit
ListTag nbttaglist = new ListTag();
+ // Purpur start
+ boolean hasPerm = getCraftPlayer().hasPermission("purpur.book.color.edit");
if (this.player.isTextFilteringEnabled()) {
- Stream<StringTag> stream = list.stream().map((itextfilter_a) -> { // CraftBukkit - decompile error
- return StringTag.valueOf((String) unaryoperator.apply(itextfilter_a.getFiltered()));
+ Stream<StringTag> stream = list.stream().map(s -> color(s.getFiltered(), hasPerm, false)).map((s) -> { // CraftBukkit - decompile error
+ return StringTag.valueOf((String) unaryoperator.apply(s));
});
+ // Purpur end
Objects.requireNonNull(nbttaglist);
stream.forEach(nbttaglist::add);
@@ -1250,10 +1256,10 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
for (int j = list.size(); i < j; ++i) {
TextFilter.FilteredText itextfilter_a = (TextFilter.FilteredText) list.get(i);
- String s = itextfilter_a.getRaw();
+ String s = color(itextfilter_a.getRaw(), hasPerm, false);
nbttaglist.add(StringTag.valueOf((String) unaryoperator.apply(s)));
- String s1 = itextfilter_a.getFiltered();
+ String s1 = color(itextfilter_a.getFiltered(), hasPerm, false);
if (!s.equals(s1)) {
nbttagcompound.putString(String.valueOf(i), (String) unaryoperator.apply(s1));
@@ -1269,6 +1275,16 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
this.player.getInventory().setItem(slot, CraftEventFactory.handleEditBookEvent(player, slot, handItem, itemstack)); // CraftBukkit // Paper - Don't ignore result (see other callsite for handleEditBookEvent)
}
+ // Purpur start
+ private String color(String str, boolean hasPerm) {
+ return color(str, hasPerm, true);
+ }
+
+ private String color(String str, boolean hasPerm, boolean parseHex) {
+ return hasPerm ? org.bukkit.ChatColor.color(str, parseHex) : str;
+ }
+ // Purpur end
+
@Override
public void handleEntityTagQuery(ServerboundEntityTagQuery packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());

View File

@@ -0,0 +1,106 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 11 Jul 2020 19:41:34 -0500
Subject: [PATCH] Entity lifespan
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index 7be2798a1b190b44445e3abd55c0598e3432bf27..a268895fa22b81c164837a731d4bde51a68190c4 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -126,6 +126,7 @@ public abstract class Mob extends LivingEntity {
private BlockPos restrictCenter;
private float restrictRadius;
+ public int ticksSinceLastInteraction; // Purpur
public boolean aware = true; // CraftBukkit
protected Mob(EntityType<? extends Mob> type, Level world) {
@@ -283,6 +284,7 @@ public abstract class Mob extends LivingEntity {
entityliving = null;
}
}
+ if (entityliving instanceof ServerPlayer) this.ticksSinceLastInteraction = 0; // Purpur
this.target = entityliving;
return true;
// CraftBukkit end
@@ -327,9 +329,35 @@ public abstract class Mob extends LivingEntity {
this.playAmbientSound();
}
+ incrementTicksSinceLastInteraction();
this.level.getProfiler().pop();
}
+ // Purpur start
+ private void incrementTicksSinceLastInteraction() {
+ ++ticksSinceLastInteraction;
+ //if (hasRider()) {
+ // ticksSinceLastInteraction = 0;
+ // return;
+ //}
+ if (level.purpurConfig.entityLifeSpan <= 0) {
+ return; // feature disabled
+ }
+ if (!this.removeWhenFarAway(0) || isPersistenceRequired() || requiresCustomPersistence() || hasCustomName()) {
+ return; // mob persistent
+ }
+ if (ticksSinceLastInteraction > level.purpurConfig.entityLifeSpan) {
+ this.discard();
+ }
+ }
+
+ @Override
+ public boolean hurt(DamageSource source, float amount) {
+ if (source.getEntity() instanceof ServerPlayer) this.ticksSinceLastInteraction = 0; // Purpur
+ return super.hurt(source, amount);
+ }
+ // Purpur end
+
@Override
protected void playHurtSound(DamageSource source) {
this.resetAmbientSoundTime();
@@ -513,6 +541,7 @@ public abstract class Mob extends LivingEntity {
}
nbt.putBoolean("Bukkit.Aware", this.aware); // CraftBukkit
+ nbt.putInt("Purpur.ticksSinceLastInteraction", ticksSinceLastInteraction); // Purpur
}
@Override
@@ -583,6 +612,11 @@ public abstract class Mob extends LivingEntity {
this.aware = nbt.getBoolean("Bukkit.Aware");
}
// CraftBukkit end
+ // Purpur start
+ if (nbt.contains("Purpur.ticksSinceLastInteraction")) {
+ ticksSinceLastInteraction = nbt.getInt("Purpur.ticksSinceLastInteraction");
+ }
+ // Purpur end
}
@Override
@@ -1590,6 +1624,7 @@ public abstract class Mob extends LivingEntity {
this.setLastHurtMob(target);
}
+ if (target instanceof ServerPlayer) this.ticksSinceLastInteraction = 0; // Purpur
return flag;
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 45e2c201f4d6768e029d075dfcb3716c92d394a4..a16797934b4c803828996c7a7f1b18f6b4925250 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -112,6 +112,11 @@ public class PurpurWorldConfig {
elytraDamagePerTridentBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.trident", elytraDamagePerTridentBoost);
}
+ public int entityLifeSpan = 0;
+ private void entitySettings() {
+ entityLifeSpan = getInt("gameplay-mechanics.entity-lifespan", entityLifeSpan);
+ }
+
public List<Item> itemImmuneToCactus = new ArrayList<>();
public List<Item> itemImmuneToExplosion = new ArrayList<>();
public List<Item> itemImmuneToFire = new ArrayList<>();

View File

@@ -0,0 +1,76 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Mon, 13 Jul 2020 11:40:00 -0500
Subject: [PATCH] Add option to teleport to spawn if outside world border
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index c488f0c2db28b5eff7209fe900ca27408fc1ce0e..dd3b3e4821dbd3a1fb73ddcc31c022175c18708d 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -2519,5 +2519,25 @@ public class ServerPlayer extends Player {
}
// CraftBukkit end
+ // Purpur start
+ public void teleport(Location to) {
+ this.ejectPassengers();
+ this.stopRiding(true);
+ if (this.isSleeping()) {
+ this.stopSleepInBed(true, false);
+ }
+
+ if (this.containerMenu != this.inventoryMenu) {
+ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.TELEPORT);
+ }
+
+ ServerLevel toLevel = ((CraftWorld) to.getWorld()).getHandle();
+ if (this.level == toLevel) {
+ this.connection.teleport(to);
+ } else {
+ this.server.getPlayerList().moveToWorld(this, toLevel, true, to, !toLevel.paperConfig.disableTeleportationSuffocationCheck);
+ }
+ }
+ // Purpur end
}
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 71ef80e636ac7c208b362410eaaffa497dd9ceca..63936445bc9005c11bbe669e29897786963e7626 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -45,6 +45,7 @@ import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.MCUtil;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
@@ -407,6 +408,7 @@ public abstract class LivingEntity extends Entity {
double d1 = this.level.getWorldBorder().getDamagePerBlock();
if (d1 > 0.0D) {
+ if (level.purpurConfig.teleportIfOutsideBorder && this instanceof ServerPlayer) { ((ServerPlayer) this).teleport(MCUtil.toLocation(level, ((ServerLevel) level).getSharedSpawnPos())); return; } // Purpur
this.hurt(DamageSource.IN_WALL, (float) Math.max(1, Mth.floor(-d0 * d1)));
}
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index a16797934b4c803828996c7a7f1b18f6b4925250..213950f1d36c504824d0053843c3fe869f9eed84 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -231,6 +231,7 @@ public class PurpurWorldConfig {
public boolean playerInvulnerableWhileAcceptingResourcePack = false;
public String playerDeathExpDropEquation = "expLevel * 7";
public int playerDeathExpDropMax = 100;
+ public boolean teleportIfOutsideBorder = false;
private void playerSettings() {
if (PurpurConfig.version < 19) {
boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer);
@@ -246,6 +247,7 @@ public class PurpurWorldConfig {
playerInvulnerableWhileAcceptingResourcePack = getBoolean("gameplay-mechanics.player.invulnerable-while-accepting-resource-pack", playerInvulnerableWhileAcceptingResourcePack);
playerDeathExpDropEquation = getString("gameplay-mechanics.player.exp-dropped-on-death.equation", playerDeathExpDropEquation);
playerDeathExpDropMax = getInt("gameplay-mechanics.player.exp-dropped-on-death.maximum", playerDeathExpDropMax);
+ teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder);
}
public boolean silkTouchEnabled = false;

View File

@@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Mon, 13 Jul 2020 13:49:41 -0500
Subject: [PATCH] Squid EAR immunity
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 213950f1d36c504824d0053843c3fe869f9eed84..1c1a1ed14a1e2a80b3a26cb990b2577904d73b0b 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1289,6 +1289,7 @@ public class PurpurWorldConfig {
public boolean squidRidable = false;
public double squidMaxHealth = 10.0D;
+ public boolean squidImmuneToEAR = true;
private void squidSettings() {
squidRidable = getBoolean("mobs.squid.ridable", squidRidable);
if (PurpurConfig.version < 10) {
@@ -1297,6 +1298,7 @@ public class PurpurWorldConfig {
set("mobs.squid.attributes.max_health", oldValue);
}
squidMaxHealth = getDouble("mobs.squid.attributes.max_health", squidMaxHealth);
+ squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR);
}
public boolean spiderRidable = false;
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index 12ffca6a545e4af5c66ecd8b15d9d8e20a6327c1..a42a96819abe9651ea31a6f869d0017303a17323 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -14,6 +14,7 @@ import net.minecraft.world.entity.ambient.AmbientCreature;
import net.minecraft.world.entity.animal.Animal;
import net.minecraft.world.entity.animal.Bee;
import net.minecraft.world.entity.animal.Sheep;
+import net.minecraft.world.entity.animal.Squid;
import net.minecraft.world.entity.animal.WaterAnimal;
import net.minecraft.world.entity.animal.horse.Llama;
import net.minecraft.world.entity.boss.EnderDragonPart;
@@ -357,6 +358,7 @@ public class ActivationRange
*/
public static boolean checkIfActive(Entity entity)
{
+ if (entity.level.purpurConfig.squidImmuneToEAR && entity instanceof Squid) return true; // Purpur
// Never safe to skip fireworks or entities not yet added to chunk
if ( entity instanceof FireworkRocketEntity ) {
return true;

View File

@@ -0,0 +1,72 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: draycia <lonelyyordle@gmail.com>
Date: Sun, 12 Apr 2020 20:41:59 -0700
Subject: [PATCH] Phantoms burn in light
diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
index c314cb61f2e643de7eb12478d265f0664858f935..789224c6285cde2009e000d98e190c36459f04e8 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
@@ -51,6 +51,7 @@ public class Phantom extends FlyingMob implements Enemy {
BlockPos anchorPoint;
Phantom.AttackPhase attackPhase;
Vec3 crystalPosition; // Purpur
+ 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
public Phantom(EntityType<? extends Phantom> type, Level world) {
super(type, world);
@@ -230,7 +231,7 @@ public class Phantom extends FlyingMob implements Enemy {
@Override
public void aiStep() {
- if (this.isAlive() && getRider() == null && shouldBurnInDay && this.isSunBurnTick()) { // Paper - Configurable Burning // Purpur
+ if (this.isAlive() && getRider() == null && (((shouldBurnInDay || level.purpurConfig.phantomBurnInDaylight) && this.isSunBurnTick()) || (level.purpurConfig.phantomBurnInLight > 0 && level.getMaxLocalRawBrightness(blockPosition()) >= level.purpurConfig.phantomBurnInLight))) { // Paper - Configurable Burning // Purpur
this.setSecondsOnFire(8);
}
@@ -630,6 +631,12 @@ public class Phantom extends FlyingMob implements Enemy {
return false;
} else if (!entityliving.isAlive()) {
return false;
+ // Purpur start
+ } else if (level.purpurConfig.phantomBurnInLight > 0 && level.getLightEmission(new BlockPos(Phantom.this)) >= level.purpurConfig.phantomBurnInLight) {
+ return false;
+ } else if (level.purpurConfig.phantomIgnorePlayersWithTorch && (TORCH.test(entityliving.getItemInHand(net.minecraft.world.InteractionHand.MAIN_HAND)) || TORCH.test(entityliving.getItemInHand(net.minecraft.world.InteractionHand.OFF_HAND)))) {
+ return false;
+ // Purpur end
} else if (entityliving instanceof Player && (((Player) entityliving).isSpectator() || ((Player) entityliving).isCreative())) {
return false;
} else if (!this.canUse()) {
@@ -767,6 +774,7 @@ public class Phantom extends FlyingMob implements Enemy {
this.nextScanTick = 60;
List<Player> list = Phantom.this.level.getNearbyPlayers(this.attackTargeting, (LivingEntity) Phantom.this, Phantom.this.getBoundingBox().inflate(16.0D, 64.0D, 16.0D));
+ if (level.purpurConfig.phantomIgnorePlayersWithTorch) list.removeIf(human -> TORCH.test(human.getItemInHand(net.minecraft.world.InteractionHand.MAIN_HAND)) || TORCH.test(human.getItemInHand(net.minecraft.world.InteractionHand.OFF_HAND)));// Purpur
if (!list.isEmpty()) {
list.sort(Comparator.<Player, Double>comparing(Entity::getY).reversed()); // Paper - remap fix
Iterator iterator = list.iterator();
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 1c1a1ed14a1e2a80b3a26cb990b2577904d73b0b..f06fb11df26f7a7e3fdb1f7ce21aa67e3ed5a07d 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1007,6 +1007,9 @@ public class PurpurWorldConfig {
public int phantomSpawnOverheadRadius = 10;
public int phantomSpawnMinPerAttempt = 1;
public int phantomSpawnMaxPerAttempt = -1;
+ public int phantomBurnInLight = 0;
+ public boolean phantomIgnorePlayersWithTorch = false;
+ public boolean phantomBurnInDaylight = true;
private void phantomSettings() {
phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable);
phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater);
@@ -1035,6 +1038,9 @@ public class PurpurWorldConfig {
phantomSpawnOverheadRadius = getInt("mobs.phantom.spawn.overhead.radius", phantomSpawnOverheadRadius);
phantomSpawnMinPerAttempt = getInt("mobs.phantom.spawn.per-attempt.min", phantomSpawnMinPerAttempt);
phantomSpawnMaxPerAttempt = getInt("mobs.phantom.spawn.per-attempt.max", phantomSpawnMaxPerAttempt);
+ phantomBurnInLight = getInt("mobs.phantom.burn-in-light", phantomBurnInLight);
+ phantomBurnInDaylight = getBoolean("mobs.phantom.burn-in-daylight", phantomBurnInDaylight);
+ phantomIgnorePlayersWithTorch = getBoolean("mobs.phantom.ignore-players-with-torch", phantomIgnorePlayersWithTorch);
}
public boolean pigRidable = false;

View File

@@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: draycia <lonelyyordle@gmail.com>
Date: Tue, 31 Mar 2020 23:48:55 -0700
Subject: [PATCH] Configurable villager breeding
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index f5a24c2be1c9c4148594130107981ad7434bb835..c942bcedcfb260141589465105091c67d6e762c9 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -751,7 +751,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
@Override
public boolean canBreed() {
- return this.foodLevel + this.countFoodPointsInInventory() >= 12 && this.getAge() == 0;
+ return level.purpurConfig.villagerCanBreed && this.foodLevel + this.countFoodPointsInInventory() >= 12 && this.getAge() == 0;
}
private boolean hungry() {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index f06fb11df26f7a7e3fdb1f7ce21aa67e3ed5a07d..970fee2f23d79ca702e6e2ca22afac434945cf9f 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1432,6 +1432,7 @@ public class PurpurWorldConfig {
public boolean villagerCanBeLeashed = false;
public int villagerSpawnIronGolemRadius = 0;
public int villagerSpawnIronGolemLimit = 0;
+ public boolean villagerCanBreed = true;
private void villagerSettings() {
villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable);
villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater);
@@ -1447,6 +1448,7 @@ public class PurpurWorldConfig {
villagerCanBeLeashed = getBoolean("mobs.villager.can-be-leashed", villagerCanBeLeashed);
villagerSpawnIronGolemRadius = getInt("mobs.villager.spawn-iron-golem.radius", villagerSpawnIronGolemRadius);
villagerSpawnIronGolemLimit = getInt("mobs.villager.spawn-iron-golem.limit", villagerSpawnIronGolemLimit);
+ villagerCanBreed = getBoolean("mobs.villager.can-breed", villagerCanBreed);
}
public boolean vindicatorRidable = false;

View File

@@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: draycia <lonelyyordle@gmail.com>
Date: Tue, 14 Apr 2020 00:35:12 -0700
Subject: [PATCH] Redstone deactivates spawners
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
index 569cef8fcb1e3e1e8b66dad4fa9b956b44542bf1..53a4faa154e1da8dc37b2adec1a5b74c2e1de4b9 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -78,6 +78,7 @@ public abstract class BaseSpawner {
}
public boolean isNearPlayer(Level world, BlockPos pos) { // Paper private->public
+ if (world.purpurConfig.spawnerDeactivateByRedstone && world.hasNeighborSignal(pos)) return false; // Purpur
return world.isAffectsSpawningPlayerNearby((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange); // Paper
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 970fee2f23d79ca702e6e2ca22afac434945cf9f..932dc1b97ae84244f1c8fd8e9c49b655a0c8b62c 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -366,6 +366,11 @@ public class PurpurWorldConfig {
signRightClickEdit = getBoolean("blocks.sign.right-click-edit", signRightClickEdit);
}
+ public boolean spawnerDeactivateByRedstone = false;
+ private void spawnerSettings() {
+ spawnerDeactivateByRedstone = getBoolean("blocks.spawner.deactivate-by-redstone", spawnerDeactivateByRedstone);
+ }
+
public boolean babiesAreRidable = true;
public boolean untamedTamablesAreRidable = true;
public boolean useNightVisionWhenRiding = false;

View File

@@ -0,0 +1,50 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: draycia <lonelyyordle@gmail.com>
Date: Wed, 29 Apr 2020 00:45:58 -0700
Subject: [PATCH] Totems work in inventory
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 63936445bc9005c11bbe669e29897786963e7626..f23b12206e762a52879ba800353638b536e3a2f1 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1517,6 +1517,19 @@ public abstract class LivingEntity extends Entity {
}
}
+ // Purpur start
+ if (level.purpurConfig.totemOfUndyingWorksInInventory && this instanceof ServerPlayer && (itemstack == null || itemstack.getItem() != Items.TOTEM_OF_UNDYING)) {
+ ServerPlayer player = (ServerPlayer) this;
+ for (ItemStack item : player.getInventory().items) {
+ if (item.getItem() == Items.TOTEM_OF_UNDYING) {
+ itemstack1 = item;
+ itemstack = item.cloneItemStack(false);
+ break;
+ }
+ }
+ }
+ // Purpur end
+
EntityResurrectEvent event = new EntityResurrectEvent((org.bukkit.entity.LivingEntity) this.getBukkitEntity());
event.setCancelled(itemstack == null);
this.level.getCraftServer().getPluginManager().callEvent(event);
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 932dc1b97ae84244f1c8fd8e9c49b655a0c8b62c..88cb60050442a757fb94fa050c4d9a073f197e85 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -232,6 +232,7 @@ public class PurpurWorldConfig {
public String playerDeathExpDropEquation = "expLevel * 7";
public int playerDeathExpDropMax = 100;
public boolean teleportIfOutsideBorder = false;
+ public boolean totemOfUndyingWorksInInventory = false;
private void playerSettings() {
if (PurpurConfig.version < 19) {
boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer);
@@ -248,6 +249,7 @@ public class PurpurWorldConfig {
playerDeathExpDropEquation = getString("gameplay-mechanics.player.exp-dropped-on-death.equation", playerDeathExpDropEquation);
playerDeathExpDropMax = getInt("gameplay-mechanics.player.exp-dropped-on-death.maximum", playerDeathExpDropMax);
teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder);
+ totemOfUndyingWorksInInventory = getBoolean("gameplay-mechanics.player.totem-of-undying-works-in-inventory", totemOfUndyingWorksInInventory);
}
public boolean silkTouchEnabled = false;

View File

@@ -0,0 +1,51 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Fri, 24 Jul 2020 19:38:21 -0500
Subject: [PATCH] Add vindicator johnny spawn chance
diff --git a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java
index 9b4a20a78f24d4b05fefbf2a7d05686ef9cc8adb..f65a997db7ee0d8e06dfe7cf41dd2231e67b1a2f 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java
@@ -7,6 +7,7 @@ import java.util.function.Predicate;
import javax.annotation.Nullable;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
@@ -147,6 +148,12 @@ public class Vindicator extends AbstractIllager {
((GroundPathNavigation)this.getNavigation()).setCanOpenDoors(true);
this.populateDefaultEquipmentSlots(difficulty);
this.populateDefaultEquipmentEnchantments(difficulty);
+ // Purpur start
+ Level level = world.getMinecraftWorld();
+ if (level.purpurConfig.vindicatorJohnnySpawnChance > 0D && random.nextDouble() <= level.purpurConfig.vindicatorJohnnySpawnChance) {
+ setCustomName(new TranslatableComponent("Johnny"));
+ }
+ // Purpur end
return spawnGroupData;
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 88cb60050442a757fb94fa050c4d9a073f197e85..73f0ba30c099a2d32111cfde8e100092f6885304 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1461,6 +1461,7 @@ public class PurpurWorldConfig {
public boolean vindicatorRidable = false;
public boolean vindicatorRidableInWater = false;
public double vindicatorMaxHealth = 24.0D;
+ public double vindicatorJohnnySpawnChance = 0D;
private void vindicatorSettings() {
vindicatorRidable = getBoolean("mobs.vindicator.ridable", vindicatorRidable);
vindicatorRidableInWater = getBoolean("mobs.vindicator.ridable-in-water", vindicatorRidableInWater);
@@ -1470,6 +1471,7 @@ public class PurpurWorldConfig {
set("mobs.vindicator.attributes.max_health", oldValue);
}
vindicatorMaxHealth = getDouble("mobs.vindicator.attributes.max_health", vindicatorMaxHealth);
+ vindicatorJohnnySpawnChance = getDouble("mobs.vindicator.johnny.spawn-chance", vindicatorJohnnySpawnChance);
}
public boolean wanderingTraderRidable = false;

View File

@@ -0,0 +1,146 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Tue, 4 Aug 2020 17:11:58 -0500
Subject: [PATCH] Add option to disable certain block updates
diff --git a/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java b/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java
index bdd3369ac1b5386642d706921e5b2c94450ae96b..3ce2146099ca55b1ac96c02fdb95712a0becf43f 100644
--- a/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java
@@ -21,6 +21,7 @@ public class ChorusPlantBlock extends PipeBlock {
@Override
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
+ if (net.pl3x.purpur.PurpurConfig.disableChorusPlantUpdates) return this.defaultBlockState(); // Purpur
return this.getStateForPlacement(ctx.getLevel(), ctx.getClickedPos());
}
@@ -36,6 +37,7 @@ public class ChorusPlantBlock extends PipeBlock {
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
+ if (net.pl3x.purpur.PurpurConfig.disableChorusPlantUpdates) return state; // Purpur
if (!state.canSurvive(world, pos)) {
world.getBlockTicks().scheduleTick(pos, this, 1);
return super.updateShape(state, direction, neighborState, world, pos, neighborPos);
diff --git a/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java b/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java
index 3c6d97b51c6fec130b80e5965afa2c49d48843c9..174d16ae5c45dd3a4c9b4cc58b36121bef38d9cc 100644
--- a/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java
@@ -22,29 +22,65 @@ public class HugeMushroomBlock extends Block {
public HugeMushroomBlock(BlockBehaviour.Properties settings) {
super(settings);
- this.registerDefaultState(this.stateDefinition.any().setValue(NORTH, Boolean.valueOf(true)).setValue(EAST, Boolean.valueOf(true)).setValue(SOUTH, Boolean.valueOf(true)).setValue(WEST, Boolean.valueOf(true)).setValue(UP, Boolean.valueOf(true)).setValue(DOWN, Boolean.valueOf(true)));
+ // Purpur start
+ this.registerDefaultState(this.stateDefinition.any()
+ .setValue(NORTH, true)
+ .setValue(EAST, true)
+ .setValue(SOUTH, true)
+ .setValue(WEST, true)
+ .setValue(UP, true)
+ .setValue(DOWN, true));
+ // Purpur end
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
+ if (net.pl3x.purpur.PurpurConfig.disableMushroomBlockUpdates) return this.defaultBlockState(); // Purpur
BlockGetter blockGetter = ctx.getLevel();
BlockPos blockPos = ctx.getClickedPos();
- return this.defaultBlockState().setValue(DOWN, Boolean.valueOf(!blockGetter.getBlockState(blockPos.below()).is(this))).setValue(UP, Boolean.valueOf(!blockGetter.getBlockState(blockPos.above()).is(this))).setValue(NORTH, Boolean.valueOf(!blockGetter.getBlockState(blockPos.north()).is(this))).setValue(EAST, Boolean.valueOf(!blockGetter.getBlockState(blockPos.east()).is(this))).setValue(SOUTH, Boolean.valueOf(!blockGetter.getBlockState(blockPos.south()).is(this))).setValue(WEST, Boolean.valueOf(!blockGetter.getBlockState(blockPos.west()).is(this)));
+ // Purpur start
+ return this.defaultBlockState()
+ .setValue(DOWN, this != blockGetter.getTypeIfLoaded(blockPos.below()).getBlock())
+ .setValue(UP, this != blockGetter.getTypeIfLoaded(blockPos.above()).getBlock())
+ .setValue(NORTH, this != blockGetter.getTypeIfLoaded(blockPos.north()).getBlock())
+ .setValue(EAST, this != blockGetter.getTypeIfLoaded(blockPos.east()).getBlock())
+ .setValue(SOUTH, this != blockGetter.getTypeIfLoaded(blockPos.south()).getBlock())
+ .setValue(WEST, this != blockGetter.getTypeIfLoaded(blockPos.west()).getBlock());
+ // Purpur end
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
+ if (net.pl3x.purpur.PurpurConfig.disableMushroomBlockUpdates) return state; // Purpur
return neighborState.is(this) ? state.setValue(PROPERTY_BY_DIRECTION.get(direction), Boolean.valueOf(false)) : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
}
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
- return state.setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.NORTH)), state.getValue(NORTH)).setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.SOUTH)), state.getValue(SOUTH)).setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.EAST)), state.getValue(EAST)).setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.WEST)), state.getValue(WEST)).setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.UP)), state.getValue(UP)).setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.DOWN)), state.getValue(DOWN));
+ // Purpur start
+ if (net.pl3x.purpur.PurpurConfig.disableMushroomBlockUpdates) return state;
+ return state
+ .setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.NORTH)), state.getValue(NORTH))
+ .setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.SOUTH)), state.getValue(SOUTH))
+ .setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.EAST)), state.getValue(EAST))
+ .setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.WEST)), state.getValue(NORTH))
+ .setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.UP)), state.getValue(UP))
+ .setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.DOWN)), state.getValue(DOWN));
+ // Purpur end
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
- return state.setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.NORTH)), state.getValue(NORTH)).setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.SOUTH)), state.getValue(SOUTH)).setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.EAST)), state.getValue(EAST)).setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.WEST)), state.getValue(WEST)).setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.UP)), state.getValue(UP)).setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.DOWN)), state.getValue(DOWN));
+ // Purpur start
+ if (net.pl3x.purpur.PurpurConfig.disableMushroomBlockUpdates) return state;
+ return state
+ .setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.NORTH)), state.getValue(NORTH))
+ .setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.SOUTH)), state.getValue(SOUTH))
+ .setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.EAST)), state.getValue(EAST))
+ .setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.WEST)), state.getValue(NORTH))
+ .setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.UP)), state.getValue(UP))
+ .setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.DOWN)), state.getValue(DOWN));
+ // Purpur end
}
@Override
diff --git a/src/main/java/net/minecraft/world/level/block/NoteBlock.java b/src/main/java/net/minecraft/world/level/block/NoteBlock.java
index f8e58d9f71703139a736d93e7f1996e027a29444..59ae3bb34678cdb5241f691915c96d6568363d3b 100644
--- a/src/main/java/net/minecraft/world/level/block/NoteBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/NoteBlock.java
@@ -35,11 +35,13 @@ public class NoteBlock extends Block {
@Override
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
+ if (net.pl3x.purpur.PurpurConfig.disableNoteBlockUpdates) return this.defaultBlockState(); // Purpur
return (BlockState) this.defaultBlockState().setValue(NoteBlock.INSTRUMENT, NoteBlockInstrument.byState(ctx.getLevel().getBlockState(ctx.getClickedPos().below())));
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
+ if (net.pl3x.purpur.PurpurConfig.disableNoteBlockUpdates) return this.defaultBlockState(); // Purpur
return direction == Direction.DOWN ? (BlockState) state.setValue(NoteBlock.INSTRUMENT, NoteBlockInstrument.byState(neighborState)) : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
}
@@ -53,6 +55,7 @@ public class NoteBlock extends Block {
state = world.getBlockState(pos); // CraftBukkit - SPIGOT-5617: update in case changed in event
}
+ if (!net.pl3x.purpur.PurpurConfig.disableNoteBlockUpdates) // Purpur
world.setBlock(pos, (BlockState) state.setValue(NoteBlock.POWERED, flag1), 3);
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index b2b7d0a89a6a0d3482caea8fcad1d46de7e4b8ee..c55f0be5437f36d42dacb2e61efcecac3cf379ee 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -249,6 +249,15 @@ public class PurpurConfig {
allowWaterPlacementInTheEnd = getBoolean("settings.allow-water-placement-in-the-end", allowWaterPlacementInTheEnd);
}
+ public static boolean disableMushroomBlockUpdates = false;
+ public static boolean disableNoteBlockUpdates = false;
+ public static boolean disableChorusPlantUpdates = false;
+ private static void blockUpdatesSettings() {
+ disableMushroomBlockUpdates = getBoolean("settings.blocks.disable-mushroom-updates", disableMushroomBlockUpdates);
+ disableNoteBlockUpdates = getBoolean("settings.blocks.disable-note-block-updates", disableNoteBlockUpdates);
+ disableChorusPlantUpdates = getBoolean("settings.blocks.disable-chorus-plant-updates", disableChorusPlantUpdates);
+ }
+
public static boolean loggerSuppressInitLegacyMaterialError = false;
public static boolean loggerSuppressIgnoredAdvancementWarnings = false;
public static boolean loggerSuppressUnrecognizedRecipeErrors = false;

View File

@@ -0,0 +1,57 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Tue, 4 Aug 2020 21:11:03 -0500
Subject: [PATCH] Dispensers place anvils option
diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
index 915c68888963b879bf74dc67cc6ffb174228f9e4..c507e60a4836d9cfa5e076841b9b7375ea9ac997 100644
--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
@@ -53,6 +53,7 @@ import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
+import net.minecraft.world.level.block.AnvilBlock;
import net.minecraft.world.level.block.BaseFireBlock;
import net.minecraft.world.level.block.BeehiveBlock;
import net.minecraft.world.level.block.Block;
@@ -1110,6 +1111,23 @@ public interface DispenseItemBehavior {
}
}
}));
+ // Purpur start
+ DispenserBlock.registerBehavior(Items.ANVIL, (new OptionalDispenseItemBehavior() {
+ @Override
+ public ItemStack execute(BlockSource dispenser, ItemStack stack) {
+ Level level = dispenser.getLevel();
+ if (!level.purpurConfig.dispenserPlaceAnvils) return super.execute(dispenser, stack);
+ Direction facing = dispenser.getBlockState().getValue(DispenserBlock.FACING);
+ BlockPos pos = dispenser.getPos().relative(facing);
+ BlockState state = level.getBlockState(pos);
+ if (state.isAir()) {
+ level.setBlockAndUpdate(pos, Blocks.ANVIL.defaultBlockState().setValue(AnvilBlock.FACING, facing.getAxis() == Direction.Axis.Y ? Direction.NORTH : facing.getClockWise()));
+ stack.shrink(1);
+ }
+ return stack;
+ }
+ }));
+ // Purpur end
}
static void setEntityPokingOutOfBlock(BlockSource pointer, Entity entity, Direction direction) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 73f0ba30c099a2d32111cfde8e100092f6885304..3b56a3668d417890c5233c04f15dda9499e8265d 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -318,8 +318,10 @@ public class PurpurWorldConfig {
}
public boolean dispenserApplyCursedArmor = true;
+ public boolean dispenserPlaceAnvils = false;
private void dispenserSettings() {
dispenserApplyCursedArmor = getBoolean("blocks.dispenser.apply-cursed-to-armor-slots", dispenserApplyCursedArmor);
+ dispenserPlaceAnvils = getBoolean("blocks.dispenser.place-anvils", dispenserPlaceAnvils);
}
public boolean farmlandGetsMoistFromBelow = false;

View File

@@ -0,0 +1,54 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Tue, 4 Aug 2020 22:08:23 -0500
Subject: [PATCH] Allow anvil colors
diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
index ca8dd8b7f7bf8826472f11cb9472cf84c0368f34..1d3534589e1977c14e01e29c5570fe0ec0ee0a88 100644
--- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
@@ -2,6 +2,9 @@ package net.minecraft.world.inventory;
import java.util.Iterator;
import java.util.Map;
+
+import io.papermc.paper.adventure.PaperAdventure;
+import net.kyori.adventure.text.format.TextDecoration;
import net.minecraft.nbt.IntTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
@@ -277,6 +280,17 @@ public class AnvilMenu extends ItemCombinerMenu {
} else if (!this.itemName.equals(itemstack.getHoverName().getString())) {
b1 = 1;
i += b1;
+ // Purpur start
+ if (player != null && player.level.purpurConfig.anvilAllowColors && player.getBukkitEntity().hasPermission("purpur.anvil.color")) {
+ final net.kyori.adventure.text.Component renameTextComponent;
+ if (itemName.startsWith("&r") && player.getBukkitEntity().hasPermission("purpur.anvil.remove_italics")) {
+ renameTextComponent = PaperAdventure.LEGACY_AMPERSAND.deserialize(itemName.substring(2)).decoration(TextDecoration.ITALIC, false);
+ } else {
+ renameTextComponent = PaperAdventure.LEGACY_AMPERSAND.deserialize(itemName);
+ }
+ itemstack1.setHoverName(PaperAdventure.asVanilla(renameTextComponent));
+ } else
+ // Purpur end
itemstack1.setHoverName((Component) (new TextComponent(this.itemName)));
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 3b56a3668d417890c5233c04f15dda9499e8265d..730abc3bc780ccbd22b9e8c33a2ea894f53f13ee 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -301,6 +301,11 @@ public class PurpurWorldConfig {
voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt);
}
+ public boolean anvilAllowColors = false;
+ private void anvilSettings() {
+ anvilAllowColors = getBoolean("blocks.anvil.allow-colors", anvilAllowColors);
+ }
+
public boolean bedExplode = true;
public double bedExplosionPower = 5.0D;
public boolean bedExplosionFire = true;

View File

@@ -0,0 +1,69 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Fri, 7 Aug 2020 12:53:36 -0500
Subject: [PATCH] Add no-random-tick block list
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 168caca104d6ee4b4cca6dde973166d8e47a29ba..2acd254df2f16c4f8d95cb240d62033e9ebc67bf 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -482,7 +482,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
this.players = Lists.newArrayList();
this.entityTickList = new EntityTickList();
Predicate<Block> predicate = (block) -> { // CraftBukkit - decompile eror
- return block == null || block.defaultBlockState().isAir();
+ return block == null || block.defaultBlockState().isAir() || purpurConfig.noRandomTickBlocks.contains(block); // Purpur
};
DefaultedRegistry registryblocks = Registry.BLOCK;
diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
index 8a6fdccb7db4234d9557f3b63f7761feb15bbed7..a2a4145b2ec826e09ad359700031583297d6612d 100644
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
@@ -914,10 +914,12 @@ public abstract class BlockBehaviour {
}
public void tick(ServerLevel world, BlockPos pos, Random random) {
+ if (world.purpurConfig.noRandomTickBlocks.contains(getBlock())) return; // Purpur
this.getBlock().tick(this.asState(), world, pos, random);
}
public void randomTick(ServerLevel world, BlockPos pos, Random random) {
+ if (world.purpurConfig.noRandomTickBlocks.contains(getBlock())) return; // Purpur
this.getBlock().randomTick(this.asState(), world, pos, random);
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 730abc3bc780ccbd22b9e8c33a2ea894f53f13ee..56b5ddbab362d2c6bd9402211d30e01b94b2e891 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -301,6 +301,28 @@ public class PurpurWorldConfig {
voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt);
}
+ public Set<Block> noRandomTickBlocks = new HashSet<>();
+ private void noRandomTickBlocks() {
+ if (PurpurConfig.version < 11) {
+ List<String> oldList = PurpurConfig.config.getStringList("world-settings." + worldName + ".blocks.no-tick");
+ if (!oldList.isEmpty()) {
+ PurpurConfig.config.set("world-settings." + worldName + ".blocks.no-random-tick", oldList);
+ PurpurConfig.config.set("world-settings." + worldName + ".blocks.no-tick", null);
+ }
+ oldList = PurpurConfig.config.getStringList("world-settings.default.blocks.no-tick");
+ if (!oldList.isEmpty()) {
+ PurpurConfig.config.set("world-settings.default.blocks.no-random-tick", oldList);
+ PurpurConfig.config.set("world-settings.default.blocks.no-tick", null);
+ }
+ }
+ getList("blocks.no-random-tick", new ArrayList<>()).forEach(key -> {
+ Block block = Registry.BLOCK.get(new ResourceLocation(key.toString()));
+ if (!block.defaultBlockState().isAir()) {
+ noRandomTickBlocks.add(block);
+ }
+ });
+ }
+
public boolean anvilAllowColors = false;
private void anvilSettings() {
anvilAllowColors = getBoolean("blocks.anvil.allow-colors", anvilAllowColors);

View File

@@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Sat, 8 Aug 2020 16:11:51 -0500
Subject: [PATCH] Add option to disable dolphin treasure searching
diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java
index 855ab63797baf825eeaddb4892cbe8430d47da0f..cc20ed6e1746f47351eb9b40f7b3c1a11daebd4f 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java
@@ -497,6 +497,7 @@ public class Dolphin extends WaterAnimal {
@Override
public boolean canUse() {
+ if (this.dolphin.level.purpurConfig.dolphinDisableTreasureSearching) return false; // Purpur
return this.dolphin.gotFish() && this.dolphin.getAirSupply() >= 100 && this.dolphin.level.getWorld().canGenerateStructures(); // MC-151364, SPIGOT-5494: hangs if generate-structures=false
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 56b5ddbab362d2c6bd9402211d30e01b94b2e891..6d1c934cb11de4a2c5c92e058f0118de4da3e2f1 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -574,6 +574,7 @@ public class PurpurWorldConfig {
public float dolphinSpitSpeed = 1.0F;
public float dolphinSpitDamage = 2.0F;
public double dolphinMaxHealth = 10.0D;
+ public boolean dolphinDisableTreasureSearching = false;
private void dolphinSettings() {
dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable);
dolphinSpitCooldown = getInt("mobs.dolphin.spit.cooldown", dolphinSpitCooldown);
@@ -585,6 +586,7 @@ public class PurpurWorldConfig {
set("mobs.dolphin.attributes.max_health", oldValue);
}
dolphinMaxHealth = getDouble("mobs.dolphin.attributes.max_health", dolphinMaxHealth);
+ dolphinDisableTreasureSearching = getBoolean("mobs.dolphin.disable-treasure-searching", dolphinDisableTreasureSearching);
}
public boolean donkeyRidableInWater = false;

View File

@@ -0,0 +1,49 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Mon, 10 Aug 2020 21:46:22 -0500
Subject: [PATCH] Short enderman height
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
index 3aeeba4465a5ff551a56ac50e23036074f9315c3..06feb2e4729bf188c783d1b105d02bc41af4263c 100644
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
@@ -280,7 +280,8 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T> {
private Component description;
@Nullable
private ResourceLocation lootTable;
- private final EntityDimensions dimensions;
+ private EntityDimensions dimensions; // Purpur - remove final
+ public void setDimensions(EntityDimensions dimensions) { this.dimensions = dimensions; } // Purpur
private static <T extends Entity> EntityType<T> register(String id, EntityType.Builder type) { // CraftBukkit - decompile error
return (EntityType) Registry.register((Registry) Registry.ENTITY_TYPE, id, (Object) type.build(id));
diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
index ec772f1ec312c3e51287d86eb2023cee80e55d7b..b9f8969cbe24661a5fa5fb4b46fdd159b76005cc 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
@@ -393,6 +393,7 @@ public class EnderMan extends Monster implements NeutralMob {
if (this.isInvulnerableTo(source)) {
return false;
} else if (getRider() != null) { return super.hurt(source, amount); // Purpur - no teleporting on damage
+ } else if (net.pl3x.purpur.PurpurConfig.endermanShortHeight && source == DamageSource.IN_WALL) { return false; // Purpur - no suffocation damage if short height
} else if (source instanceof IndirectEntityDamageSource) {
if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper start
for (int i = 0; i < 64; ++i) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index c55f0be5437f36d42dacb2e61efcecac3cf379ee..ee78e74edb95f29c42ae94e733fd44043191206e 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -239,6 +239,12 @@ public class PurpurConfig {
enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows);
}
+ public static boolean endermanShortHeight = false;
+ private static void entitySettings() {
+ endermanShortHeight = getBoolean("settings.entity.enderman.short-height", endermanShortHeight);
+ if (endermanShortHeight) EntityType.ENDERMAN.setDimensions(EntityDimensions.scalable(0.6F, 1.9F));
+ }
+
public static boolean dontSendUselessEntityPackets = false;
private static void dontSendUselessEntityPackets() {
dontSendUselessEntityPackets = getBoolean("settings.dont-send-useless-entity-packets", dontSendUselessEntityPackets);

View File

@@ -0,0 +1,75 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Thu, 13 Aug 2020 04:00:26 -0500
Subject: [PATCH] Stop squids floating on top of water
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 87b9812c7c879403792c9a5a91366af7a63bc683..49c622253d70c8a3e60881d91cf09085458eebcf 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -3881,6 +3881,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
this.yRotO = this.getYRot();
}
+ // Purpur start
+ public AABB getAxisForFluidCheck() {
+ return this.getBoundingBox().deflate(0.001D);
+ }
+ // Purpur end
+
public boolean updateFluidHeightAndDoFluidPushing(Tag<Fluid> tag, double d0) {
if (this.touchingUnloadedChunk()) {
return false;
diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java
index 8f0583a32156b5dcfe0eb6351ce6a0ce341d1e13..af13adb96a083c83b7b847770a85e32bd0eafa4b 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Squid.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java
@@ -79,6 +79,12 @@ public class Squid extends WaterAnimal {
public void initAttributes() {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level.purpurConfig.squidMaxHealth);
}
+
+ @Override
+ public net.minecraft.world.phys.AABB getAxisForFluidCheck() {
+ // Stops squids from floating just over the water
+ return super.getAxisForFluidCheck().offsetY(level.purpurConfig.squidOffsetWaterCheck);
+ }
// Purpur end
@Override
diff --git a/src/main/java/net/minecraft/world/phys/AABB.java b/src/main/java/net/minecraft/world/phys/AABB.java
index 68cc6f2a78a06293a29317fda72ab3ee79b3533a..cfb2e46b34b2982d6724f18214557fc80cf4adfa 100644
--- a/src/main/java/net/minecraft/world/phys/AABB.java
+++ b/src/main/java/net/minecraft/world/phys/AABB.java
@@ -367,4 +367,10 @@ public class AABB {
public static AABB ofSize(Vec3 center, double dx, double dy, double dz) {
return new AABB(center.x - dx / 2.0D, center.y - dy / 2.0D, center.z - dz / 2.0D, center.x + dx / 2.0D, center.y + dy / 2.0D, center.z + dz / 2.0D);
}
+
+ // Purpur - tuinity added method
+ public final AABB offsetY(double dy) {
+ return new AABB(this.minX, this.minY + dy, this.minZ, this.maxX, this.maxY + dy, this.maxZ);
+ }
+ // Purpur
}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 6d1c934cb11de4a2c5c92e058f0118de4da3e2f1..99e55295b4ad0128e427d0014b9f8fbbfa819954 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1334,6 +1334,7 @@ public class PurpurWorldConfig {
public boolean squidRidable = false;
public double squidMaxHealth = 10.0D;
public boolean squidImmuneToEAR = true;
+ public double squidOffsetWaterCheck = 0.0D;
private void squidSettings() {
squidRidable = getBoolean("mobs.squid.ridable", squidRidable);
if (PurpurConfig.version < 10) {
@@ -1343,6 +1344,7 @@ public class PurpurWorldConfig {
}
squidMaxHealth = getDouble("mobs.squid.attributes.max_health", squidMaxHealth);
squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR);
+ squidOffsetWaterCheck = getDouble("mobs.squid.water-offset-check", squidOffsetWaterCheck);
}
public boolean spiderRidable = false;

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Sat, 15 Aug 2020 06:51:46 -0500
Subject: [PATCH] Use configured height for nether surface builders
diff --git a/src/main/java/net/minecraft/world/level/levelgen/surfacebuilders/NetherCappedSurfaceBuilder.java b/src/main/java/net/minecraft/world/level/levelgen/surfacebuilders/NetherCappedSurfaceBuilder.java
index cdfbdb411eacf5f8c6ced2dbc5789e0d49b93e1f..e4013f241a5e9aeb334dadde8b55c7e6ca32233c 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/surfacebuilders/NetherCappedSurfaceBuilder.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/surfacebuilders/NetherCappedSurfaceBuilder.java
@@ -40,7 +40,7 @@ public abstract class NetherCappedSurfaceBuilder extends SurfaceBuilder<SurfaceB
return entry.getValue().getValue((double)x, (double)seaLevel, (double)z);
})).get().getKey();
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
- BlockState blockState3 = chunk.getBlockState(mutableBlockPos.set(k, 128, m));
+ BlockState blockState3 = chunk.getBlockState(mutableBlockPos.set(k, height, m)); // Purpur - use configured height
for(int p = height; p >= i; --p) { // Paper - fix MC-187716 - use configured height
mutableBlockPos.set(k, p, m);

View File

@@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Mon, 17 Aug 2020 17:34:33 -0500
Subject: [PATCH] Crying obsidian valid for portal frames
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalShape.java b/src/main/java/net/minecraft/world/level/portal/PortalShape.java
index d3ae4835b53071e92fe9613cd92907e232e71ba0..153ed3b6e5bd5bbbd94e91aa9c71d84156d4a258 100644
--- a/src/main/java/net/minecraft/world/level/portal/PortalShape.java
+++ b/src/main/java/net/minecraft/world/level/portal/PortalShape.java
@@ -31,7 +31,7 @@ public class PortalShape {
private static final int MIN_HEIGHT = 3;
public static final int MAX_HEIGHT = 21;
private static final BlockBehaviour.StatePredicate FRAME = (iblockdata, iblockaccess, blockposition) -> {
- return iblockdata.is(Blocks.OBSIDIAN);
+ return iblockdata.is(Blocks.OBSIDIAN) || (net.pl3x.purpur.PurpurConfig.cryingObsidianValidForPortalFrame && iblockdata.is(Blocks.CRYING_OBSIDIAN)); // Purpur
};
private final LevelAccessor level;
private final Direction.Axis axis;
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index ee78e74edb95f29c42ae94e733fd44043191206e..0af482784c7d9337b16c52ba52962f0380ae43e0 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -207,6 +207,7 @@ public class PurpurConfig {
public static int barrelRows = 3;
public static boolean enderChestSixRows = false;
public static boolean enderChestPermissionRows = false;
+ public static boolean cryingObsidianValidForPortalFrame = false;
private static void blockSettings() {
if (version < 3) {
boolean oldValue = getBoolean("settings.barrel.packed-barrels", true);
@@ -237,6 +238,7 @@ public class PurpurConfig {
enderChestSixRows = getBoolean("settings.blocks.ender_chest.six-rows", enderChestSixRows);
org.bukkit.event.inventory.InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27);
enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows);
+ cryingObsidianValidForPortalFrame = getBoolean("settings.blocks.crying_obsidian.valid-for-portal-frame", cryingObsidianValidForPortalFrame);
}
public static boolean endermanShortHeight = false;

View File

@@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Mon, 17 Aug 2020 19:32:05 -0500
Subject: [PATCH] Entities can use portals configuration
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 49c622253d70c8a3e60881d91cf09085458eebcf..1630e3bcbcd799060b80cdd19ef37ae648425029 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -2719,7 +2719,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
public void handleInsidePortal(BlockPos pos) {
if (this.isOnPortalCooldown()) {
this.setPortalCooldown();
- } else {
+ } else if (level.purpurConfig.entitiesCanUsePortals || this instanceof ServerPlayer) { // Purpur
if (!this.level.isClientSide && !pos.equals(this.portalEntrancePos)) {
this.portalEntrancePos = pos.immutable();
}
@@ -3370,7 +3370,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
}
public boolean canChangeDimensions() {
- return isAlive() && valid; // Paper
+ return isAlive() && valid && (level.purpurConfig.entitiesCanUsePortals || this instanceof ServerPlayer); // Paper // Purpur
}
public float getBlockExplosionResistance(Explosion explosion, BlockGetter world, BlockPos pos, BlockState blockState, FluidState fluidState, float max) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 99e55295b4ad0128e427d0014b9f8fbbfa819954..058e2045b4717ab65fc14097154ee57ad461ce45 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -287,6 +287,7 @@ public class PurpurWorldConfig {
public boolean useBetterMending = false;
public boolean boatEjectPlayersOnLand = false;
public boolean disableDropsOnCrammingDeath = false;
+ public boolean entitiesCanUsePortals = true;
public boolean milkCuresBadOmen = true;
public double tridentLoyaltyVoidReturnHeight = 0.0D;
public double voidDamageHeight = -64.0D;
@@ -295,6 +296,7 @@ public class PurpurWorldConfig {
useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending);
boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand);
disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath);
+ entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals);
milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen);
tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight);
voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight);

View File

@@ -0,0 +1,22 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Mon, 17 Aug 2020 21:50:39 -0500
Subject: [PATCH] LivingEntity#broadcastItemBreak
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index 916d487372efdbf68a383f4ae761cccd75e0a1d8..be1f7cf667b5c9b2e691397bfc2e316b7ba84251 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -931,5 +931,11 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
public void setSafeFallDistance(float safeFallDistance) {
getHandle().safeFallDistance = safeFallDistance;
}
+
+ @Override
+ public void broadcastItemBreak(org.bukkit.inventory.EquipmentSlot slot) {
+ if (slot == null) return;
+ getHandle().broadcastBreakEvent(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot));
+ }
// Purpur end
}

View File

@@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Thu, 20 Aug 2020 17:38:12 -0700
Subject: [PATCH] Customizable wither health and healing
Adds the ability to customize the health of the wither, as well as the amount that it heals, and how often.
diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
index 43de1fa753e54ae09d43a9aef8dda22c27c67b81..ff71f78497681805246d7b3e4ac59288db9af997 100644
--- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
@@ -504,8 +504,10 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob
}
}
- if (this.tickCount % 20 == 0) {
- this.heal(1.0F, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit
+ // Purpur start - customizable heal rate and amount
+ if (this.tickCount % level.purpurConfig.witherHealthRegenDelay == 0) {
+ this.heal(level.purpurConfig.witherHealthRegenAmount, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit
+ // Purpur end
}
this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth());
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 058e2045b4717ab65fc14097154ee57ad461ce45..0f3c9233fb4761a394b301a634373b95949d5c48 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1545,6 +1545,8 @@ public class PurpurWorldConfig {
public boolean witherRidableInWater = false;
public double witherMaxY = 256D;
public double witherMaxHealth = 300.0D;
+ public float witherHealthRegenAmount = 1.0f;
+ public int witherHealthRegenDelay = 20;
private void witherSettings() {
witherRidable = getBoolean("mobs.wither.ridable", witherRidable);
witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater);
@@ -1559,6 +1561,8 @@ public class PurpurWorldConfig {
set("mobs.wither.attributes.max_health", oldValue);
}
witherMaxHealth = getDouble("mobs.wither.attributes.max_health", witherMaxHealth);
+ witherHealthRegenAmount = (float) getDouble("mobs.wither.health-regen-amount", witherHealthRegenAmount);
+ witherHealthRegenDelay = getInt("mobs.wither.health-regen-delay", witherHealthRegenDelay);
}
public boolean witherSkeletonRidable = false;

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