27748 lines
1.4 MiB
27748 lines
1.4 MiB
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: granny <contact@granny.dev>
|
|
Date: Wed, 30 Oct 2024 13:25:10 +0900
|
|
Subject: [PATCH] Purpur Server Changes
|
|
|
|
PurpurMC
|
|
Copyright (C) 2024 PurpurMC
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
|
|
diff --git a/build.gradle.kts b/build.gradle.kts
|
|
index 9b3a6b336cb1344d4e74e0e4f7c50ffd1e1b8955..ccb31eb5993db028d0cbf104261205c9462f8734 100644
|
|
--- a/build.gradle.kts
|
|
+++ b/build.gradle.kts
|
|
@@ -13,7 +13,7 @@ configurations.named(log4jPlugins.compileClasspathConfigurationName) {
|
|
val alsoShade: Configuration by configurations.creating
|
|
|
|
dependencies {
|
|
- implementation(project(":paper-api"))
|
|
+ implementation(project(":purpur-api")) // Pufferfish // Paper // Purpur
|
|
// Paper start
|
|
implementation("org.jline:jline-terminal-jansi:3.21.0")
|
|
implementation("net.minecrell:terminalconsoleappender:1.3.0")
|
|
@@ -47,6 +47,10 @@ dependencies {
|
|
runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18")
|
|
runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18")
|
|
|
|
+ implementation("org.mozilla:rhino-runtime:1.7.14") // Purpur
|
|
+ implementation("org.mozilla:rhino-engine:1.7.14") // Purpur
|
|
+ implementation("dev.omega24:upnp4j:1.0") // Purpur
|
|
+
|
|
testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test
|
|
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
|
|
testImplementation("org.junit.platform:junit-platform-suite-engine:1.10.0")
|
|
@@ -85,14 +89,14 @@ tasks.jar {
|
|
val gitBranch = git("rev-parse", "--abbrev-ref", "HEAD").getText().trim() // Paper
|
|
attributes(
|
|
"Main-Class" to "org.bukkit.craftbukkit.Main",
|
|
- "Implementation-Title" to "Paper",
|
|
+ "Implementation-Title" to "Purpur", // Pufferfish // Purpur
|
|
"Implementation-Version" to implementationVersion,
|
|
"Implementation-Vendor" to date, // Paper
|
|
- "Specification-Title" to "Paper",
|
|
+ "Specification-Title" to "Purpur", // Pufferfish // Purpur
|
|
"Specification-Version" to project.version,
|
|
- "Specification-Vendor" to "Paper Team",
|
|
- "Brand-Id" to "papermc:paper",
|
|
- "Brand-Name" to "Paper",
|
|
+ "Specification-Vendor" to "Purpur Team", // Pufferfish // Purpur
|
|
+ "Brand-Id" to "purpurmc:purpur", // Pufferfish // Purpur
|
|
+ "Brand-Name" to "Purpur", // Pufferfish // Purpur
|
|
"Build-Number" to (build ?: ""),
|
|
"Build-Time" to Instant.now().toString(),
|
|
"Git-Branch" to gitBranch, // Paper
|
|
@@ -153,7 +157,7 @@ fun TaskContainer.registerRunTask(
|
|
name: String,
|
|
block: JavaExec.() -> Unit
|
|
): TaskProvider<JavaExec> = register<JavaExec>(name) {
|
|
- group = "paper"
|
|
+ group = "paperweight" // Purpur
|
|
mainClass.set("org.bukkit.craftbukkit.Main")
|
|
standardInput = System.`in`
|
|
workingDir = rootProject.layout.projectDirectory
|
|
diff --git a/src/log4jPlugins/java/org/purpurmc/purpur/gui/HighlightErrorConverter.java b/src/log4jPlugins/java/org/purpurmc/purpur/gui/HighlightErrorConverter.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..15a226e3854d731f7724025ea3459c8ace07630c
|
|
--- /dev/null
|
|
+++ b/src/log4jPlugins/java/org/purpurmc/purpur/gui/HighlightErrorConverter.java
|
|
@@ -0,0 +1,85 @@
|
|
+package org.purpurmc.purpur.gui.util;
|
|
+
|
|
+import org.apache.logging.log4j.Level;
|
|
+import org.apache.logging.log4j.core.LogEvent;
|
|
+import org.apache.logging.log4j.core.config.Configuration;
|
|
+import org.apache.logging.log4j.core.config.plugins.Plugin;
|
|
+import org.apache.logging.log4j.core.layout.PatternLayout;
|
|
+import org.apache.logging.log4j.core.pattern.ConverterKeys;
|
|
+import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
|
|
+import org.apache.logging.log4j.core.pattern.PatternConverter;
|
|
+import org.apache.logging.log4j.core.pattern.PatternFormatter;
|
|
+import org.apache.logging.log4j.core.pattern.PatternParser;
|
|
+import org.apache.logging.log4j.util.PerformanceSensitive;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+@Plugin(name = "highlightGUIError", category = PatternConverter.CATEGORY)
|
|
+@ConverterKeys({"highlightGUIError"})
|
|
+@PerformanceSensitive("allocation")
|
|
+public final class HighlightErrorConverter extends LogEventPatternConverter {
|
|
+ private static final String ERROR = "\u00A74\u00A7l"; // Bold Red
|
|
+ private static final String WARN = "\u00A7e\u00A7l"; // Bold Yellow
|
|
+
|
|
+ private final List<PatternFormatter> formatters;
|
|
+
|
|
+ private HighlightErrorConverter(List<PatternFormatter> formatters) {
|
|
+ super("highlightGUIError", null);
|
|
+ this.formatters = formatters;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void format(LogEvent event, StringBuilder toAppendTo) {
|
|
+ Level level = event.getLevel();
|
|
+ if (level.isMoreSpecificThan(Level.ERROR)) {
|
|
+ format(ERROR, event, toAppendTo);
|
|
+ return;
|
|
+ } else if (level.isMoreSpecificThan(Level.WARN)) {
|
|
+ format(WARN, event, toAppendTo);
|
|
+ return;
|
|
+ }
|
|
+ for (PatternFormatter formatter : formatters) {
|
|
+ formatter.format(event, toAppendTo);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void format(String style, LogEvent event, StringBuilder toAppendTo) {
|
|
+ int start = toAppendTo.length();
|
|
+ toAppendTo.append(style);
|
|
+ int end = toAppendTo.length();
|
|
+
|
|
+ for (PatternFormatter formatter : formatters) {
|
|
+ formatter.format(event, toAppendTo);
|
|
+ }
|
|
+
|
|
+ if (toAppendTo.length() == end) {
|
|
+ toAppendTo.setLength(start);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean handlesThrowable() {
|
|
+ for (final PatternFormatter formatter : formatters) {
|
|
+ if (formatter.handlesThrowable()) {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ public static HighlightErrorConverter newInstance(Configuration config, String[] options) {
|
|
+ if (options.length != 1) {
|
|
+ LOGGER.error("Incorrect number of options on highlightGUIError. Expected 1 received " + options.length);
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ if (options[0] == null) {
|
|
+ LOGGER.error("No pattern supplied on highlightGUIError");
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ PatternParser parser = PatternLayout.createPatternParser(config);
|
|
+ List<PatternFormatter> formatters = parser.parse(options[0]);
|
|
+ return new HighlightErrorConverter(formatters);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
|
|
index 4b002e8b75d117b726b0de274a76d3596fce015b..8cde30544e14f8fc2dac32966ae3c21f8cf3a551 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/Metrics.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
|
|
@@ -593,7 +593,7 @@ public class Metrics {
|
|
boolean logFailedRequests = config.getBoolean("logFailedRequests", false);
|
|
// Only start Metrics, if it's enabled in the config
|
|
if (config.getBoolean("enabled", true)) {
|
|
- Metrics metrics = new Metrics("Paper", serverUUID, logFailedRequests, Bukkit.getLogger());
|
|
+ Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger()); // Pufferfish // Purpur
|
|
|
|
metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> {
|
|
String minecraftVersion = Bukkit.getVersion();
|
|
@@ -602,16 +602,8 @@ public class Metrics {
|
|
}));
|
|
|
|
metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size()));
|
|
- metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : "offline"));
|
|
- final String paperVersion;
|
|
- final String implVersion = org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion();
|
|
- if (implVersion != null) {
|
|
- final String buildOrHash = implVersion.substring(implVersion.lastIndexOf('-') + 1);
|
|
- paperVersion = "git-Paper-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash);
|
|
- } else {
|
|
- paperVersion = "unknown";
|
|
- }
|
|
- metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> paperVersion));
|
|
+ metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() ? "bungee" : "offline"))); // Purpur
|
|
+ metrics.addCustomChart(new Metrics.SimplePie("purpur_version", () -> (org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() != null) ? org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() : "unknown")); // Purpur
|
|
|
|
metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> {
|
|
Map<String, Map<String, Integer>> map = new HashMap<>();
|
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
|
|
index 532306cacd52579cdf37e4aca25887b1ed3ba6a1..6d36fc6d8e22d9b68dea3830f6ecc8763184c343 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
|
|
@@ -35,7 +35,10 @@ public class PaperVersionFetcher implements VersionFetcher {
|
|
private static final Logger LOGGER = LogUtils.getClassLogger();
|
|
private static final int DISTANCE_ERROR = -1;
|
|
private static final int DISTANCE_UNKNOWN = -2;
|
|
- private static final String DOWNLOAD_PAGE = "https://papermc.io/downloads/paper";
|
|
+ // Purpur start
|
|
+ private static final String DOWNLOAD_PAGE = "https://purpurmc.org/downloads";
|
|
+ private static int distance = DISTANCE_UNKNOWN; public int distance() { return distance; }
|
|
+ // Purpur end
|
|
|
|
@Override
|
|
public long getCacheTime() {
|
|
@@ -49,7 +52,7 @@ public class PaperVersionFetcher implements VersionFetcher {
|
|
if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) {
|
|
updateMessage = text("You are running a development version without access to version information", color(0xFF5300));
|
|
} else {
|
|
- updateMessage = getUpdateStatusMessage("PaperMC/Paper", build);
|
|
+ updateMessage = getUpdateStatusMessage("PurpurMC/Purpur", build); // Purpur
|
|
}
|
|
final @Nullable Component history = this.getHistory();
|
|
|
|
@@ -57,7 +60,7 @@ public class PaperVersionFetcher implements VersionFetcher {
|
|
}
|
|
|
|
private static Component getUpdateStatusMessage(final String repo, final ServerBuildInfo build) {
|
|
- int distance = DISTANCE_ERROR;
|
|
+ //int distance = DISTANCE_ERROR; // Purpur - use field
|
|
|
|
final OptionalInt buildNumber = build.buildNumber();
|
|
if (buildNumber.isPresent()) {
|
|
@@ -71,10 +74,10 @@ public class PaperVersionFetcher implements VersionFetcher {
|
|
}
|
|
|
|
return switch (distance) {
|
|
- case DISTANCE_ERROR -> text("Error obtaining version information", NamedTextColor.YELLOW);
|
|
- case 0 -> text("You are running the latest version", NamedTextColor.GREEN);
|
|
- case DISTANCE_UNKNOWN -> text("Unknown version", NamedTextColor.YELLOW);
|
|
- default -> text("You are " + distance + " version(s) behind", NamedTextColor.YELLOW)
|
|
+ case DISTANCE_ERROR -> text("* Error obtaining version information", NamedTextColor.RED); // Purpur
|
|
+ case 0 -> text("* You are running the latest version", NamedTextColor.GREEN); // Purpur
|
|
+ case DISTANCE_UNKNOWN -> text("* Unknown version", NamedTextColor.YELLOW); // Purpur
|
|
+ default -> text("* You are " + distance + " version(s) behind", NamedTextColor.YELLOW) // Purpur
|
|
.append(Component.newline())
|
|
.append(text("Download the new version at: ")
|
|
.append(text(DOWNLOAD_PAGE, NamedTextColor.GOLD)
|
|
@@ -86,18 +89,15 @@ public class PaperVersionFetcher implements VersionFetcher {
|
|
private static int fetchDistanceFromSiteApi(final ServerBuildInfo build, final int jenkinsBuild) {
|
|
try {
|
|
try (final BufferedReader reader = Resources.asCharSource(
|
|
- URI.create("https://api.papermc.io/v2/projects/paper/versions/" + build.minecraftVersionId()).toURL(),
|
|
+ URI.create("https://api.purpurmc.org/v2/purpur/" + build.minecraftVersionId()).toURL(), // Purpur
|
|
Charsets.UTF_8
|
|
).openBufferedStream()) {
|
|
final JsonObject json = new Gson().fromJson(reader, JsonObject.class);
|
|
- final JsonArray builds = json.getAsJsonArray("builds");
|
|
- final int latest = StreamSupport.stream(builds.spliterator(), false)
|
|
- .mapToInt(JsonElement::getAsInt)
|
|
- .max()
|
|
- .orElseThrow();
|
|
+ //final JsonArray builds = json.getAsJsonArray("builds"); // Purpur
|
|
+ final int latest = json.getAsJsonObject("builds").getAsJsonPrimitive("latest").getAsInt(); // Purpur
|
|
return latest - jenkinsBuild;
|
|
} catch (final JsonSyntaxException ex) {
|
|
- LOGGER.error("Error parsing json from Paper's downloads API", ex);
|
|
+ LOGGER.error("Error parsing json from Purpur's downloads API", ex); // Purpur
|
|
return DISTANCE_ERROR;
|
|
}
|
|
} catch (final IOException e) {
|
|
@@ -141,6 +141,6 @@ public class PaperVersionFetcher implements VersionFetcher {
|
|
return null;
|
|
}
|
|
|
|
- return text("Previous version: " + oldVersion, NamedTextColor.GRAY, TextDecoration.ITALIC);
|
|
+ return text("Previous: " + oldVersion, NamedTextColor.GRAY); // Purpur
|
|
}
|
|
}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
|
|
index 6ee39b534b8d992655bc0cef3c299d12cbae0034..90b3526479320064378f2cde6c2f2b8e48a59ba6 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
|
|
@@ -20,7 +20,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/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java
|
|
index 3470720466fc81f977c18e3a97bb918926025a22..c8651af322927c46d075f88890fcd0476bd85440 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java
|
|
@@ -136,6 +136,10 @@ public class MobGoalHelper {
|
|
static {
|
|
// TODO these kinda should be checked on each release, in case obfuscation changes
|
|
deobfuscationMap.put("abstract_skeleton_1", "abstract_skeleton_melee");
|
|
+ // Purpur start
|
|
+ deobfuscationMap.put("zombie_1", "zombie_attack_villager");
|
|
+ deobfuscationMap.put("drowned_1", "drowned_attack_villager");
|
|
+ // Purpur end
|
|
|
|
ignored.add("goal_selector_1");
|
|
ignored.add("goal_selector_2");
|
|
diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
|
|
index 12b327eea95e0de9e9c39b7d039badee8ec46508..849ecc5af70901f1e40cb6c419f33f1cf6f3b6be 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
|
|
@@ -61,6 +61,7 @@ public class RAMDetails extends JList<String> {
|
|
|
|
// Follows CraftServer#getTPS
|
|
double[] tps = new double[] {
|
|
+ server.tps5s.getAverage(), // Purpur
|
|
server.tps1.getAverage(),
|
|
server.tps5.getAverage(),
|
|
server.tps15.getAverage()
|
|
@@ -73,7 +74,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((double)this.server.getAverageTickTimeNanos() / (double) TimeUtil.NANOSECONDS_PER_MILLISECOND) + " ms");
|
|
- vector.add("TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg));
|
|
+ vector.add("TPS from last 5s, 1m, 5m, 15m: " + String.join(", ", tpsAvg)); // Purpur
|
|
setListData(vector);
|
|
}
|
|
|
|
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
|
index 790bad0494454ca12ee152e3de6da3da634d9b20..a6e5950b5875cafd734300cdfbf58f5d3736f3c8 100644
|
|
--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
|
+++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
|
@@ -31,6 +31,7 @@ public record ServerBuildInfoImpl(
|
|
private static final String ATTRIBUTE_GIT_COMMIT = "Git-Commit";
|
|
|
|
private static final String BRAND_PAPER_NAME = "Paper";
|
|
+ private static final String BRAND_PURPUR_NAME = "Purpur"; // Purpur
|
|
|
|
private static final String BUILD_DEV = "DEV";
|
|
|
|
@@ -42,9 +43,9 @@ public record ServerBuildInfoImpl(
|
|
this(
|
|
getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID)
|
|
.map(Key::key)
|
|
- .orElse(BRAND_PAPER_ID),
|
|
+ .orElse(BRAND_PURPUR_ID), // Purpur
|
|
getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME)
|
|
- .orElse(BRAND_PAPER_NAME),
|
|
+ .orElse(BRAND_PURPUR_NAME), // Purpur
|
|
SharedConstants.getCurrentVersion().getId(),
|
|
SharedConstants.getCurrentVersion().getName(),
|
|
getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER)
|
|
@@ -61,7 +62,7 @@ public record ServerBuildInfoImpl(
|
|
|
|
@Override
|
|
public boolean isBrandCompatible(final @NotNull Key brandId) {
|
|
- return brandId.equals(this.brandId);
|
|
+ return brandId.equals(this.brandId) || brandId.equals(BRAND_PAPER_ID); // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/io/papermc/paper/command/PaperPluginsCommand.java b/src/main/java/io/papermc/paper/command/PaperPluginsCommand.java
|
|
index f0fce4113fb07c64adbec029d177c236cbdcbae8..865dc183276720d54d31d2a54d1bb5c845e80598 100644
|
|
--- a/src/main/java/io/papermc/paper/command/PaperPluginsCommand.java
|
|
+++ b/src/main/java/io/papermc/paper/command/PaperPluginsCommand.java
|
|
@@ -78,10 +78,10 @@ public class PaperPluginsCommand extends BukkitCommand {
|
|
this.setAliases(Arrays.asList("pl"));
|
|
}
|
|
|
|
- private static <T> List<Component> formatProviders(TreeMap<String, PluginProvider<T>> plugins) {
|
|
+ private static <T> List<Component> formatProviders(TreeMap<String, PluginProvider<T>> plugins, @NotNull CommandSender sender) { // Purpur
|
|
List<Component> components = new ArrayList<>(plugins.size());
|
|
for (PluginProvider<T> entry : plugins.values()) {
|
|
- components.add(formatProvider(entry));
|
|
+ components.add(formatProvider(entry, sender)); // Purpur
|
|
}
|
|
|
|
boolean isFirst = true;
|
|
@@ -109,7 +109,7 @@ public class PaperPluginsCommand extends BukkitCommand {
|
|
return formattedSublists;
|
|
}
|
|
|
|
- private static Component formatProvider(PluginProvider<?> provider) {
|
|
+ private static Component formatProvider(PluginProvider<?> provider, @NotNull CommandSender sender) { // Purpur
|
|
TextComponent.Builder builder = Component.text();
|
|
if (provider instanceof SpigotPluginProvider spigotPluginProvider && CraftMagicNumbers.isLegacy(spigotPluginProvider.getMeta())) {
|
|
builder.append(LEGACY_PLUGIN_STAR);
|
|
@@ -117,13 +117,65 @@ public class PaperPluginsCommand extends BukkitCommand {
|
|
|
|
String name = provider.getMeta().getName();
|
|
Component pluginName = Component.text(name, fromStatus(provider))
|
|
- .clickEvent(ClickEvent.runCommand("/version " + name));
|
|
+ // Purpur start
|
|
+ .clickEvent(ClickEvent.suggestCommand("/version " + name));
|
|
+
|
|
+ if (sender instanceof org.bukkit.entity.Player && sender.hasPermission("bukkit.command.version")) {
|
|
+ // Event components
|
|
+ String description = provider.getMeta().getDescription();
|
|
+ TextComponent.Builder hover = Component.text();
|
|
+ hover.append(Component.text("Version: ", NamedTextColor.WHITE)).append(Component.text(provider.getMeta().getVersion(), NamedTextColor.GREEN));
|
|
+
|
|
+ if (description != null) {
|
|
+ hover.append(Component.newline())
|
|
+ .append(Component.text("Description: ", NamedTextColor.WHITE))
|
|
+ .append(Component.text(description, NamedTextColor.GREEN));
|
|
+ }
|
|
+
|
|
+ if (provider.getMeta().getWebsite() != null) {
|
|
+ hover.append(Component.newline())
|
|
+ .append(Component.text("Website: ", NamedTextColor.WHITE))
|
|
+ .append(Component.text(provider.getMeta().getWebsite(), NamedTextColor.GREEN));
|
|
+ }
|
|
+
|
|
+ if (!provider.getMeta().getAuthors().isEmpty()) {
|
|
+ hover.append(Component.newline());
|
|
+ if (provider.getMeta().getAuthors().size() == 1) {
|
|
+ hover.append(Component.text("Author: "));
|
|
+ } else {
|
|
+ hover.append(Component.text("Authors: "));
|
|
+ }
|
|
+
|
|
+ hover.append(getAuthors(provider.getMeta()));
|
|
+ }
|
|
+
|
|
+ pluginName.hoverEvent(hover.build());
|
|
+ }
|
|
+ // Purpur end
|
|
|
|
builder.append(pluginName);
|
|
|
|
return builder.build();
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @NotNull
|
|
+ private static TextComponent getAuthors(@NotNull final PluginMeta pluginMeta) {
|
|
+ TextComponent.Builder builder = Component.text();
|
|
+ List<String> authors = pluginMeta.getAuthors();
|
|
+
|
|
+ for (int i = 0; i < authors.size(); i++) {
|
|
+ if (i > 0) {
|
|
+ builder.append(Component.text(i < authors.size() - 1 ? ", " : " and ", NamedTextColor.WHITE));
|
|
+ }
|
|
+
|
|
+ builder.append(Component.text(authors.get(i), NamedTextColor.GREEN));
|
|
+ }
|
|
+
|
|
+ return builder.build();
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
private static Component asPlainComponents(String strings) {
|
|
net.kyori.adventure.text.TextComponent.Builder builder = Component.text();
|
|
for (String string : strings.split("\n")) {
|
|
@@ -182,24 +234,24 @@ public class PaperPluginsCommand extends BukkitCommand {
|
|
}
|
|
}
|
|
|
|
- Component infoMessage = Component.text("Server Plugins (%s):".formatted(paperPlugins.size() + spigotPlugins.size()), NamedTextColor.WHITE);
|
|
+ //Component infoMessage = Component.text("Server Plugins (%s):".formatted(paperPlugins.size() + spigotPlugins.size()), NamedTextColor.WHITE);
|
|
//.append(INFO_ICON_START.hoverEvent(SERVER_PLUGIN_INFO)); TODO: Add docs
|
|
|
|
- sender.sendMessage(infoMessage);
|
|
+ //sender.sendMessage(infoMessage); // Purpur
|
|
|
|
- if (!paperPlugins.isEmpty()) {
|
|
- sender.sendMessage(PAPER_HEADER);
|
|
- }
|
|
+ //if (!paperPlugins.isEmpty()) { // Purpur
|
|
+ sender.sendMessage(PAPER_HEADER.append(Component.text(" (%s):".formatted(paperPlugins.size())))); // Purpur
|
|
+ //} // Purpur
|
|
|
|
- for (Component component : formatProviders(paperPlugins)) {
|
|
+ for (Component component : formatProviders(paperPlugins, sender)) { // Purpur
|
|
sender.sendMessage(component);
|
|
}
|
|
|
|
- if (!spigotPlugins.isEmpty()) {
|
|
- sender.sendMessage(BUKKIT_HEADER);
|
|
- }
|
|
+ //if (!spigotPlugins.isEmpty()) { // Purpur
|
|
+ sender.sendMessage(BUKKIT_HEADER.append(Component.text(" (%s):".formatted(spigotPlugins.size())))); // Purpur
|
|
+ //} // Purpur
|
|
|
|
- for (Component component : formatProviders(spigotPlugins)) {
|
|
+ for (Component component : formatProviders(spigotPlugins, sender)) { // Purpur
|
|
sender.sendMessage(component);
|
|
}
|
|
|
|
diff --git a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java
|
|
index 1029b6de6f36b08bf634b4056ef5701383f6f258..ee0d1df78838e05450ad1a06ce70eab2d5e5d3b8 100644
|
|
--- a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java
|
|
+++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java
|
|
@@ -260,6 +260,7 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
|
|
for (final NodePath path : RemovedConfigurations.REMOVED_WORLD_PATHS) {
|
|
builder.addAction(path, TransformAction.remove());
|
|
}
|
|
+ org.purpurmc.purpur.configuration.transformation.VoidDamageHeightMigration.apply(builder, contextMap); // Purpur
|
|
builder.build().apply(node);
|
|
|
|
final ConfigurationTransformation.VersionedBuilder versionedBuilder = Transformations.versionedBuilder();
|
|
diff --git a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java
|
|
index dad3fcc689ec806f985122a7cbd501a7d0fd0d36..b7428b8c287980941eaa5c5d1f1d321955277a09 100644
|
|
--- a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java
|
|
+++ b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java
|
|
@@ -400,6 +400,7 @@ public class WorldConfiguration extends ConfigurationPart {
|
|
public boolean useVanillaWorldScoreboardNameColoring = false;
|
|
}
|
|
|
|
+ @Setting(org.purpurmc.purpur.configuration.transformation.VoidDamageHeightMigration.ENVIRONMENT_KEY) // Purpur
|
|
public Environment environment;
|
|
|
|
public class Environment extends ConfigurationPart {
|
|
@@ -409,7 +410,9 @@ public class WorldConfiguration extends ConfigurationPart {
|
|
public boolean disableExplosionKnockback = false;
|
|
public boolean generateFlatBedrock = false;
|
|
public FrostedIce frostedIce;
|
|
+ @Setting(org.purpurmc.purpur.configuration.transformation.VoidDamageHeightMigration.VOID_DAMAGE_KEY) // Purpur
|
|
public DoubleOr.Disabled voidDamageAmount = new DoubleOr.Disabled(OptionalDouble.of(4));
|
|
+ @Setting(org.purpurmc.purpur.configuration.transformation.VoidDamageHeightMigration.VOID_DAMAGE_MIN_HEIGHT_OFFSET_KEY) // Purpur
|
|
public double voidDamageMinBuildHeightOffset = -64.0;
|
|
|
|
public class FrostedIce extends ConfigurationPart {
|
|
diff --git a/src/main/java/io/papermc/paper/logging/SysoutCatcher.java b/src/main/java/io/papermc/paper/logging/SysoutCatcher.java
|
|
index a8e813ca89b033f061e695288b3383bdcf128531..1ab65af9359d19530bba7f985a604d2a430ee234 100644
|
|
--- a/src/main/java/io/papermc/paper/logging/SysoutCatcher.java
|
|
+++ b/src/main/java/io/papermc/paper/logging/SysoutCatcher.java
|
|
@@ -54,9 +54,9 @@ public final class SysoutCatcher {
|
|
final JavaPlugin plugin = JavaPlugin.getProvidingPlugin(clazz);
|
|
|
|
// Instead of just printing the message, send it to the plugin's logger
|
|
- plugin.getLogger().log(this.level, this.prefix + line);
|
|
+ plugin.getLogger().log(this.level, /*this.prefix +*/ line); // Purpur - prefix not needed
|
|
|
|
- if (SysoutCatcher.SUPPRESS_NAGS) {
|
|
+ if (true || SysoutCatcher.SUPPRESS_NAGS) { // Purpur - nagging is annoying
|
|
return;
|
|
}
|
|
if (SysoutCatcher.NAG_INTERVAL > 0 || SysoutCatcher.NAG_TIMEOUT > 0) {
|
|
diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java
|
|
index b24265573fdef5d9a964bcd76146f34542c420cf..710477ae27ebc5afdf0012ef0867d05efd293c24 100644
|
|
--- a/src/main/java/net/minecraft/CrashReport.java
|
|
+++ b/src/main/java/net/minecraft/CrashReport.java
|
|
@@ -32,6 +32,7 @@ public class CrashReport {
|
|
private boolean trackingStackTrace = true;
|
|
private StackTraceElement[] uncategorizedStackTrace = new StackTraceElement[0];
|
|
private final SystemReport systemReport = new SystemReport();
|
|
+ private List<String> extraInfo = List.of("", "DO NOT REPORT THIS TO PAPER! REPORT TO PURPUR INSTEAD!", ""); // Purpur - Rebrand
|
|
|
|
public CrashReport(String message, Throwable cause) {
|
|
io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(cause); // Paper
|
|
@@ -144,7 +145,7 @@ public class CrashReport {
|
|
}
|
|
|
|
public String getFriendlyReport(ReportType type) {
|
|
- return this.getFriendlyReport(type, List.of());
|
|
+ return this.getFriendlyReport(type, extraInfo); // Purpur - Rebrand
|
|
}
|
|
|
|
@Nullable
|
|
@@ -191,7 +192,7 @@ public class CrashReport {
|
|
}
|
|
|
|
public boolean saveToFile(Path path, ReportType type) {
|
|
- return this.saveToFile(path, type, List.of());
|
|
+ return this.saveToFile(path, type, extraInfo); // Purpur - Rebrand
|
|
}
|
|
|
|
public SystemReport getSystemReport() {
|
|
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
|
index 13bd145b1e8006a53c22f5dc0c78f29b540c7663..0d133cd7993eb40b19e2aabe8e2bfcdcf5352398 100644
|
|
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
|
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
|
@@ -211,6 +211,19 @@ public class CommandSourceStack implements ExecutionCommandSource<CommandSourceS
|
|
}
|
|
// CraftBukkit end
|
|
|
|
+ // Purpur start
|
|
+ public boolean testPermission(int i, String bukkitPermission) {
|
|
+ if (hasPermission(i, bukkitPermission)) {
|
|
+ return true;
|
|
+ }
|
|
+ net.kyori.adventure.text.Component permissionMessage = getLevel().getServer().server.permissionMessage();
|
|
+ if (!permissionMessage.equals(net.kyori.adventure.text.Component.empty())) {
|
|
+ sendFailure(io.papermc.paper.adventure.PaperAdventure.asVanilla(permissionMessage.replaceText(net.kyori.adventure.text.TextReplacementConfig.builder().matchLiteral("<permission>").replacement(bukkitPermission).build())));
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public Vec3 getPosition() {
|
|
return this.worldPosition;
|
|
}
|
|
@@ -312,6 +325,30 @@ public class CommandSourceStack implements ExecutionCommandSource<CommandSourceS
|
|
}
|
|
}
|
|
|
|
+ // 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.miniMessage().deserialize(message), broadcastToOps);
|
|
+ }
|
|
+
|
|
+ public void sendSuccess(@Nullable net.kyori.adventure.text.Component message) {
|
|
+ sendSuccess(message, false);
|
|
+ }
|
|
+
|
|
+ public void sendSuccess(@Nullable net.kyori.adventure.text.Component message, boolean broadcastToOps) {
|
|
+ if (message == null) {
|
|
+ return;
|
|
+ }
|
|
+ sendSuccess(() -> io.papermc.paper.adventure.PaperAdventure.asVanilla(message), broadcastToOps);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public void sendSuccess(Supplier<Component> feedbackSupplier, boolean broadcastToOps) {
|
|
boolean flag1 = this.source.acceptsSuccess() && !this.silent;
|
|
boolean flag2 = broadcastToOps && this.source.shouldInformAdmins() && !this.silent;
|
|
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
|
|
index 260350422fc724ba5cd5769cbb387b6007f36a84..647a3ac2aea4dadd638836f831cc3768d10c7b74 100644
|
|
--- a/src/main/java/net/minecraft/commands/Commands.java
|
|
+++ b/src/main/java/net/minecraft/commands/Commands.java
|
|
@@ -169,7 +169,7 @@ public class Commands {
|
|
DamageCommand.register(this.dispatcher, commandRegistryAccess);
|
|
DataCommands.register(this.dispatcher);
|
|
DataPackCommand.register(this.dispatcher);
|
|
- DebugCommand.register(this.dispatcher);
|
|
+ //DebugCommand.register(this.dispatcher); // Purpur
|
|
DefaultGameModeCommands.register(this.dispatcher);
|
|
DifficultyCommand.register(this.dispatcher);
|
|
EffectCommands.register(this.dispatcher, commandRegistryAccess);
|
|
@@ -226,8 +226,8 @@ public class Commands {
|
|
JfrCommand.register(this.dispatcher);
|
|
}
|
|
|
|
- if (SharedConstants.IS_RUNNING_IN_IDE) {
|
|
- TestCommand.register(this.dispatcher);
|
|
+ if (org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands || SharedConstants.IS_RUNNING_IN_IDE) { // Purpur
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands) TestCommand.register(this.dispatcher); // Purpur
|
|
RaidCommand.register(this.dispatcher, commandRegistryAccess);
|
|
DebugPathCommand.register(this.dispatcher);
|
|
DebugMobSpawningCommand.register(this.dispatcher);
|
|
@@ -255,6 +255,14 @@ public class Commands {
|
|
StopCommand.register(this.dispatcher);
|
|
TransferCommand.register(this.dispatcher);
|
|
WhitelistCommand.register(this.dispatcher);
|
|
+ org.purpurmc.purpur.command.CreditsCommand.register(this.dispatcher); // Purpur
|
|
+ org.purpurmc.purpur.command.DemoCommand.register(this.dispatcher); // Purpur
|
|
+ org.purpurmc.purpur.command.PingCommand.register(this.dispatcher); // Purpur
|
|
+ org.purpurmc.purpur.command.UptimeCommand.register(this.dispatcher); // Purpur
|
|
+ org.purpurmc.purpur.command.TPSBarCommand.register(this.dispatcher); // Purpur
|
|
+ org.purpurmc.purpur.command.CompassCommand.register(this.dispatcher); // Purpur
|
|
+ org.purpurmc.purpur.command.RamBarCommand.register(this.dispatcher); // Purpur
|
|
+ org.purpurmc.purpur.command.RamCommand.register(this.dispatcher); // Purpur
|
|
}
|
|
|
|
if (environment.includeIntegrated) {
|
|
@@ -345,9 +353,9 @@ public class Commands {
|
|
// Paper end
|
|
CommandSourceStack commandlistenerwrapper = (CommandSourceStack) parseresults.getContext().getSource();
|
|
|
|
- Profiler.get().push(() -> {
|
|
+ /*Profiler.get().push(() -> { // Purpur
|
|
return "/" + s;
|
|
- });
|
|
+ });*/ // Purpur
|
|
ContextChain contextchain = this.finishParsing(parseresults, s, commandlistenerwrapper, label); // CraftBukkit // Paper - Add UnknownCommandEvent
|
|
|
|
try {
|
|
@@ -377,7 +385,7 @@ public class Commands {
|
|
Commands.LOGGER.error("'/{}' threw an exception", s, exception);
|
|
}
|
|
} finally {
|
|
- Profiler.get().pop();
|
|
+ //Profiler.get().pop(); // Purpur
|
|
}
|
|
|
|
}
|
|
@@ -514,6 +522,7 @@ public class Commands {
|
|
private void runSync(ServerPlayer player, Collection<String> bukkit, RootCommandNode<SharedSuggestionProvider> rootcommandnode) {
|
|
// Paper end - Perf: Async command map building
|
|
new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent<CommandSourceStack>(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, true).callEvent(); // Paper - Brigadier API
|
|
+ if (PlayerCommandSendEvent.getHandlerList().getRegisteredListeners().length > 0) { // Purpur - skip all this crap if there's nothing listening
|
|
PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit));
|
|
event.getPlayer().getServer().getPluginManager().callEvent(event);
|
|
|
|
@@ -524,6 +533,7 @@ public class Commands {
|
|
}
|
|
}
|
|
// CraftBukkit end
|
|
+ } // Purpur - skip event
|
|
player.connection.send(new ClientboundCommandsPacket(rootcommandnode));
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelector.java b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelector.java
|
|
index c8d39e6e1c570c9219f6066da273dc0130920519..b455c7e9d18bac3654daa8510f85cc21202e254b 100644
|
|
--- a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelector.java
|
|
+++ b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelector.java
|
|
@@ -198,10 +198,10 @@ public class EntitySelector {
|
|
|
|
if (this.playerName != null) {
|
|
entityplayer = source.getServer().getPlayerList().getPlayerByName(this.playerName);
|
|
- return entityplayer == null ? List.of() : List.of(entityplayer);
|
|
+ return entityplayer == null || !canSee(source, entityplayer) ? List.of() : List.of(entityplayer); // Purpur
|
|
} else if (this.entityUUID != null) {
|
|
entityplayer = source.getServer().getPlayerList().getPlayer(this.entityUUID);
|
|
- return entityplayer == null ? List.of() : List.of(entityplayer);
|
|
+ return entityplayer == null || !canSee(source, entityplayer) ? List.of() : List.of(entityplayer); // Purpur
|
|
} else {
|
|
Vec3 vec3d = (Vec3) this.position.apply(source.getPosition());
|
|
AABB axisalignedbb = this.getAbsoluteAabb(vec3d);
|
|
@@ -214,7 +214,7 @@ public class EntitySelector {
|
|
ServerPlayer entityplayer1 = (ServerPlayer) entity;
|
|
|
|
if (predicate.test(entityplayer1)) {
|
|
- return List.of(entityplayer1);
|
|
+ return !canSee(source, entityplayer1) ? List.of() : List.of(entityplayer1); // Purpur
|
|
}
|
|
}
|
|
|
|
@@ -225,6 +225,7 @@ public class EntitySelector {
|
|
|
|
if (this.isWorldLimited()) {
|
|
object = source.getLevel().getPlayers(predicate, i);
|
|
+ ((List) object).removeIf(entityplayer3 -> !canSee(source, (ServerPlayer) entityplayer3)); // Purpur
|
|
} else {
|
|
object = new ObjectArrayList();
|
|
Iterator iterator = source.getServer().getPlayerList().getPlayers().iterator();
|
|
@@ -232,7 +233,7 @@ public class EntitySelector {
|
|
while (iterator.hasNext()) {
|
|
ServerPlayer entityplayer2 = (ServerPlayer) iterator.next();
|
|
|
|
- if (predicate.test(entityplayer2)) {
|
|
+ if (predicate.test(entityplayer2) && canSee(source, entityplayer2)) { // Purpur
|
|
((List) object).add(entityplayer2);
|
|
if (((List) object).size() >= i) {
|
|
return (List) object;
|
|
@@ -299,4 +300,10 @@ public class EntitySelector {
|
|
public static Component joinNames(List<? extends Entity> entities) {
|
|
return ComponentUtils.formatList(entities, Entity::getDisplayName);
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ private boolean canSee(CommandSourceStack sender, ServerPlayer target) {
|
|
+ return !org.purpurmc.purpur.PurpurConfig.hideHiddenPlayersFromEntitySelector || !(sender.getEntity() instanceof ServerPlayer player) || player.getBukkitEntity().canSee(target.getBukkitEntity());
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/commands/execution/tasks/BuildContexts.java b/src/main/java/net/minecraft/commands/execution/tasks/BuildContexts.java
|
|
index b0d26b0eadb2a43924629424a6c13198aace8f69..e7cc8105fff9cb952eabfd006e0a4e4638091019 100644
|
|
--- a/src/main/java/net/minecraft/commands/execution/tasks/BuildContexts.java
|
|
+++ b/src/main/java/net/minecraft/commands/execution/tasks/BuildContexts.java
|
|
@@ -42,7 +42,7 @@ public class BuildContexts<T extends ExecutionCommandSource<T>> {
|
|
ChainModifiers chainModifiers = flags;
|
|
List<T> list = sources;
|
|
if (contextChain.getStage() != Stage.EXECUTE) {
|
|
- context.profiler().push(() -> "prepare " + this.commandInput);
|
|
+ //context.profiler().push(() -> "prepare " + this.commandInput); // Purpur
|
|
|
|
try {
|
|
for (int i = context.forkLimit(); contextChain.getStage() != Stage.EXECUTE; contextChain = contextChain.nextStage()) {
|
|
@@ -52,7 +52,7 @@ public class BuildContexts<T extends ExecutionCommandSource<T>> {
|
|
}
|
|
|
|
RedirectModifier<T> redirectModifier = commandContext.getRedirectModifier();
|
|
- if (redirectModifier instanceof CustomModifierExecutor<T> customModifierExecutor) {
|
|
+ if (redirectModifier instanceof CustomModifierExecutor customModifierExecutor) { // Purpur - decompile error
|
|
customModifierExecutor.apply(baseSource, list, contextChain, chainModifiers, ExecutionControl.create(context, frame));
|
|
return;
|
|
}
|
|
@@ -86,17 +86,17 @@ public class BuildContexts<T extends ExecutionCommandSource<T>> {
|
|
}
|
|
}
|
|
} finally {
|
|
- context.profiler().pop();
|
|
+ //context.profiler().pop(); // Purpur
|
|
}
|
|
}
|
|
|
|
if (list.isEmpty()) {
|
|
if (chainModifiers.isReturn()) {
|
|
- context.queueNext(new CommandQueueEntry<>(frame, FallthroughTask.instance()));
|
|
+ context.queueNext(new CommandQueueEntry<>(frame, (EntryAction<T>) FallthroughTask.instance())); // Purpur - decompile error
|
|
}
|
|
} else {
|
|
CommandContext<T> commandContext2 = contextChain.getTopContext();
|
|
- if (commandContext2.getCommand() instanceof CustomCommandExecutor<T> customCommandExecutor) {
|
|
+ if (commandContext2.getCommand() instanceof CustomCommandExecutor customCommandExecutor) { // Purpur - decompile error
|
|
ExecutionControl<T> executionControl = ExecutionControl.create(context, frame);
|
|
|
|
for (T executionCommandSource2 : list) {
|
|
diff --git a/src/main/java/net/minecraft/commands/execution/tasks/ExecuteCommand.java b/src/main/java/net/minecraft/commands/execution/tasks/ExecuteCommand.java
|
|
index e9775b4506909bee65a74964f0d5391a0513de1d..684f7f202305c09b1037c5d38a52a5ea7f00751b 100644
|
|
--- a/src/main/java/net/minecraft/commands/execution/tasks/ExecuteCommand.java
|
|
+++ b/src/main/java/net/minecraft/commands/execution/tasks/ExecuteCommand.java
|
|
@@ -23,7 +23,7 @@ public class ExecuteCommand<T extends ExecutionCommandSource<T>> implements Unbo
|
|
|
|
@Override
|
|
public void execute(T executionCommandSource, ExecutionContext<T> executionContext, Frame frame) {
|
|
- executionContext.profiler().push(() -> "execute " + this.commandInput);
|
|
+ //executionContext.profiler().push(() -> "execute " + this.commandInput); // Purpur
|
|
|
|
try {
|
|
executionContext.incrementCost();
|
|
@@ -37,7 +37,7 @@ public class ExecuteCommand<T extends ExecutionCommandSource<T>> implements Unbo
|
|
} catch (CommandSyntaxException var9) {
|
|
executionCommandSource.handleError(var9, this.modifiers.isForked(), executionContext.tracer());
|
|
} finally {
|
|
- executionContext.profiler().pop();
|
|
+ //executionContext.profiler().pop(); // Purpur
|
|
}
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/commands/synchronization/ArgumentTypeInfos.java b/src/main/java/net/minecraft/commands/synchronization/ArgumentTypeInfos.java
|
|
index 7b118a92a6eb779f800ae8f5d8f6e3c861fc4f6a..057a038e8dcacd7496a0b2373de2c20255a5c297 100644
|
|
--- a/src/main/java/net/minecraft/commands/synchronization/ArgumentTypeInfos.java
|
|
+++ b/src/main/java/net/minecraft/commands/synchronization/ArgumentTypeInfos.java
|
|
@@ -119,10 +119,10 @@ public class ArgumentTypeInfos {
|
|
register(registry, "dimension", DimensionArgument.class, SingletonArgumentInfo.contextFree(DimensionArgument::dimension));
|
|
register(registry, "gamemode", GameModeArgument.class, SingletonArgumentInfo.contextFree(GameModeArgument::gameMode));
|
|
register(registry, "time", TimeArgument.class, new TimeArgument.Info());
|
|
- register(registry, "resource_or_tag", fixClassType(ResourceOrTagArgument.class), new ResourceOrTagArgument.Info());
|
|
- register(registry, "resource_or_tag_key", fixClassType(ResourceOrTagKeyArgument.class), new ResourceOrTagKeyArgument.Info());
|
|
- register(registry, "resource", fixClassType(ResourceArgument.class), new ResourceArgument.Info());
|
|
- register(registry, "resource_key", fixClassType(ResourceKeyArgument.class), new ResourceKeyArgument.Info());
|
|
+ register(registry, "resource_or_tag", fixClassType(ResourceOrTagArgument.class), new ResourceOrTagArgument.Info<>()); // Purpur - decompile error
|
|
+ register(registry, "resource_or_tag_key", fixClassType(ResourceOrTagKeyArgument.class), new ResourceOrTagKeyArgument.Info<>()); // Purpur - decompile error
|
|
+ register(registry, "resource", fixClassType(ResourceArgument.class), new ResourceArgument.Info<>()); // Purpur - decompile error
|
|
+ register(registry, "resource_key", fixClassType(ResourceKeyArgument.class), new ResourceKeyArgument.Info<>()); // Purpur - decompile error
|
|
register(registry, "template_mirror", TemplateMirrorArgument.class, SingletonArgumentInfo.contextFree(TemplateMirrorArgument::templateMirror));
|
|
register(registry, "template_rotation", TemplateRotationArgument.class, SingletonArgumentInfo.contextFree(TemplateRotationArgument::templateRotation));
|
|
register(registry, "heightmap", HeightmapTypeArgument.class, SingletonArgumentInfo.contextFree(HeightmapTypeArgument::heightmap));
|
|
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
|
|
index f58a94efafbc01d402cd03a108bb90f60930a316..21ea63da99c5b3e2e1ab9cc1049c903bba6cf288 100644
|
|
--- a/src/main/java/net/minecraft/core/BlockPos.java
|
|
+++ b/src/main/java/net/minecraft/core/BlockPos.java
|
|
@@ -62,6 +62,12 @@ public class BlockPos extends Vec3i {
|
|
public static final int MAX_HORIZONTAL_COORDINATE = 33554431;
|
|
// Paper end - Optimize Bit Operations by inlining
|
|
|
|
+ // Purpur start
|
|
+ public BlockPos(net.minecraft.world.entity.Entity entity) {
|
|
+ super(entity.getBlockX(), entity.getBlockY(), entity.getBlockZ());
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public BlockPos(int x, int y, int z) {
|
|
super(x, y, z);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
|
index 0d12605dc84dad49faa18bf1fd058c3c168623ee..c6490554a3025f4de3f3218178fad76cd1848a19 100644
|
|
--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
|
+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
|
@@ -930,5 +930,22 @@ public interface DispenseItemBehavior {
|
|
DispenserBlock.registerBehavior(Items.TNT_MINECART, new MinecartDispenseItemBehavior(EntityType.TNT_MINECART));
|
|
DispenserBlock.registerBehavior(Items.HOPPER_MINECART, new MinecartDispenseItemBehavior(EntityType.HOPPER_MINECART));
|
|
DispenserBlock.registerBehavior(Items.COMMAND_BLOCK_MINECART, new MinecartDispenseItemBehavior(EntityType.COMMAND_BLOCK_MINECART));
|
|
+ // Purpur start
|
|
+ DispenserBlock.registerBehavior(Items.ANVIL, (new OptionalDispenseItemBehavior() {
|
|
+ @Override
|
|
+ public ItemStack execute(BlockSource dispenser, ItemStack stack) {
|
|
+ net.minecraft.world.level.Level level = dispenser.level();
|
|
+ if (!level.purpurConfig.dispenserPlaceAnvils) return super.execute(dispenser, stack);
|
|
+ Direction facing = dispenser.blockEntity().getBlockState().getValue(DispenserBlock.FACING);
|
|
+ BlockPos pos = dispenser.pos().relative(facing);
|
|
+ BlockState state = level.getBlockState(pos);
|
|
+ if (state.isAir()) {
|
|
+ level.setBlockAndUpdate(pos, Blocks.ANVIL.defaultBlockState().setValue(net.minecraft.world.level.block.AnvilBlock.FACING, facing.getAxis() == Direction.Axis.Y ? Direction.NORTH : facing.getClockWise()));
|
|
+ stack.shrink(1);
|
|
+ }
|
|
+ return stack;
|
|
+ }
|
|
+ }));
|
|
+ // Purpur end
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
|
|
index bf8c511739265c6a9cd277752e844481598f8966..ffe2399ab6b1f311536475d8216238b5b01c5dab 100644
|
|
--- a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
|
|
+++ b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
|
|
@@ -41,7 +41,7 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior {
|
|
return false;
|
|
} else {
|
|
LivingEntity entityliving = (LivingEntity) list.getFirst();
|
|
- EquipmentSlot enumitemslot = entityliving.getEquipmentSlotForItem(stack);
|
|
+ EquipmentSlot enumitemslot = pointer.level().purpurConfig.dispenserApplyCursedArmor ? entityliving.getEquipmentSlotForItem(stack) : entityliving.getEquipmentSlotForDispenserItem(stack); if (enumitemslot == null) return false; // Purpur - Dispenser curse of binding protection
|
|
ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
|
|
|
|
// CraftBukkit start
|
|
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
|
index 4a8356a714ed50d4a32bcf046a2e16491bef014b..56e47c5709c765943407d2065b25bd512d1f9388 100644
|
|
--- a/src/main/java/net/minecraft/network/Connection.java
|
|
+++ b/src/main/java/net/minecraft/network/Connection.java
|
|
@@ -617,11 +617,20 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
|
private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world
|
|
private static int joinAttemptsThisTick; // Paper - Buffer joins to world
|
|
private static int currTick; // Paper - Buffer joins to world
|
|
+ private static int tickSecond; // Purpur
|
|
public void tick() {
|
|
this.flushQueue();
|
|
// Paper start - Buffer joins to world
|
|
if (Connection.currTick != net.minecraft.server.MinecraftServer.currentTick) {
|
|
Connection.currTick = net.minecraft.server.MinecraftServer.currentTick;
|
|
+ // Purpur start
|
|
+ if (org.purpurmc.purpur.PurpurConfig.maxJoinsPerSecond) {
|
|
+ if (++Connection.tickSecond > 20) {
|
|
+ Connection.tickSecond = 0;
|
|
+ Connection.joinAttemptsThisTick = 0;
|
|
+ }
|
|
+ } else
|
|
+ // Purpur end
|
|
Connection.joinAttemptsThisTick = 0;
|
|
}
|
|
// Paper end - Buffer joins to world
|
|
diff --git a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java
|
|
index 300929a406905f5ff1ede664d5b99fb0938d4d2e..a4e9ac0e07f08e0b6aa682e8c1587d9c84fc3c6c 100644
|
|
--- a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java
|
|
+++ b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java
|
|
@@ -45,7 +45,7 @@ public class SignedMessageChain {
|
|
SignedMessageLink signedMessageLink = SignedMessageChain.this.nextLink;
|
|
if (signedMessageLink == null) {
|
|
throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.CHAIN_BROKEN);
|
|
- } else if (body.timeStamp().isBefore(SignedMessageChain.this.lastTimeStamp)) {
|
|
+ } else if (org.purpurmc.purpur.PurpurConfig.kickForOutOfOrderChat && body.timeStamp().isBefore(SignedMessageChain.this.lastTimeStamp)) {
|
|
this.setChainBroken();
|
|
throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.OUT_OF_ORDER_CHAT, org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event causes
|
|
} else {
|
|
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
|
|
index 90ca25c4aaf92a5639839a7cdaee2ffcdb75efa7..f0d762bd140fad27ae73bcf3e61b640b9e3f2592 100644
|
|
--- a/src/main/java/net/minecraft/server/Main.java
|
|
+++ b/src/main/java/net/minecraft/server/Main.java
|
|
@@ -120,6 +120,12 @@ public class Main {
|
|
JvmProfiler.INSTANCE.start(Environment.SERVER);
|
|
}
|
|
|
|
+ // Purpur start - load config files early
|
|
+ org.bukkit.configuration.file.YamlConfiguration purpurConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionset.valueOf("purpur-settings"));
|
|
+ org.purpurmc.purpur.PurpurConfig.clampEnchantLevels = purpurConfiguration.getBoolean("settings.enchantment.clamp-levels");
|
|
+ org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands = purpurConfiguration.getBoolean("settings.register-minecraft-debug-commands");
|
|
+ // Purpur end - load config files early
|
|
+
|
|
io.papermc.paper.plugin.PluginInitializerManager.load(optionset); // Paper
|
|
Bootstrap.bootStrap();
|
|
Bootstrap.validate();
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index 64b56abf8900d0424100da460fc68ac964394793..fa1c48a1f861b06e970bdc3499c14f19eea04772 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -314,6 +314,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
public OptionSet options;
|
|
public org.bukkit.command.ConsoleCommandSender console;
|
|
public static int currentTick; // Paper - improve tick loop
|
|
+ public static final long startTimeMillis = System.currentTimeMillis();
|
|
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
|
|
public int autosavePeriod;
|
|
// Paper - don't store the vanilla dispatcher
|
|
@@ -324,10 +325,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
public static final int TICK_TIME = 1000000000 / MinecraftServer.TPS;
|
|
private static final int SAMPLE_INTERVAL = 20; // Paper - improve server tick loop
|
|
@Deprecated(forRemoval = true) // Paper
|
|
- public final double[] recentTps = new double[ 3 ];
|
|
+ public final double[] recentTps = new double[ 4 ]; // Purpur
|
|
// Spigot end
|
|
public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations; // Paper - add paper configuration files
|
|
public boolean isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
|
|
+ public boolean lagging = false; // Purpur
|
|
+ protected boolean upnp = false; // Purpur
|
|
|
|
public volatile Thread shutdownThread; // Paper
|
|
public volatile boolean abnormalExit = false; // Paper
|
|
@@ -428,12 +431,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
public MinecraftServer(OptionSet options, WorldLoader.DataLoadContext worldLoader, Thread thread, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PackRepository resourcepackrepository, WorldStem worldstem, Proxy proxy, DataFixer datafixer, Services services, ChunkProgressListenerFactory worldloadlistenerfactory) {
|
|
super("Server");
|
|
SERVER = this; // Paper - better singleton
|
|
- this.metricsRecorder = InactiveMetricsRecorder.INSTANCE;
|
|
- this.onMetricsRecordingStopped = (methodprofilerresults) -> {
|
|
+ //this.metricsRecorder = InactiveMetricsRecorder.INSTANCE; // Purpur
|
|
+ /*this.onMetricsRecordingStopped = (methodprofilerresults) -> { // Purpur
|
|
this.stopRecordingMetrics();
|
|
- };
|
|
- this.onMetricsRecordingFinished = (path) -> {
|
|
- };
|
|
+ };*/ // Purpur
|
|
+ //this.onMetricsRecordingFinished = (path) -> { // Purpur
|
|
+ //}; // Purpur
|
|
this.random = RandomSource.create();
|
|
this.port = -1;
|
|
this.levels = Maps.newLinkedHashMap();
|
|
@@ -1046,15 +1049,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
org.spigotmc.WatchdogThread.doStop(); // Paper
|
|
// Paper end
|
|
// CraftBukkit end
|
|
- if (this.metricsRecorder.isRecording()) {
|
|
+ /*if (this.metricsRecorder.isRecording()) { // Purpur
|
|
this.cancelRecordingMetrics();
|
|
- }
|
|
+ }*/ // Purpur
|
|
|
|
MinecraftServer.LOGGER.info("Stopping server");
|
|
Commands.COMMAND_SENDING_POOL.shutdownNow(); // Paper - Perf: Async command map building; Shutdown and don't bother finishing
|
|
+ this.server.spark.disable(); // Paper - spark
|
|
+ // Purpur start
|
|
+ if (upnp) {
|
|
+ if (dev.omega24.upnp4j.UPnP4J.close(this.getPort(), dev.omega24.upnp4j.util.Protocol.TCP)) {
|
|
+ LOGGER.info("[UPnP] Port {} closed", this.getPort());
|
|
+ } else {
|
|
+ LOGGER.error("[UPnP] Failed to close port {}", this.getPort());
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
// CraftBukkit start
|
|
if (this.server != null) {
|
|
- this.server.spark.disable(); // Paper - spark
|
|
this.server.disablePlugins();
|
|
this.server.waitForAsyncTasksShutdown(); // Paper - Wait for Async Tasks during shutdown
|
|
}
|
|
@@ -1154,6 +1166,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
this.safeShutdown(waitForShutdown, false);
|
|
}
|
|
public void safeShutdown(boolean waitForShutdown, boolean isRestarting) {
|
|
+ org.purpurmc.purpur.task.BossBarTask.stopAll(); // Purpur
|
|
+ org.purpurmc.purpur.task.BeehiveTask.instance().unregister(); // Purpur
|
|
this.isRestarting = isRestarting;
|
|
this.hasLoggedStop = true; // Paper - Debugging
|
|
if (isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
|
|
@@ -1180,6 +1194,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);
|
|
@@ -1266,6 +1281,25 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
LOGGER.info("*************************************************************************************");
|
|
}
|
|
// Paper end - Add onboarding message for initial server start
|
|
+ // Purpur start
|
|
+ if (org.purpurmc.purpur.configuration.transformation.VoidDamageHeightMigration.HAS_BEEN_REGISTERED) {
|
|
+ try {
|
|
+ org.purpurmc.purpur.PurpurConfig.config.save((File) this.options.valueOf("purpur-settings"));
|
|
+ } catch (IOException ex) {
|
|
+ Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "Could not save " + this.options.valueOf("purpur-settings"), ex);
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ // Purpur start
|
|
+ if (!Boolean.getBoolean("Purpur.IReallyDontWantStartupCommands") && !org.purpurmc.purpur.PurpurConfig.startupCommands.isEmpty()) {
|
|
+ LOGGER.info("Purpur: Running startup commands specified in purpur.yml.");
|
|
+ for (final String startupCommand : org.purpurmc.purpur.PurpurConfig.startupCommands) {
|
|
+ LOGGER.info("Purpur: Running the following command: \"{}\"", startupCommand);
|
|
+ ((DedicatedServer) this).handleConsoleInput(startupCommand, this.createCommandSourceStack());
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
|
|
while (this.running) {
|
|
long i;
|
|
@@ -1293,14 +1327,19 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
if (++MinecraftServer.currentTick % MinecraftServer.SAMPLE_INTERVAL == 0) {
|
|
final long diff = currentTime - tickSection;
|
|
final java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP);
|
|
+ tps5s.add(currentTps, diff); // Purpur
|
|
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
|
|
+ lagging = recentTps[0] < org.purpurmc.purpur.PurpurConfig.laggingThreshold; // Purpur
|
|
tickSection = currentTime;
|
|
}
|
|
// Paper end - further improve server tick loop
|
|
@@ -1308,22 +1347,22 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
|
|
boolean flag = i == 0L;
|
|
|
|
- if (this.debugCommandProfilerDelayStart) {
|
|
+ /*if (this.debugCommandProfilerDelayStart) { // Purpur
|
|
this.debugCommandProfilerDelayStart = false;
|
|
this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount);
|
|
- }
|
|
+ }*/ // Purpur
|
|
|
|
//MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit // Paper - don't overwrite current tick time
|
|
lastTick = currentTime;
|
|
this.nextTickTimeNanos += i;
|
|
|
|
try {
|
|
- Profiler.Scope profiler_a = Profiler.use(this.createProfiler());
|
|
+ //Profiler.Scope profiler_a = Profiler.use(this.createProfiler()); // Purpur
|
|
|
|
try {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("tick");
|
|
+ //gameprofilerfiller.push("tick"); // Purpur
|
|
this.tickFrame.start();
|
|
this.tickServer(flag ? () -> {
|
|
return false;
|
|
@@ -1336,9 +1375,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
}
|
|
// Paper end - rewrite chunk system
|
|
this.tickFrame.end();
|
|
- gameprofilerfiller.popPush("nextTickWait");
|
|
+ //gameprofilerfiller.popPush("nextTickWait"); // Purpur
|
|
this.mayHaveDelayedTasks = true;
|
|
this.delayedTasksMaxNextTickTimeNanos = Math.max(Util.getNanos() + i, this.nextTickTimeNanos);
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.tpsCatchup /*|| !gg.pufferfish.pufferfish.PufferfishConfig.tpsCatchup*/) { // Purpur // Purpur - TODO: Pufferfish
|
|
+ this.nextTickTimeNanos = currentTime + i;
|
|
+ this.delayedTasksMaxNextTickTimeNanos = nextTickTimeNanos;
|
|
+ }
|
|
this.startMeasuringTaskExecutionTime();
|
|
this.waitUntilNextTick();
|
|
this.finishMeasuringTaskExecutionTime();
|
|
@@ -1346,23 +1389,23 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
this.tickRateManager.endTickWork();
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
this.logFullTickTime();
|
|
} catch (Throwable throwable) {
|
|
- if (profiler_a != null) {
|
|
+ /*if (profiler_a != null) { // Purpur
|
|
try {
|
|
profiler_a.close();
|
|
} catch (Throwable throwable1) {
|
|
throwable.addSuppressed(throwable1);
|
|
}
|
|
- }
|
|
+ }*/ // Purpur
|
|
|
|
throw throwable;
|
|
}
|
|
|
|
- if (profiler_a != null) {
|
|
+ /*if (profiler_a != null) { // Purpur
|
|
profiler_a.close();
|
|
- }
|
|
+ }*/ // Purpur
|
|
} finally {
|
|
this.endMetricsRecordingTick();
|
|
}
|
|
@@ -1572,7 +1615,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
}
|
|
|
|
public void doRunTask(TickTask ticktask) { // CraftBukkit - decompile error
|
|
- Profiler.get().incrementCounter("runTask");
|
|
+ //Profiler.get().incrementCounter("runTask"); // Purpur
|
|
super.doRunTask(ticktask);
|
|
}
|
|
|
|
@@ -1690,7 +1733,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
profiler.pop();
|
|
// Paper end - Incremental chunk and player saving
|
|
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
this.runAllTasks(); // Paper - move runAllTasks() into full server tick (previously for timings)
|
|
this.server.spark.executeMainThreadTasks(); // Paper - spark
|
|
@@ -1700,7 +1743,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
new com.destroystokyo.paper.event.server.ServerTickEndEvent(this.tickCount, ((double)(endTime - lastTick) / 1000000D), remaining).callEvent();
|
|
// Paper end - Server Tick Events
|
|
this.server.spark.tickEnd(((double)(endTime - lastTick) / 1000000D)); // Paper - spark
|
|
- gameprofilerfiller.push("tallying");
|
|
+ //gameprofilerfiller.push("tallying"); // Purpur
|
|
long k = Util.getNanos() - i;
|
|
int l = this.tickCount % 100;
|
|
|
|
@@ -1714,7 +1757,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
this.tickTimes60s.add(this.tickCount, k);
|
|
// Paper end - Add tick times API and /mspt command
|
|
this.logTickMethodTime(i);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
private void autoSave() {
|
|
@@ -1814,9 +1857,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
});
|
|
// Paper end - Folia scheduler API
|
|
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper
|
|
- gameprofilerfiller.push("commandFunctions");
|
|
+ //gameprofilerfiller.push("commandFunctions"); // Purpur
|
|
this.getFunctions().tick();
|
|
- gameprofilerfiller.popPush("levels");
|
|
+ //gameprofilerfiller.popPush("levels"); // Purpur
|
|
//Iterator iterator = this.getAllLevels().iterator(); // Paper - Throw exception on world create while being ticked; moved down
|
|
|
|
// CraftBukkit start
|
|
@@ -1833,7 +1876,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
long worldTime = level.getGameTime();
|
|
final ClientboundSetTimePacket worldPacket = new ClientboundSetTimePacket(worldTime, dayTime, doDaylight);
|
|
for (Player entityhuman : level.players()) {
|
|
- if (!(entityhuman instanceof ServerPlayer) || (tickCount + entityhuman.getId()) % 20 != 0) {
|
|
+ if (!(entityhuman instanceof ServerPlayer) || (!level.isForceTime() && (tickCount + entityhuman.getId()) % 20 != 0)) { // Purpur
|
|
continue;
|
|
}
|
|
ServerPlayer entityplayer = (ServerPlayer) entityhuman;
|
|
@@ -1853,21 +1896,22 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
|
|
net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers
|
|
worldserver.updateLagCompensationTick(); // Paper - lag compensation
|
|
+ worldserver.hasRidableMoveEvent = org.purpurmc.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur
|
|
|
|
- gameprofilerfiller.push(() -> {
|
|
+ /*gameprofilerfiller.push(() -> { // Purpur
|
|
String s = String.valueOf(worldserver);
|
|
|
|
return s + " " + String.valueOf(worldserver.dimension().location());
|
|
- });
|
|
+ });*/ // Purpur
|
|
/* Drop global time updates
|
|
if (this.tickCount % 20 == 0) {
|
|
- gameprofilerfiller.push("timeSync");
|
|
+ //gameprofilerfiller.push("timeSync"); // Purpur
|
|
this.synchronizeTime(worldserver);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
// CraftBukkit end */
|
|
|
|
- gameprofilerfiller.push("tick");
|
|
+ //gameprofilerfiller.push("tick"); // Purpur
|
|
|
|
try {
|
|
worldserver.tick(shouldKeepTicking);
|
|
@@ -1878,27 +1922,27 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
throw new ReportedException(crashreport);
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
|
|
}
|
|
this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
|
|
|
|
- gameprofilerfiller.popPush("connection");
|
|
+ //gameprofilerfiller.popPush("connection"); // Purpur
|
|
this.tickConnection();
|
|
- gameprofilerfiller.popPush("players");
|
|
+ //gameprofilerfiller.popPush("players"); // Purpur
|
|
this.playerList.tick();
|
|
if (SharedConstants.IS_RUNNING_IN_IDE && this.tickRateManager.runsNormally()) {
|
|
GameTestTicker.SINGLETON.tick();
|
|
}
|
|
|
|
- gameprofilerfiller.popPush("server gui refresh");
|
|
+ //gameprofilerfiller.popPush("server gui refresh"); // Purpur
|
|
|
|
for (int i = 0; i < this.tickables.size(); ++i) {
|
|
((Runnable) this.tickables.get(i)).run();
|
|
}
|
|
|
|
- gameprofilerfiller.popPush("send chunks");
|
|
+ //gameprofilerfiller.popPush("send chunks"); // Purpur
|
|
iterator = this.playerList.getPlayers().iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
@@ -1908,7 +1952,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
entityplayer.connection.resumeFlushing();
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
public void tickConnection() {
|
|
@@ -1920,9 +1964,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
}
|
|
|
|
public void forceTimeSynchronization() {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
|
|
- gameprofilerfiller.push("timeSync");
|
|
+ //gameprofilerfiller.push("timeSync"); // Purpur
|
|
Iterator iterator = this.getAllLevels().iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
@@ -1931,7 +1975,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
this.synchronizeTime(worldserver);
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
public boolean isLevelEnabled(Level world) {
|
|
@@ -2008,7 +2052,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
|
|
@DontObfuscate
|
|
public String getServerModName() {
|
|
- return io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); // Paper
|
|
+ return org.purpurmc.purpur.PurpurConfig.serverModName; // Paper // Purpur
|
|
}
|
|
|
|
public SystemReport fillSystemReport(SystemReport details) {
|
|
@@ -2884,7 +2928,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
// CraftBukkit end
|
|
|
|
private ProfilerFiller createProfiler() {
|
|
- if (this.willStartRecordingMetrics) {
|
|
+ if (false && this.willStartRecordingMetrics) { // Purpur
|
|
this.metricsRecorder = ActiveMetricsRecorder.createStarted(new ServerMetricsSamplersProvider(Util.timeSource, this.isDedicatedServer()), Util.timeSource, Util.ioPool(), new MetricsPersister("server"), this.onMetricsRecordingStopped, (path) -> {
|
|
this.executeBlocking(() -> {
|
|
this.saveDebugReport(path.resolve("server"));
|
|
@@ -2894,37 +2938,38 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
this.willStartRecordingMetrics = false;
|
|
}
|
|
|
|
- this.metricsRecorder.startTick();
|
|
- return SingleTickProfiler.decorateFiller(this.metricsRecorder.getProfiler(), SingleTickProfiler.createTickProfiler("Server"));
|
|
+ //this.metricsRecorder.startTick(); // Purpur
|
|
+ return null; // Purpur
|
|
+ //return SingleTickProfiler.decorateFiller(this.metricsRecorder.getProfiler(), SingleTickProfiler.createTickProfiler("Server")); // Purpur
|
|
}
|
|
|
|
public void endMetricsRecordingTick() {
|
|
- this.metricsRecorder.endTick();
|
|
+ //this.metricsRecorder.endTick(); // Purpur
|
|
}
|
|
|
|
public boolean isRecordingMetrics() {
|
|
- return this.metricsRecorder.isRecording();
|
|
+ return false; //this.metricsRecorder.isRecording(); // Purpur
|
|
}
|
|
|
|
public void startRecordingMetrics(Consumer<ProfileResults> resultConsumer, Consumer<Path> dumpConsumer) {
|
|
- this.onMetricsRecordingStopped = (methodprofilerresults) -> {
|
|
+ /*this.onMetricsRecordingStopped = (methodprofilerresults) -> { // Purpur
|
|
this.stopRecordingMetrics();
|
|
resultConsumer.accept(methodprofilerresults);
|
|
};
|
|
this.onMetricsRecordingFinished = dumpConsumer;
|
|
- this.willStartRecordingMetrics = true;
|
|
+ this.willStartRecordingMetrics = true;*/ // Purpur
|
|
}
|
|
|
|
public void stopRecordingMetrics() {
|
|
- this.metricsRecorder = InactiveMetricsRecorder.INSTANCE;
|
|
+ //this.metricsRecorder = InactiveMetricsRecorder.INSTANCE; // Purpur
|
|
}
|
|
|
|
public void finishRecordingMetrics() {
|
|
- this.metricsRecorder.end();
|
|
+ //this.metricsRecorder.end(); // Purpur
|
|
}
|
|
|
|
public void cancelRecordingMetrics() {
|
|
- this.metricsRecorder.cancel();
|
|
+ //this.metricsRecorder.cancel(); // Purpur
|
|
}
|
|
|
|
public Path getWorldPath(LevelResource worldSavePath) {
|
|
@@ -2977,15 +3022,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
}
|
|
|
|
public boolean isTimeProfilerRunning() {
|
|
- return this.debugCommandProfilerDelayStart || this.debugCommandProfiler != null;
|
|
+ return false; //this.debugCommandProfilerDelayStart || this.debugCommandProfiler != null; // Purpur
|
|
}
|
|
|
|
public void startTimeProfiler() {
|
|
- this.debugCommandProfilerDelayStart = true;
|
|
+ //this.debugCommandProfilerDelayStart = true; // Purpur
|
|
}
|
|
|
|
public ProfileResults stopTimeProfiler() {
|
|
- if (this.debugCommandProfiler == null) {
|
|
+ if (true || this.debugCommandProfiler == null) { // Purpur
|
|
return EmptyProfileResults.EMPTY;
|
|
} else {
|
|
ProfileResults methodprofilerresults = this.debugCommandProfiler.stop(Util.getNanos(), this.tickCount);
|
|
diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
|
index 8e2eb7b61421ceb063654826941f1a81f6f50bdf..1e85c9318ede93b8e9fe548a8945324b5b00e818 100644
|
|
--- a/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
|
+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
|
@@ -199,6 +199,7 @@ public class PlayerAdvancements {
|
|
|
|
if (advancementholder == null) {
|
|
if (!minecraftkey.getNamespace().equals("minecraft")) return; // CraftBukkit
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressIgnoredAdvancementWarnings) // Purpur
|
|
PlayerAdvancements.LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", minecraftkey, this.playerSavePath);
|
|
} else {
|
|
this.startProgress(advancementholder, advancementprogress);
|
|
@@ -249,6 +250,7 @@ public class PlayerAdvancements {
|
|
advancement.value().display().ifPresent((advancementdisplay) -> {
|
|
// Paper start - Add Adventure message to PlayerAdvancementDoneEvent
|
|
if (event.message() != null && this.player.serverLevel().getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) {
|
|
+ if (org.purpurmc.purpur.PurpurConfig.advancementOnlyBroadcastToAffectedPlayer) this.player.sendMessage(message); else // Purpur
|
|
this.playerList.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false);
|
|
// Paper end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/ServerFunctionManager.java b/src/main/java/net/minecraft/server/ServerFunctionManager.java
|
|
index 0b348f701b61c7b7ed0190eff8b2d73f3a3d5c74..ebd4d2463f88535edd69a1b63a65a635a5592ca2 100644
|
|
--- a/src/main/java/net/minecraft/server/ServerFunctionManager.java
|
|
+++ b/src/main/java/net/minecraft/server/ServerFunctionManager.java
|
|
@@ -54,10 +54,10 @@ public class ServerFunctionManager {
|
|
}
|
|
|
|
private void executeTagFunctions(Collection<CommandFunction<CommandSourceStack>> functions, ResourceLocation label) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
Objects.requireNonNull(label);
|
|
- gameprofilerfiller.push(label::toString);
|
|
+ //gameprofilerfiller.push(label::toString); // Purpur
|
|
Iterator iterator = functions.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
@@ -66,15 +66,15 @@ public class ServerFunctionManager {
|
|
this.execute(commandfunction, this.getGameLoopSender());
|
|
}
|
|
|
|
- Profiler.get().pop();
|
|
+ //Profiler.get().pop(); // Purpur
|
|
}
|
|
|
|
public void execute(CommandFunction<CommandSourceStack> function, CommandSourceStack source) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push(() -> {
|
|
+ /*gameprofilerfiller.push(() -> { // Purpur
|
|
return "function " + String.valueOf(function.id());
|
|
- });
|
|
+ });*/ // Purpur
|
|
|
|
try {
|
|
InstantiatedFunction<CommandSourceStack> instantiatedfunction = function.instantiate((CompoundTag) null, this.getDispatcher());
|
|
@@ -87,7 +87,7 @@ public class ServerFunctionManager {
|
|
} catch (Exception exception) {
|
|
ServerFunctionManager.LOGGER.warn("Failed to execute function {}", function.id(), exception);
|
|
} finally {
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/commands/EnchantCommand.java b/src/main/java/net/minecraft/server/commands/EnchantCommand.java
|
|
index cf0a5943f457c532958f40b4989fa18f967abae6..2ab8ff8ca51eb841932ccca4a348acc0141264a8 100644
|
|
--- a/src/main/java/net/minecraft/server/commands/EnchantCommand.java
|
|
+++ b/src/main/java/net/minecraft/server/commands/EnchantCommand.java
|
|
@@ -70,7 +70,7 @@ public class EnchantCommand {
|
|
|
|
private static int enchant(CommandSourceStack source, Collection<? extends Entity> targets, Holder<Enchantment> enchantment, int level) throws CommandSyntaxException {
|
|
Enchantment enchantment2 = enchantment.value();
|
|
- if (level > enchantment2.getMaxLevel()) {
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchantCommand && level > enchantment2.getMaxLevel()) { // Purpur - Config to allow unsafe enchants
|
|
throw ERROR_LEVEL_TOO_HIGH.create(level, enchantment2.getMaxLevel());
|
|
} else {
|
|
int i = 0;
|
|
@@ -81,7 +81,7 @@ public class EnchantCommand {
|
|
ItemStack itemStack = livingEntity.getMainHandItem();
|
|
if (!itemStack.isEmpty()) {
|
|
if (enchantment2.canEnchant(itemStack)
|
|
- && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantmentsForCrafting(itemStack).keySet(), enchantment)) {
|
|
+ && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantmentsForCrafting(itemStack).keySet(), enchantment) || (org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchantCommand && !itemStack.hasEnchantment(enchantment))) { // Purpur - Config to allow unsafe enchants
|
|
itemStack.enchant(enchantment, level);
|
|
i++;
|
|
} else if (targets.size() == 1) {
|
|
diff --git a/src/main/java/net/minecraft/server/commands/GameModeCommand.java b/src/main/java/net/minecraft/server/commands/GameModeCommand.java
|
|
index d1da3600dc07107309b20ebe6e7c0c4da0e8de76..244b4719c689f153fa36381a60acc280bb0bd9b3 100644
|
|
--- a/src/main/java/net/minecraft/server/commands/GameModeCommand.java
|
|
+++ b/src/main/java/net/minecraft/server/commands/GameModeCommand.java
|
|
@@ -57,6 +57,18 @@ public class GameModeCommand {
|
|
}
|
|
|
|
private static int setMode(CommandContext<CommandSourceStack> context, Collection<ServerPlayer> targets, GameType gameMode) {
|
|
+ // Purpur start
|
|
+ if (org.purpurmc.purpur.PurpurConfig.commandGamemodeRequiresPermission) {
|
|
+ String gamemode = gameMode.getName();
|
|
+ CommandSourceStack sender = context.getSource();
|
|
+ if (!sender.testPermission(2, "minecraft.command.gamemode." + gamemode)) {
|
|
+ return 0;
|
|
+ }
|
|
+ if (sender.getEntity() instanceof ServerPlayer player && (targets.size() > 1 || !targets.contains(player)) && !sender.testPermission(2, "minecraft.command.gamemode." + gamemode + ".other")) {
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
int i = 0;
|
|
|
|
for (ServerPlayer serverPlayer : targets) {
|
|
diff --git a/src/main/java/net/minecraft/server/commands/GiveCommand.java b/src/main/java/net/minecraft/server/commands/GiveCommand.java
|
|
index 0d9de4c61c7b26a6ff37c12fde629161fd0c3d5a..2f7897744f4aea718170698881773e9031a58a51 100644
|
|
--- a/src/main/java/net/minecraft/server/commands/GiveCommand.java
|
|
+++ b/src/main/java/net/minecraft/server/commands/GiveCommand.java
|
|
@@ -60,6 +60,7 @@ public class GiveCommand {
|
|
boolean flag = entityplayer.getInventory().add(itemstack1);
|
|
ItemEntity entityitem;
|
|
|
|
+ if (org.purpurmc.purpur.PurpurConfig.disableGiveCommandDrops) continue; // Purpur - add config option for toggling give command dropping
|
|
if (flag && itemstack1.isEmpty()) {
|
|
entityitem = entityplayer.drop(itemstack, false, false, false); // CraftBukkit - SPIGOT-2942: Add boolean to call event
|
|
if (entityitem != null) {
|
|
diff --git a/src/main/java/net/minecraft/server/commands/PerfCommand.java b/src/main/java/net/minecraft/server/commands/PerfCommand.java
|
|
index 8c587f829c5e8c6b6df3150024c4ae704988c47b..8ac4d5dbe7f8febf4226f26a6b035282dcdf1b0f 100644
|
|
--- a/src/main/java/net/minecraft/server/commands/PerfCommand.java
|
|
+++ b/src/main/java/net/minecraft/server/commands/PerfCommand.java
|
|
@@ -42,6 +42,7 @@ public class PerfCommand {
|
|
}
|
|
|
|
private static int startProfilingDedicatedServer(CommandSourceStack source) throws CommandSyntaxException {
|
|
+ if (true) return removedMessage(source); // Purpur
|
|
MinecraftServer minecraftServer = source.getServer();
|
|
if (minecraftServer.isRecordingMetrics()) {
|
|
throw ERROR_ALREADY_RUNNING.create();
|
|
@@ -55,6 +56,7 @@ public class PerfCommand {
|
|
}
|
|
|
|
private static int stopProfilingDedicatedServer(CommandSourceStack source) throws CommandSyntaxException {
|
|
+ if (true) return removedMessage(source); // Purpur
|
|
MinecraftServer minecraftServer = source.getServer();
|
|
if (!minecraftServer.isRecordingMetrics()) {
|
|
throw ERROR_NOT_RUNNING.create();
|
|
@@ -64,6 +66,18 @@ public class PerfCommand {
|
|
}
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ private static int removedMessage(CommandSourceStack source) {
|
|
+ if (true) {
|
|
+ net.kyori.adventure.text.minimessage.MiniMessage mm = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage();
|
|
+ source.getSender().sendMessage(mm.deserialize("<gold>Purpur has removed Mojang's Profiler to save your performance. Please use <click:suggest_command:'/spark'><grey>/spark</grey></click> instead"));
|
|
+ source.getSender().sendMessage(mm.deserialize("<gold>For more information, view its documentation at"));
|
|
+ source.getSender().sendMessage(mm.deserialize("<gold><click:open_url:'https://spark.lucko.me/docs/Command-Usage'>https://spark.lucko.me/docs/Command-Usage</click>"));
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
private static void saveResults(CommandSourceStack source, Path tempProfilingDirectory, MinecraftServer server) {
|
|
String string = String.format(
|
|
Locale.ROOT, "%s-%s-%s", Util.getFilenameFormattedDateTime(), server.getWorldData().getLevelName(), SharedConstants.getCurrentVersion().getId()
|
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
index 17a158ff6ce6520b69a5a0032ba4c05449dd0cf8..e9ad8e2ac267c46df80e884308df8bb12d0deeff 100644
|
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
@@ -111,6 +111,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
return;
|
|
}
|
|
// Paper start - Use TerminalConsoleAppender
|
|
+ if (DedicatedServer.this.gui == null || System.console() != null) // Purpur - has no GUI or has console (did not double-click)
|
|
new com.destroystokyo.paper.console.PaperConsole(DedicatedServer.this).start();
|
|
/*
|
|
jline.console.ConsoleReader bufferedreader = DedicatedServer.this.reader;
|
|
@@ -219,6 +220,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
org.spigotmc.SpigotConfig.registerCommands();
|
|
// Spigot end
|
|
io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // Paper - load mappings for stacktrace deobf and etc.
|
|
+ // Purpur start
|
|
+ try {
|
|
+ org.purpurmc.purpur.PurpurConfig.init((java.io.File) options.valueOf("purpur-settings"));
|
|
+ } catch (Exception e) {
|
|
+ DedicatedServer.LOGGER.error("Unable to load server configuration", e);
|
|
+ return false;
|
|
+ }
|
|
+ org.purpurmc.purpur.PurpurConfig.registerCommands();
|
|
+ // Purpur end
|
|
// Paper start - initialize global and world-defaults configuration
|
|
this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess());
|
|
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());
|
|
@@ -283,6 +293,30 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
if (true) throw new IllegalStateException("Failed to bind to port", ioexception); // Paper - Propagate failed to bind to port error
|
|
return false;
|
|
}
|
|
+ // Purpur start
|
|
+ if (org.purpurmc.purpur.PurpurConfig.useUPnP) {
|
|
+ LOGGER.info("[UPnP] Attempting to start UPnP port forwarding service...");
|
|
+ if (dev.omega24.upnp4j.UPnP4J.isUPnPAvailable()) {
|
|
+ if (dev.omega24.upnp4j.UPnP4J.isOpen(this.getPort(), dev.omega24.upnp4j.util.Protocol.TCP)) {
|
|
+ this.upnp = false;
|
|
+ LOGGER.info("[UPnP] Port {} is already open", this.getPort());
|
|
+ } else if (dev.omega24.upnp4j.UPnP4J.open(this.getPort(), dev.omega24.upnp4j.util.Protocol.TCP)) {
|
|
+ this.upnp = true;
|
|
+ LOGGER.info("[UPnP] Successfully opened port {}", this.getPort());
|
|
+ } else {
|
|
+ this.upnp = false;
|
|
+ LOGGER.info("[UPnP] Failed to open port {}", this.getPort());
|
|
+ }
|
|
+
|
|
+ if (upnp) {
|
|
+ LOGGER.info("[UPnP] {}:{}", dev.omega24.upnp4j.UPnP4J.getExternalIP(), this.getPort());
|
|
+ }
|
|
+ } else {
|
|
+ this.upnp = false;
|
|
+ LOGGER.error("[UPnP] Service is unavailable");
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
|
|
// CraftBukkit start
|
|
// this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // Spigot - moved up
|
|
@@ -356,6 +390,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
DedicatedServer.LOGGER.info("JMX monitoring enabled");
|
|
}
|
|
|
|
+ org.purpurmc.purpur.task.BossBarTask.startAll(); // Purpur
|
|
+ if (org.purpurmc.purpur.PurpurConfig.beeCountPayload) org.purpurmc.purpur.task.BeehiveTask.instance().register(); // Purpur
|
|
return true;
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
|
index 149a542c4afa09d491cb33ae33563ba15786758d..ee70e7a2f87ca31b1c2918148d585e90601d277b 100644
|
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
|
@@ -56,6 +56,7 @@ public class DedicatedServerProperties extends Settings<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 pvp = this.get("pvp", true);
|
|
public final boolean allowFlight = this.get("allow-flight", false);
|
|
public final String motd = this.get("motd", "A Minecraft Server");
|
|
diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
|
index 759062d219ff490a3cb19e710c4d18e3e08288e0..8f74c2ec5252b6265549589310d742337c91cb2c 100644
|
|
--- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
|
+++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
|
@@ -43,6 +43,11 @@ public class MinecraftServerGui extends JComponent {
|
|
private Thread logAppenderThread;
|
|
private final Collection<Runnable> finalizers = Lists.newArrayList();
|
|
final AtomicBoolean isClosing = new AtomicBoolean();
|
|
+ // Purpur start
|
|
+ private final CommandHistory history = new CommandHistory();
|
|
+ private String currentCommand = "";
|
|
+ private int historyIndex = 0;
|
|
+ // Purpur end
|
|
|
|
public static MinecraftServerGui showFrameFor(final DedicatedServer server) {
|
|
try {
|
|
@@ -51,7 +56,7 @@ public class MinecraftServerGui extends JComponent {
|
|
;
|
|
}
|
|
|
|
- final JFrame jframe = new JFrame("Minecraft server");
|
|
+ final JFrame jframe = new JFrame("Purpur Minecraft server"); // Purpur
|
|
final MinecraftServerGui servergui = new MinecraftServerGui(server);
|
|
|
|
jframe.setDefaultCloseOperation(2);
|
|
@@ -59,7 +64,7 @@ public class MinecraftServerGui extends JComponent {
|
|
jframe.pack();
|
|
jframe.setLocationRelativeTo((Component) null);
|
|
jframe.setVisible(true);
|
|
- jframe.setName("Minecraft server"); // Paper - Improve ServerGUI
|
|
+ jframe.setName("Purpur Minecraft server"); // Paper - Improve ServerGUI // Purpur
|
|
|
|
// Paper start - Improve ServerGUI
|
|
try {
|
|
@@ -71,7 +76,7 @@ public class MinecraftServerGui extends JComponent {
|
|
jframe.addWindowListener(new WindowAdapter() {
|
|
public void windowClosing(WindowEvent windowevent) {
|
|
if (!servergui.isClosing.getAndSet(true)) {
|
|
- jframe.setTitle("Minecraft server - shutting down!");
|
|
+ jframe.setTitle("Purpur Minecraft server - shutting down!"); // Purpur
|
|
server.halt(true);
|
|
servergui.runFinalizers();
|
|
}
|
|
@@ -159,7 +164,7 @@ public class MinecraftServerGui extends JComponent {
|
|
|
|
private JComponent buildChatPanel() {
|
|
JPanel jpanel = new JPanel(new BorderLayout());
|
|
- JTextArea jtextarea = new JTextArea();
|
|
+ org.purpurmc.purpur.gui.JColorTextPane jtextarea = new org.purpurmc.purpur.gui.JColorTextPane(); // Purpur
|
|
JScrollPane jscrollpane = new JScrollPane(jtextarea, 22, 30);
|
|
|
|
jtextarea.setEditable(false);
|
|
@@ -171,10 +176,43 @@ public class MinecraftServerGui extends JComponent {
|
|
|
|
if (!s.isEmpty()) {
|
|
this.server.handleConsoleInput(s, this.server.createCommandSourceStack());
|
|
+ // Purpur start
|
|
+ history.add(s);
|
|
+ historyIndex = -1;
|
|
+ // Purpur end
|
|
}
|
|
|
|
jtextfield.setText("");
|
|
});
|
|
+ // Purpur start
|
|
+ jtextfield.getInputMap().put(javax.swing.KeyStroke.getKeyStroke("UP"), "up");
|
|
+ jtextfield.getInputMap().put(javax.swing.KeyStroke.getKeyStroke("DOWN"), "down");
|
|
+ jtextfield.getActionMap().put("up", new javax.swing.AbstractAction() {
|
|
+ @Override
|
|
+ public void actionPerformed(java.awt.event.ActionEvent actionEvent) {
|
|
+ if (historyIndex < 0) {
|
|
+ currentCommand = jtextfield.getText();
|
|
+ }
|
|
+ if (historyIndex < history.size() - 1) {
|
|
+ jtextfield.setText(history.get(++historyIndex));
|
|
+ }
|
|
+ }
|
|
+ });
|
|
+ jtextfield.getActionMap().put("down", new javax.swing.AbstractAction() {
|
|
+ @Override
|
|
+ public void actionPerformed(java.awt.event.ActionEvent actionEvent) {
|
|
+ if (historyIndex >= 0) {
|
|
+ if (historyIndex == 0) {
|
|
+ --historyIndex;
|
|
+ jtextfield.setText(currentCommand);
|
|
+ } else {
|
|
+ --historyIndex;
|
|
+ jtextfield.setText(history.get(historyIndex));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ });
|
|
+ // Purpur end
|
|
jtextarea.addFocusListener(new FocusAdapter() { // CraftBukkit - decompile error
|
|
public void focusGained(FocusEvent focusevent) {}
|
|
});
|
|
@@ -210,7 +248,7 @@ public class MinecraftServerGui extends JComponent {
|
|
}
|
|
|
|
private static final java.util.regex.Pattern ANSI = java.util.regex.Pattern.compile("\\e\\[[\\d;]*[^\\d;]"); // CraftBukkit // Paper
|
|
- public void print(JTextArea textArea, JScrollPane scrollPane, String message) {
|
|
+ public void print(org.purpurmc.purpur.gui.JColorTextPane textArea, JScrollPane scrollPane, String message) { // Purpur
|
|
if (!SwingUtilities.isEventDispatchThread()) {
|
|
SwingUtilities.invokeLater(() -> {
|
|
this.print(textArea, scrollPane, message);
|
|
@@ -224,11 +262,14 @@ public class MinecraftServerGui extends JComponent {
|
|
flag = (double) jscrollbar.getValue() + jscrollbar.getSize().getHeight() + (double) (MinecraftServerGui.MONOSPACED.getSize() * 4) > (double) jscrollbar.getMaximum();
|
|
}
|
|
|
|
+ /* // Purpur
|
|
try {
|
|
document.insertString(document.getLength(), MinecraftServerGui.ANSI.matcher(message).replaceAll(""), (AttributeSet) null); // CraftBukkit
|
|
} catch (BadLocationException badlocationexception) {
|
|
;
|
|
}
|
|
+ */ // Purpur
|
|
+ textArea.append(message); // Purpur
|
|
|
|
if (flag) {
|
|
jscrollbar.setValue(Integer.MAX_VALUE);
|
|
@@ -236,4 +277,16 @@ public class MinecraftServerGui extends JComponent {
|
|
|
|
}
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ public static class CommandHistory extends java.util.LinkedList<String> {
|
|
+ @Override
|
|
+ public boolean add(String command) {
|
|
+ if (size() > 1000) {
|
|
+ remove();
|
|
+ }
|
|
+ return super.offerFirst(command);
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/gui/StatsComponent.java b/src/main/java/net/minecraft/server/gui/StatsComponent.java
|
|
index 096c89bd01cec2abd151bf6fffc4847d1bcd548f..cd0a8a6a1be75cab8bbb8ee3ac17bb732b9e7108 100644
|
|
--- a/src/main/java/net/minecraft/server/gui/StatsComponent.java
|
|
+++ b/src/main/java/net/minecraft/server/gui/StatsComponent.java
|
|
@@ -45,7 +45,7 @@ public class StatsComponent extends JComponent {
|
|
this.msgs[1] = "Avg tick: "
|
|
+ DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / (double)TimeUtil.NANOSECONDS_PER_MILLISECOND)
|
|
+ " ms";
|
|
- this.msgs[2] = "TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg);
|
|
+ this.msgs[2] = "TPS from last 5s, 1m, 5m, 15m: " + String.join(", ", tpsAvg); // Purpur
|
|
// Paper end - Improve ServerGUI
|
|
this.values[this.vp++ & 0xFF] = (int)(l * 100L / Runtime.getRuntime().maxMemory());
|
|
this.repaint();
|
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
index 5b3a886c624b36557cbfaccdc3fb05a46a4ba36a..e16f22dd82b4315da34af3c9a189d9d5fec0fd2f 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
@@ -406,16 +406,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
}
|
|
|
|
protected void tick(BooleanSupplier shouldKeepTicking) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("poi");
|
|
+ //gameprofilerfiller.push("poi"); // Purpur
|
|
this.poiManager.tick(shouldKeepTicking);
|
|
- gameprofilerfiller.popPush("chunk_unload");
|
|
+ //gameprofilerfiller.popPush("chunk_unload"); // Purpur
|
|
if (!this.level.noSave()) {
|
|
this.processUnloads(shouldKeepTicking);
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
public boolean hasWork() {
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
index 3c711e1df57ac5b0f8795ebb12299d275792b1d4..bb168636cbf23b5b0c7232529e390f434546dc37 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
@@ -442,38 +442,38 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
// CraftBukkit start - modelled on below
|
|
public void purgeUnload() {
|
|
if (true) return; // Paper - rewrite chunk system
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("purge");
|
|
+ //gameprofilerfiller.push("purge"); // Purpur
|
|
this.distanceManager.purgeStaleTickets();
|
|
this.runDistanceManagerUpdates();
|
|
- gameprofilerfiller.popPush("unload");
|
|
+ //gameprofilerfiller.popPush("unload"); // Purpur
|
|
this.chunkMap.tick(() -> true);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
this.clearCache();
|
|
}
|
|
// CraftBukkit end
|
|
|
|
@Override
|
|
public void tick(BooleanSupplier shouldKeepTicking, boolean tickChunks) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("purge");
|
|
+ //gameprofilerfiller.push("purge"); // Purpur
|
|
if (this.level.tickRateManager().runsNormally() || !tickChunks || this.level.spigotConfig.unloadFrozenChunks) { // Spigot
|
|
this.distanceManager.purgeStaleTickets();
|
|
}
|
|
|
|
this.runDistanceManagerUpdates();
|
|
- gameprofilerfiller.popPush("chunks");
|
|
+ //gameprofilerfiller.popPush("chunks"); // Purpur
|
|
if (tickChunks) {
|
|
((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getPlayerChunkLoader().tick(); // Paper - rewrite chunk system
|
|
this.tickChunks();
|
|
this.chunkMap.tick();
|
|
}
|
|
|
|
- gameprofilerfiller.popPush("unload");
|
|
+ //gameprofilerfiller.popPush("unload"); // Purpur
|
|
this.chunkMap.tick(shouldKeepTicking);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
this.clearCache();
|
|
}
|
|
|
|
@@ -483,34 +483,34 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
|
|
this.lastInhabitedUpdate = i;
|
|
if (!this.level.isDebug()) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("pollingChunks");
|
|
+ //gameprofilerfiller.push("pollingChunks"); // Purpur
|
|
if (this.level.tickRateManager().runsNormally()) {
|
|
List<LevelChunk> list = this.tickingChunks;
|
|
|
|
try {
|
|
- gameprofilerfiller.push("filteringTickingChunks");
|
|
+ //gameprofilerfiller.push("filteringTickingChunks"); // Purpur
|
|
this.collectTickingChunks(list);
|
|
- gameprofilerfiller.popPush("shuffleChunks");
|
|
+ //gameprofilerfiller.popPush("shuffleChunks"); // Purpur
|
|
// Paper start - chunk tick iteration optimisation
|
|
this.shuffleRandom.setSeed(this.level.random.nextLong());
|
|
if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled
|
|
// Paper end - chunk tick iteration optimisation
|
|
- this.tickChunks(gameprofilerfiller, j, list);
|
|
- gameprofilerfiller.pop();
|
|
+ this.tickChunks(null, j, list); // Purpur
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
} finally {
|
|
list.clear();
|
|
}
|
|
}
|
|
|
|
- this.broadcastChangedChunks(gameprofilerfiller);
|
|
- gameprofilerfiller.pop();
|
|
+ this.broadcastChangedChunks(null); // Purpur
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
}
|
|
|
|
- private void broadcastChangedChunks(ProfilerFiller profiler) {
|
|
- profiler.push("broadcast");
|
|
+ private void broadcastChangedChunks(ProfilerFiller profiler) { // Purpur
|
|
+ //profiler.push("broadcast"); // Purpur
|
|
Iterator iterator = this.chunkHoldersToBroadcast.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
@@ -523,7 +523,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
}
|
|
|
|
this.chunkHoldersToBroadcast.clear();
|
|
- profiler.pop();
|
|
+ //profiler.pop(); // Purpur
|
|
}
|
|
|
|
private void collectTickingChunks(List<LevelChunk> chunks) {
|
|
@@ -550,7 +550,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
}
|
|
|
|
private void tickChunks(ProfilerFiller profiler, long timeDelta, List<LevelChunk> chunks) {
|
|
- profiler.popPush("naturalSpawnCount");
|
|
+ //profiler.popPush("naturalSpawnCount"); // Purpur
|
|
int j = this.distanceManager.getNaturalSpawnChunkCount();
|
|
// Paper start - Optional per player mob spawns
|
|
final int naturalSpawnChunkCount = j;
|
|
@@ -577,7 +577,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
// Paper end - Optional per player mob spawns
|
|
|
|
this.lastSpawnState = spawnercreature_d;
|
|
- profiler.popPush("spawnAndTick");
|
|
+ //profiler.popPush("spawnAndTick"); // Purpur
|
|
boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
|
|
int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
|
|
List list1;
|
|
@@ -615,7 +615,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
}
|
|
}
|
|
|
|
- profiler.popPush("customSpawners");
|
|
+ //profiler.popPush("customSpawners"); // Purpur
|
|
if (flag) {
|
|
this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies);
|
|
}
|
|
@@ -813,7 +813,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
|
|
@Override
|
|
protected void doRunTask(Runnable task) {
|
|
- Profiler.get().incrementCounter("runTask");
|
|
+ //Profiler.get().incrementCounter("runTask"); // Purpur
|
|
super.doRunTask(task);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
index 90eb4927fa51ce3df86aa7b6c71f49150a03e337..d8717af85f539da807ddf866e17f1e643c83d3f6 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
@@ -81,7 +81,7 @@ public class ServerEntity {
|
|
@Nullable
|
|
private List<SynchedEntityData.DataValue<?>> trackedDataValues;
|
|
// CraftBukkit start
|
|
- private final Set<ServerPlayerConnection> trackedPlayers;
|
|
+ public final Set<ServerPlayerConnection> trackedPlayers; // Purpur - private -> 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/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
index 5964d601c05176f48167cc92057a59e52a4da92b..8dea24a5cef8f8d01285641bc73062c5078a061f 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
@@ -223,6 +223,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
private final StructureManager structureManager;
|
|
private final StructureCheck structureCheck;
|
|
private final boolean tickTime;
|
|
+ private double preciseTime; // Purpur
|
|
+ private boolean forceTime; // Purpur
|
|
private final RandomSequences randomSequences;
|
|
|
|
// CraftBukkit start
|
|
@@ -230,6 +232,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
public final UUID uuid;
|
|
public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent
|
|
public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent
|
|
+ public boolean hasRidableMoveEvent = false; // Purpur
|
|
|
|
public LevelChunk getChunkIfLoaded(int x, int z) {
|
|
return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately
|
|
@@ -597,7 +600,24 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
// CraftBukkit end
|
|
this.tickTime = flag1;
|
|
this.server = minecraftserver;
|
|
- this.customSpawners = list;
|
|
+ // Purpur start - enable/disable MobSpawners per world
|
|
+ this.customSpawners = Lists.newArrayList();
|
|
+ if (purpurConfig.phantomSpawning) {
|
|
+ customSpawners.add(new net.minecraft.world.level.levelgen.PhantomSpawner());
|
|
+ }
|
|
+ if (purpurConfig.patrolSpawning) {
|
|
+ customSpawners.add(new net.minecraft.world.level.levelgen.PatrolSpawner());
|
|
+ }
|
|
+ if (purpurConfig.catSpawning) {
|
|
+ customSpawners.add(new net.minecraft.world.entity.npc.CatSpawner());
|
|
+ }
|
|
+ if (purpurConfig.villageSiegeSpawning) {
|
|
+ customSpawners.add(new net.minecraft.world.entity.ai.village.VillageSiege());
|
|
+ }
|
|
+ if (purpurConfig.villagerTraderSpawning) {
|
|
+ customSpawners.add(new net.minecraft.world.entity.npc.WanderingTraderSpawner(iworlddataserver));
|
|
+ }
|
|
+ // Purpur end
|
|
this.serverLevelData = iworlddataserver;
|
|
ChunkGenerator chunkgenerator = worlddimension.generator();
|
|
// CraftBukkit start
|
|
@@ -669,6 +689,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
this.chunkDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.ChunkDataController((ServerLevel)(Object)this, this.chunkTaskScheduler);
|
|
// Paper end - rewrite chunk system
|
|
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
|
|
+ this.preciseTime = this.serverLevelData.getDayTime(); // Purpur
|
|
}
|
|
|
|
// Paper start
|
|
@@ -703,24 +724,24 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
}
|
|
|
|
public void tick(BooleanSupplier shouldKeepTicking) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
this.handlingTick = true;
|
|
TickRateManager tickratemanager = this.tickRateManager();
|
|
boolean flag = tickratemanager.runsNormally();
|
|
|
|
if (flag) {
|
|
- gameprofilerfiller.push("world border");
|
|
+ //gameprofilerfiller.push("world border"); // Purpur
|
|
this.getWorldBorder().tick();
|
|
- gameprofilerfiller.popPush("weather");
|
|
+ //gameprofilerfiller.popPush("weather"); // Purpur
|
|
this.advanceWeatherCycle();
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
int i = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE);
|
|
long j;
|
|
|
|
- if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) {
|
|
+ if (this.purpurConfig.playersSkipNight && this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) {
|
|
// CraftBukkit start
|
|
j = this.levelData.getDayTime() + 24000L;
|
|
TimeSkipEvent event = new TimeSkipEvent(this.getWorld(), TimeSkipEvent.SkipReason.NIGHT_SKIP, (j - j % 24000L) - this.getDayTime());
|
|
@@ -745,30 +766,30 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
this.tickTime();
|
|
}
|
|
|
|
- gameprofilerfiller.push("tickPending");
|
|
+ //gameprofilerfiller.push("tickPending"); // Purpur
|
|
if (!this.isDebug() && flag) {
|
|
j = this.getGameTime();
|
|
- gameprofilerfiller.push("blockTicks");
|
|
+ //gameprofilerfiller.push("blockTicks"); // Purpur
|
|
this.blockTicks.tick(j, paperConfig().environment.maxBlockTicks, this::tickBlock); // Paper - configurable max block ticks
|
|
- gameprofilerfiller.popPush("fluidTicks");
|
|
+ //gameprofilerfiller.popPush("fluidTicks"); // Purpur
|
|
this.fluidTicks.tick(j, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
- gameprofilerfiller.popPush("raid");
|
|
+ //gameprofilerfiller.popPush("raid"); // Purpur
|
|
if (flag) {
|
|
this.raids.tick();
|
|
}
|
|
|
|
- gameprofilerfiller.popPush("chunkSource");
|
|
+ //gameprofilerfiller.popPush("chunkSource"); // Purpur
|
|
this.getChunkSource().tick(shouldKeepTicking, true);
|
|
- gameprofilerfiller.popPush("blockEvents");
|
|
+ //gameprofilerfiller.popPush("blockEvents"); // Purpur
|
|
if (flag) {
|
|
this.runBlockEvents();
|
|
}
|
|
|
|
this.handlingTick = false;
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
boolean flag1 = !paperConfig().unsupportedSettings.disableWorldTickingWhenEmpty || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players // Paper - restore this
|
|
|
|
if (flag1) {
|
|
@@ -776,20 +797,20 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
}
|
|
|
|
if (flag1 || this.emptyTime++ < 300) {
|
|
- gameprofilerfiller.push("entities");
|
|
+ //gameprofilerfiller.push("entities"); // Purpur
|
|
if (this.dragonFight != null && flag) {
|
|
- gameprofilerfiller.push("dragonFight");
|
|
+ //gameprofilerfiller.push("dragonFight"); // Purpur
|
|
this.dragonFight.tick();
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
org.spigotmc.ActivationRange.activateEntities(this); // Spigot
|
|
this.entityTickList.forEach((entity) -> {
|
|
if (!entity.isRemoved()) {
|
|
if (!tickratemanager.isEntityFrozen(entity)) {
|
|
- gameprofilerfiller.push("checkDespawn");
|
|
+ //gameprofilerfiller.push("checkDespawn"); // Purpur
|
|
entity.checkDespawn();
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
if (true) { // Paper - rewrite chunk system
|
|
Entity entity1 = entity.getVehicle();
|
|
|
|
@@ -801,20 +822,20 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
entity.stopRiding();
|
|
}
|
|
|
|
- gameprofilerfiller.push("tick");
|
|
+ //gameprofilerfiller.push("tick"); // Purpur
|
|
this.guardEntityTick(this::tickNonPassenger, entity);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
}
|
|
}
|
|
});
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
this.tickBlockEntities();
|
|
}
|
|
|
|
- gameprofilerfiller.push("entityManagement");
|
|
+ //gameprofilerfiller.push("entityManagement"); // Purpur
|
|
// Paper - rewrite chunk system
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -834,6 +855,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
this.serverLevelData.getScheduledEvents().tick(this.server, i);
|
|
Profiler.get().pop();
|
|
if (this.serverLevelData.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) {
|
|
+ // Purpur start
|
|
+ int incrementTicks = isDay() ? this.purpurConfig.daytimeTicks : this.purpurConfig.nighttimeTicks;
|
|
+ if (incrementTicks != 12000) {
|
|
+ this.preciseTime += 12000 / (double) incrementTicks;
|
|
+ this.setDayTime(this.preciseTime);
|
|
+ } else
|
|
+ // Purpur end
|
|
this.setDayTime(this.levelData.getDayTime() + 1L);
|
|
}
|
|
|
|
@@ -842,7 +870,21 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
|
|
public void setDayTime(long timeOfDay) {
|
|
this.serverLevelData.setDayTime(timeOfDay);
|
|
+ // Purpur start
|
|
+ this.preciseTime = timeOfDay;
|
|
+ this.forceTime = false;
|
|
+ }
|
|
+ public void setDayTime(double i) {
|
|
+ this.serverLevelData.setDayTime((long) i);
|
|
+ this.forceTime = true;
|
|
+ // Purpur end
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ public boolean isForceTime() {
|
|
+ return this.forceTime;
|
|
}
|
|
+ // Purpur end
|
|
|
|
public void tickCustomSpawners(boolean spawnMonsters, boolean spawnAnimals) {
|
|
Iterator iterator = this.customSpawners.iterator();
|
|
@@ -920,9 +962,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
boolean flag = this.isRaining();
|
|
int j = chunkcoordintpair.getMinBlockX();
|
|
int k = chunkcoordintpair.getMinBlockZ();
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("thunder");
|
|
+ //gameprofilerfiller.push("thunder"); // Purpur
|
|
if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && simpleRandom.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder // Paper - optimise random ticking
|
|
BlockPos blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
|
|
|
|
@@ -931,10 +973,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01D) && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper - Configurable spawn chances for skeleton horses
|
|
|
|
if (flag1) {
|
|
- SkeletonHorse entityhorseskeleton = (SkeletonHorse) EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT);
|
|
+ // Purpur start
|
|
+ net.minecraft.world.entity.animal.horse.AbstractHorse entityhorseskeleton;
|
|
+ if (purpurConfig.zombieHorseSpawnChance > 0D && random.nextDouble() <= purpurConfig.zombieHorseSpawnChance) {
|
|
+ entityhorseskeleton = EntityType.ZOMBIE_HORSE.create(this, EntitySpawnReason.EVENT);
|
|
+ } else {
|
|
+ entityhorseskeleton = EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT);
|
|
+ if (entityhorseskeleton != null) ((SkeletonHorse) entityhorseskeleton).setTrap(true);
|
|
+ }
|
|
+ // Purpur end
|
|
|
|
if (entityhorseskeleton != null) {
|
|
- entityhorseskeleton.setTrap(true);
|
|
+ //entityhorseskeleton.setTrap(true); // Purpur - moved up
|
|
entityhorseskeleton.setAge(0);
|
|
entityhorseskeleton.setPos((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ());
|
|
this.addFreshEntity(entityhorseskeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit
|
|
@@ -951,7 +1001,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
}
|
|
}
|
|
|
|
- gameprofilerfiller.popPush("iceandsnow");
|
|
+ //gameprofilerfiller.popPush("iceandsnow"); // Purpur
|
|
|
|
if (!this.paperConfig().environment.disableIceAndSnow) { // Paper - Option to disable ice and snow
|
|
for (int l = 0; l < randomTickSpeed; ++l) {
|
|
@@ -961,12 +1011,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
}
|
|
} // Paper - Option to disable ice and snow
|
|
|
|
- gameprofilerfiller.popPush("tickBlocks");
|
|
+ //gameprofilerfiller.popPush("tickBlocks"); // Purpur
|
|
if (randomTickSpeed > 0) {
|
|
this.optimiseRandomTick(chunk, randomTickSpeed); // Paper - optimise random ticking
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
@VisibleForTesting
|
|
@@ -1015,7 +1065,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
return holder.is(PoiTypes.LIGHTNING_ROD);
|
|
}, (blockposition1) -> {
|
|
return blockposition1.getY() == this.getHeight(Heightmap.Types.WORLD_SURFACE, blockposition1.getX(), blockposition1.getZ()) - 1;
|
|
- }, pos, 128, PoiManager.Occupancy.ANY);
|
|
+ }, pos, org.purpurmc.purpur.PurpurConfig.lightningRodRange, PoiManager.Occupancy.ANY);
|
|
|
|
return optional.map((blockposition1) -> {
|
|
return blockposition1.above(1);
|
|
@@ -1064,11 +1114,27 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
if (this.canSleepThroughNights()) {
|
|
if (!this.getServer().isSingleplayer() || this.getServer().isPublished()) {
|
|
int i = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE);
|
|
- MutableComponent ichatmutablecomponent;
|
|
+ Component ichatmutablecomponent;
|
|
|
|
if (this.sleepStatus.areEnoughSleeping(i)) {
|
|
+ // Purpur start
|
|
+ if (org.purpurmc.purpur.PurpurConfig.sleepSkippingNight.isBlank()) {
|
|
+ return;
|
|
+ }
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.sleepSkippingNight.equalsIgnoreCase("default")) {
|
|
+ ichatmutablecomponent = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepSkippingNight));
|
|
+ } else
|
|
ichatmutablecomponent = Component.translatable("sleep.skipping_night");
|
|
} else {
|
|
+ if (org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent.isBlank()) {
|
|
+ return;
|
|
+ }
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent.equalsIgnoreCase("default")) {
|
|
+ ichatmutablecomponent = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent,
|
|
+ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("count", Integer.toString(this.sleepStatus.amountSleeping())),
|
|
+ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("total", Integer.toString(this.sleepStatus.sleepersNeeded(i)))));
|
|
+ } else
|
|
+ // Purpur end
|
|
ichatmutablecomponent = Component.translatable("sleep.players_sleeping", this.sleepStatus.amountSleeping(), this.sleepStatus.sleepersNeeded(i));
|
|
}
|
|
|
|
@@ -1208,6 +1274,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
@VisibleForTesting
|
|
public void resetWeatherCycle() {
|
|
// CraftBukkit start
|
|
+ if (this.purpurConfig.rainStopsAfterSleep) // Purpur
|
|
this.serverLevelData.setRaining(false, org.bukkit.event.weather.WeatherChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents
|
|
// If we stop due to everyone sleeping we should reset the weather duration to some other random value.
|
|
// Not that everyone ever manages to get the whole server to sleep at the same time....
|
|
@@ -1215,6 +1282,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
this.serverLevelData.setRainTime(0);
|
|
}
|
|
// CraftBukkit end
|
|
+ if (this.purpurConfig.thunderStopsAfterSleep) // Purpur
|
|
this.serverLevelData.setThundering(false, org.bukkit.event.weather.ThunderChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents
|
|
// CraftBukkit start
|
|
// If we stop due to everyone sleeping we should reset the weather duration to some other random value.
|
|
@@ -1286,19 +1354,19 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
}*/ // Paper - comment out EAR 2
|
|
// Spigot end
|
|
entity.setOldPosAndRot();
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
++entity.tickCount;
|
|
- gameprofilerfiller.push(() -> {
|
|
+ /*gameprofilerfiller.push(() -> { // Purpur
|
|
return BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString();
|
|
- });
|
|
- gameprofilerfiller.incrementCounter("tickNonPassenger");
|
|
+ });*/ // Purpur
|
|
+ //gameprofilerfiller.incrementCounter("tickNonPassenger"); // Purpur
|
|
final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(entity); // Paper - EAR 2
|
|
if (isActive) { // Paper - EAR 2
|
|
entity.tick();
|
|
entity.postTick(); // CraftBukkit
|
|
} else { entity.inactiveTick(); } // Paper - EAR 2
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
Iterator iterator = entity.getPassengers().iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
@@ -1321,12 +1389,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
if (passenger instanceof Player || this.entityTickList.contains(passenger)) {
|
|
passenger.setOldPosAndRot();
|
|
++passenger.tickCount;
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push(() -> {
|
|
+ /*gameprofilerfiller.push(() -> { // Purpur
|
|
return BuiltInRegistries.ENTITY_TYPE.getKey(passenger.getType()).toString();
|
|
- });
|
|
- gameprofilerfiller.incrementCounter("tickPassenger");
|
|
+ });*/ // Purpur
|
|
+ //gameprofilerfiller.incrementCounter("tickPassenger"); // Purpur
|
|
// Paper start - EAR 2
|
|
if (isActive) {
|
|
passenger.rideTick();
|
|
@@ -1338,7 +1406,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
vehicle.positionRider(passenger);
|
|
}
|
|
// Paper end - EAR 2
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
Iterator iterator = passenger.getPassengers().iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
@@ -2740,7 +2808,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
// Spigot Start
|
|
if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message
|
|
// Paper start - Fix merchant inventory not closing on entity removal
|
|
- if (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) {
|
|
+ if (!entity.level().purpurConfig.playerVoidTrading && entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) { // Purpur
|
|
merchant.getTrader().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED);
|
|
}
|
|
// Paper end - Fix merchant inventory not closing on entity removal
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
index cffbd3300967e5d80b5973b35a76235bb2aa1b73..17f5640ab2b6880895b3b96ae06db8b0e3c03a02 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
@@ -329,6 +329,10 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
public com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent
|
|
public @Nullable String clientBrandName = null; // Paper - Brand support
|
|
public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event
|
|
+ public boolean purpurClient = false; // Purpur
|
|
+ private boolean tpsBar = false; // Purpur
|
|
+ private boolean compassBar = false; // Purpur
|
|
+ private boolean ramBar = false; // Purpur
|
|
|
|
// Paper start - rewrite chunk system
|
|
private ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader;
|
|
@@ -691,6 +695,9 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
});
|
|
}
|
|
|
|
+ if (nbt.contains("Purpur.TPSBar")) { this.tpsBar = nbt.getBoolean("Purpur.TPSBar"); } // Purpur
|
|
+ if (nbt.contains("Purpur.CompassBar")) { this.compassBar = nbt.getBoolean("Purpur.CompassBar"); } // Purpur
|
|
+ if (nbt.contains("Purpur.RamBar")) { this.ramBar = nbt.getBoolean("Purpur.RamBar"); } // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -743,6 +750,9 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
}
|
|
|
|
this.saveEnderPearls(nbt);
|
|
+ nbt.putBoolean("Purpur.RamBar", this.ramBar); // Purpur
|
|
+ nbt.putBoolean("Purpur.TPSBar", this.tpsBar); // Purpur
|
|
+ nbt.putBoolean("Purpur.CompassBar", this.compassBar); // Purpur
|
|
}
|
|
|
|
private void saveParentVehicle(CompoundTag nbt) {
|
|
@@ -1032,6 +1042,15 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
this.trackEnteredOrExitedLavaOnVehicle();
|
|
this.updatePlayerAttributes();
|
|
this.advancements.flushDirty(this);
|
|
+
|
|
+ // Purpur start
|
|
+ if (this.level().purpurConfig.useNightVisionWhenRiding && this.getVehicle() != null && this.getVehicle().getRider() == this && this.level().getGameTime() % 100 == 0) { // 5 seconds
|
|
+ MobEffectInstance nightVision = this.getEffect(MobEffects.NIGHT_VISION);
|
|
+ if (nightVision == null || nightVision.getDuration() <= 300) { // 15 seconds
|
|
+ this.addEffect(new MobEffectInstance(MobEffects.NIGHT_VISION, 400, 0)); // 20 seconds
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
|
|
private void updatePlayerAttributes() {
|
|
@@ -1329,6 +1348,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
}));
|
|
PlayerTeam scoreboardteam = this.getTeam();
|
|
|
|
+ if (org.purpurmc.purpur.PurpurConfig.deathMessageOnlyBroadcastToAffectedPlayer) this.sendSystemMessage(ichatbasecomponent); else // Purpur
|
|
if (scoreboardteam != null && scoreboardteam.getDeathMessageVisibility() != Team.Visibility.ALWAYS) {
|
|
if (scoreboardteam.getDeathMessageVisibility() == Team.Visibility.HIDE_FOR_OTHER_TEAMS) {
|
|
this.server.getPlayerList().broadcastSystemToTeam(this, ichatbasecomponent);
|
|
@@ -1432,6 +1452,16 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
if (this.isInvulnerableTo(world, source)) {
|
|
return false;
|
|
} else {
|
|
+ // Purpur start
|
|
+ if (source.is(DamageTypeTags.IS_FALL)) { // Purpur
|
|
+ if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.AbstractMinecart && level().purpurConfig.minecartControllable && !level().purpurConfig.minecartControllableFallDamage) {
|
|
+ return false;
|
|
+ }
|
|
+ if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.Boat && !level().purpurConfig.boatsDoFallDamage) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
boolean flag = this.server.isDedicatedServer() && this.isPvpAllowed() && source.is(DamageTypeTags.IS_FALL);
|
|
|
|
if (!flag && this.spawnInvulnerableTime > 0 && !source.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) {
|
|
@@ -1643,15 +1673,15 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
this.unsetRemoved();
|
|
*/
|
|
// CraftBukkit end
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("moving");
|
|
+ //gameprofilerfiller.push("moving"); // Purpur
|
|
if (worldserver != null && resourcekey == LevelStem.OVERWORLD && worldserver.getTypeKey() == LevelStem.NETHER) { // CraftBukkit - empty to fall through to null to event
|
|
this.enteredNetherPosition = this.position();
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("placing");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("placing"); // Purpur
|
|
// CraftBukkit start
|
|
this.isChangingDimension = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds
|
|
LevelData worlddata = worldserver.getLevelData();
|
|
@@ -1664,11 +1694,12 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
worldserver1.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION);
|
|
this.unsetRemoved();
|
|
// CraftBukkit end
|
|
+ this.portalPos = io.papermc.paper.util.MCUtil.toBlockPosition(exit); // Purpur - Fix stuck in portals
|
|
this.setServerLevel(worldserver);
|
|
this.connection.internalTeleport(PositionMoveRotation.of(teleportTarget), teleportTarget.relatives()); // CraftBukkit - use internal teleport without event
|
|
this.connection.resetPosition();
|
|
worldserver.addDuringTeleport(this);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
this.triggerDimensionChangeTriggers(worldserver1);
|
|
this.stopUsingItem();
|
|
this.connection.send(new ClientboundPlayerAbilitiesPacket(this.getAbilities()));
|
|
@@ -1774,7 +1805,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
return entitymonster.isPreventingPlayerRest(this.serverLevel(), this);
|
|
});
|
|
|
|
- if (!list.isEmpty()) {
|
|
+ if (!this.level().purpurConfig.playerSleepNearMonsters && !list.isEmpty()) { // Purpur
|
|
return Either.left(net.minecraft.world.entity.player.Player.BedSleepingProblem.NOT_SAFE);
|
|
}
|
|
}
|
|
@@ -1814,7 +1845,19 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
});
|
|
|
|
if (!this.serverLevel().canSleepThroughNights()) {
|
|
- this.displayClientMessage(Component.translatable("sleep.not_possible"), true);
|
|
+ // Purpur start
|
|
+ Component clientMessage;
|
|
+ if (org.purpurmc.purpur.PurpurConfig.sleepNotPossible.isBlank()) {
|
|
+ clientMessage = null;
|
|
+ } else if (!org.purpurmc.purpur.PurpurConfig.sleepNotPossible.equalsIgnoreCase("default")) {
|
|
+ clientMessage = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepNotPossible));
|
|
+ } else {
|
|
+ clientMessage = Component.translatable("sleep.not_possible");
|
|
+ }
|
|
+ if (clientMessage != null) {
|
|
+ this.displayClientMessage(clientMessage, true);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
|
|
((ServerLevel) this.level()).updateSleepingPlayerList();
|
|
@@ -1936,6 +1979,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
|
|
@Override
|
|
public void openTextEdit(SignBlockEntity sign, boolean front) {
|
|
+ if (level().purpurConfig.signAllowColors) this.connection.send(sign.getTranslatedUpdatePacket(textFilteringEnabled, front)); // Purpur
|
|
this.connection.send(new ClientboundBlockUpdatePacket(this.level(), sign.getBlockPos()));
|
|
this.connection.send(new ClientboundOpenSignEditorPacket(sign.getBlockPos(), front));
|
|
}
|
|
@@ -2252,6 +2296,26 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
this.lastSentExp = -1; // CraftBukkit - Added to reset
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public void sendActionBarMessage(@Nullable String message) {
|
|
+ if (message != null && !message.isEmpty()) {
|
|
+ sendActionBarMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void sendActionBarMessage(@Nullable net.kyori.adventure.text.Component message) {
|
|
+ if (message != null) {
|
|
+ sendActionBarMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void sendActionBarMessage(@Nullable Component message) {
|
|
+ if (message != null) {
|
|
+ displayClientMessage(message, true);
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public void displayClientMessage(Component message, boolean overlay) {
|
|
this.sendSystemMessage(message, overlay);
|
|
@@ -2476,6 +2540,20 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
return new CommandSourceStack(this.commandSource(), this.position(), this.getRotationVector(), this.serverLevel(), this.getPermissionLevel(), this.getName().getString(), this.getDisplayName(), this.server, this);
|
|
}
|
|
|
|
+ // Purpur Start
|
|
+ public void sendMiniMessage(@Nullable String message) {
|
|
+ if (message != null && !message.isEmpty()) {
|
|
+ this.sendMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void sendMessage(@Nullable net.kyori.adventure.text.Component message) {
|
|
+ if (message != null) {
|
|
+ this.sendSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message));
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public void sendSystemMessage(Component message) {
|
|
this.sendSystemMessage(message, false);
|
|
}
|
|
@@ -2600,8 +2678,68 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
|
|
public void resetLastActionTime() {
|
|
this.lastActionTime = Util.getMillis();
|
|
+ this.setAfk(false); // Purpur
|
|
}
|
|
|
|
+ // Purpur Start
|
|
+ private boolean isAfk = false;
|
|
+
|
|
+ @Override
|
|
+ public void setAfk(boolean afk) {
|
|
+ if (this.isAfk == afk) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ String msg = afk ? org.purpurmc.purpur.PurpurConfig.afkBroadcastAway : org.purpurmc.purpur.PurpurConfig.afkBroadcastBack;
|
|
+
|
|
+ org.purpurmc.purpur.event.PlayerAFKEvent event = new org.purpurmc.purpur.event.PlayerAFKEvent(this.getBukkitEntity(), afk, this.level().purpurConfig.idleTimeoutKick, msg, !Bukkit.isPrimaryThread());
|
|
+ if (!event.callEvent() || event.shouldKick()) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ this.isAfk = afk;
|
|
+
|
|
+ if (!afk) {
|
|
+ resetLastActionTime();
|
|
+ }
|
|
+
|
|
+ msg = event.getBroadcastMsg();
|
|
+ if (msg != null && !msg.isEmpty()) {
|
|
+ String playerName = this.getGameProfile().getName();
|
|
+ if (org.purpurmc.purpur.PurpurConfig.afkBroadcastUseDisplayName) {
|
|
+ net.kyori.adventure.text.Component playerDisplayNameComponent = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(this.getBukkitEntity().getDisplayName());
|
|
+ playerName = net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer.plainText().serialize(playerDisplayNameComponent);
|
|
+ }
|
|
+ server.getPlayerList().broadcastMiniMessage(String.format(msg, playerName), false);
|
|
+ }
|
|
+
|
|
+ if (this.level().purpurConfig.idleTimeoutUpdateTabList) {
|
|
+ String scoreboardName = getScoreboardName();
|
|
+ String playerListName = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().serialize(getBukkitEntity().playerListName());
|
|
+ String[] split = playerListName.split(scoreboardName);
|
|
+ String prefix = (split.length > 0 ? split[0] : "").replace(org.purpurmc.purpur.PurpurConfig.afkTabListPrefix, "");
|
|
+ String suffix = (split.length > 1 ? split[1] : "").replace(org.purpurmc.purpur.PurpurConfig.afkTabListSuffix, "");
|
|
+ if (afk) {
|
|
+ getBukkitEntity().setPlayerListName(org.purpurmc.purpur.PurpurConfig.afkTabListPrefix + prefix + scoreboardName + suffix + org.purpurmc.purpur.PurpurConfig.afkTabListSuffix, true);
|
|
+ } else {
|
|
+ getBukkitEntity().setPlayerListName(prefix + scoreboardName + suffix, true);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ((ServerLevel) this.level()).updateSleepingPlayerList();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isAfk() {
|
|
+ return this.isAfk;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canBeCollidedWith() {
|
|
+ return !this.isAfk() && super.canBeCollidedWith();
|
|
+ }
|
|
+ // Purpur End
|
|
+
|
|
public ServerStatsCounter getStats() {
|
|
return this.stats;
|
|
}
|
|
@@ -3308,4 +3446,50 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
|
return (CraftPlayer) super.getBukkitEntity();
|
|
}
|
|
// CraftBukkit end
|
|
+
|
|
+ // Purpur start
|
|
+ public void teleport(Location to) {
|
|
+ this.ejectPassengers();
|
|
+ this.stopRiding(true);
|
|
+
|
|
+ if (this.isSleeping()) {
|
|
+ this.stopSleepInBed(true, false);
|
|
+ }
|
|
+
|
|
+ if (this.containerMenu != this.inventoryMenu) {
|
|
+ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.TELEPORT);
|
|
+ }
|
|
+
|
|
+ ServerLevel toLevel = ((CraftWorld) to.getWorld()).getHandle();
|
|
+ if (this.level() == toLevel) {
|
|
+ this.connection.teleport(to);
|
|
+ } else {
|
|
+ this.server.getPlayerList().respawn(this, true, RemovalReason.KILLED, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.DEATH, to);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public boolean tpsBar() {
|
|
+ return this.tpsBar;
|
|
+ }
|
|
+
|
|
+ public void tpsBar(boolean tpsBar) {
|
|
+ this.tpsBar = tpsBar;
|
|
+ }
|
|
+
|
|
+ public boolean compassBar() {
|
|
+ return this.compassBar;
|
|
+ }
|
|
+
|
|
+ public void compassBar(boolean compassBar) {
|
|
+ this.compassBar = compassBar;
|
|
+ }
|
|
+
|
|
+ public boolean ramBar() {
|
|
+ return this.ramBar;
|
|
+ }
|
|
+
|
|
+ public void ramBar(boolean ramBar) {
|
|
+ this.ramBar = ramBar;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
|
index a96f859a5d0c6ec692d4627a69f3c9ee49199dbc..88eb3774f688bcff383efa7f113bd0b1b97d8a11 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
|
@@ -403,6 +403,7 @@ public class ServerPlayerGameMode {
|
|
} else {capturedBlockEntity = true;} // Paper - Send block entities after destroy prediction
|
|
return false;
|
|
}
|
|
+ if (this.player.level().purpurConfig.slabHalfBreak && this.player.isShiftKeyDown() && iblockdata.getBlock() instanceof net.minecraft.world.level.block.SlabBlock && ((net.minecraft.world.level.block.SlabBlock) iblockdata.getBlock()).halfBreak(iblockdata, pos, this.player)) return true; // Purpur
|
|
}
|
|
// CraftBukkit end
|
|
|
|
@@ -523,6 +524,7 @@ public class ServerPlayerGameMode {
|
|
public InteractionHand interactHand;
|
|
public ItemStack interactItemStack;
|
|
public InteractionResult useItemOn(ServerPlayer player, Level world, ItemStack stack, InteractionHand hand, BlockHitResult hitResult) {
|
|
+ if (shiftClickMended(stack)) return InteractionResult.SUCCESS; // Purpur
|
|
BlockPos blockposition = hitResult.getBlockPos();
|
|
BlockState iblockdata = world.getBlockState(blockposition);
|
|
boolean cancelledBlock = false;
|
|
@@ -583,7 +585,7 @@ public class ServerPlayerGameMode {
|
|
ItemStack itemstack1 = stack.copy();
|
|
InteractionResult enuminteractionresult;
|
|
|
|
- if (!flag1) {
|
|
+ if (!flag1 || (player.level().purpurConfig.composterBulkProcess && iblockdata.is(Blocks.COMPOSTER))) { // Purpur
|
|
InteractionResult enuminteractionresult1 = iblockdata.useItemOn(player.getItemInHand(hand), world, player, hand, hitResult);
|
|
|
|
if (enuminteractionresult1.consumesAction()) {
|
|
@@ -631,4 +633,18 @@ public class ServerPlayerGameMode {
|
|
public void setLevel(ServerLevel world) {
|
|
this.level = world;
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ public boolean shiftClickMended(ItemStack itemstack) {
|
|
+ if (this.player.level().purpurConfig.shiftRightClickRepairsMendingPoints > 0 && this.player.isShiftKeyDown() && this.player.getBukkitEntity().hasPermission("purpur.mending_shift_click")) {
|
|
+ int points = Math.min(this.player.totalExperience, this.player.level().purpurConfig.shiftRightClickRepairsMendingPoints);
|
|
+ if (points > 0 && itemstack.isDamaged() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.MENDING, itemstack) > 0) {
|
|
+ this.player.giveExperiencePoints(-points);
|
|
+ this.player.level().addFreshEntity(new net.minecraft.world.entity.ExperienceOrb(this.player.level(), this.player.getX(), this.player.getY(), this.player.getZ(), points, org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN, this.player, this.player));
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java
|
|
index e4b0dc3121101d54394a0c3a413dabf8103b2ea6..a8484b9659f175cc20985bf66082616ceb31df4d 100644
|
|
--- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java
|
|
+++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java
|
|
@@ -336,6 +336,7 @@ public class WorldGenRegion implements WorldGenLevel {
|
|
return true;
|
|
} else {
|
|
// Paper start - Buffer OOB setBlock calls
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressSetBlockFarChunk) // Purpur
|
|
if (!hasSetFarWarned) {
|
|
Util.logAndPauseIfInIde("Detected setBlock in a far chunk [" + i + ", " + j + "], pos: " + String.valueOf(pos) + ", status: " + String.valueOf(this.generatingStep.targetStatus()) + (this.currentlyGenerating == null ? "" : ", currently generating: " + (String) this.currentlyGenerating.get()));
|
|
hasSetFarWarned = true;
|
|
diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
|
index b0bc66dc7248aae691dcab68b925b52a1695e63f..49cb116fd55e6d5cd36b9773b39191e4ab06b7e0 100644
|
|
--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
|
+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
|
@@ -80,11 +80,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
|
private long keepAliveChallenge;
|
|
private long closedListenerTime;
|
|
private boolean closed = false;
|
|
+ private it.unimi.dsi.fastutil.longs.LongList keepAlives = new it.unimi.dsi.fastutil.longs.LongArrayList(); // Purpur
|
|
private int latency;
|
|
private volatile boolean suspendFlushingOnServerThread = false;
|
|
public final java.util.Map<java.util.UUID, net.kyori.adventure.resource.ResourcePackCallback> packCallbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - adventure resource pack callbacks
|
|
private static final long KEEPALIVE_LIMIT = Long.getLong("paper.playerconnection.keepalive", 30) * 1000; // Paper - provide property to set keepalive limit
|
|
protected static final ResourceLocation MINECRAFT_BRAND = ResourceLocation.withDefaultNamespace("brand"); // Paper - Brand support
|
|
+ protected static final ResourceLocation PURPUR_CLIENT = ResourceLocation.fromNamespaceAndPath("purpur", "client"); // Purpur
|
|
|
|
public ServerCommonPacketListenerImpl(MinecraftServer minecraftserver, Connection networkmanager, CommonListenerCookie commonlistenercookie, ServerPlayer player) { // CraftBukkit
|
|
this.server = minecraftserver;
|
|
@@ -136,6 +138,16 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
|
|
|
@Override
|
|
public void handleKeepAlive(ServerboundKeepAlivePacket packet) {
|
|
+ // Purpur start
|
|
+ if (org.purpurmc.purpur.PurpurConfig.useAlternateKeepAlive) {
|
|
+ if (this.keepAlivePending && !keepAlives.isEmpty() && keepAlives.contains(packet.getId())) {
|
|
+ int ping = (int) (Util.getMillis() - packet.getId());
|
|
+ this.latency = (this.latency * 3 + ping) / 4;
|
|
+ this.keepAlivePending = false;
|
|
+ keepAlives.clear(); // we got a valid response, lets roll with it and forget the rest
|
|
+ }
|
|
+ } else
|
|
+ // Purpur end
|
|
//PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // CraftBukkit // Paper - handle ServerboundKeepAlivePacket async
|
|
if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) {
|
|
int i = (int) (Util.getMillis() - this.keepAliveTime);
|
|
@@ -179,6 +191,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
|
ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t register custom payload", ex);
|
|
this.disconnect(Component.literal("Invalid payload REGISTER!"), PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause
|
|
}
|
|
+ // Purpur start
|
|
+ } else if (identifier.equals(PURPUR_CLIENT)) {
|
|
+ try {
|
|
+ player.purpurClient = true;
|
|
+ } catch (Exception ignore) {
|
|
+ }
|
|
+ // Purpur end
|
|
} else if (identifier.equals(ServerCommonPacketListenerImpl.CUSTOM_UNREGISTER)) {
|
|
try {
|
|
String channels = payload.toString(com.google.common.base.Charsets.UTF_8);
|
|
@@ -255,12 +274,27 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
|
}
|
|
|
|
protected void keepConnectionAlive() {
|
|
- Profiler.get().push("keepAlive");
|
|
+ //Profiler.get().push("keepAlive"); // Purpur
|
|
// Paper start - give clients a longer time to respond to pings as per pre 1.12.2 timings
|
|
// This should effectively place the keepalive handling back to "as it was" before 1.12.2
|
|
long currentTime = Util.getMillis();
|
|
long elapsedTime = currentTime - this.keepAliveTime;
|
|
|
|
+ // Purpur start
|
|
+ if (org.purpurmc.purpur.PurpurConfig.useAlternateKeepAlive) {
|
|
+ if (elapsedTime >= 1000L) { // 1 second
|
|
+ if (this.keepAlivePending && !this.processedDisconnect && keepAlives.size() * 1000L >= KEEPALIVE_LIMIT) {
|
|
+ this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT);
|
|
+ } else if (this.checkIfClosed(currentTime)) {
|
|
+ this.keepAlivePending = true;
|
|
+ this.keepAliveTime = currentTime; // hijack this field for 1 second intervals
|
|
+ this.keepAlives.add(currentTime); // currentTime is ID
|
|
+ this.send(new ClientboundKeepAlivePacket(currentTime));
|
|
+ }
|
|
+ }
|
|
+ } else
|
|
+ // Purpur end
|
|
+
|
|
if (!this.isSingleplayerOwner() && elapsedTime >= 15000L) { // Paper - use vanilla's 15000L between keep alive packets
|
|
if (this.keepAlivePending && !this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // Paper - check keepalive limit, don't fire if already disconnected
|
|
this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause
|
|
@@ -273,7 +307,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
|
}
|
|
// Paper end - give clients a longer time to respond to pings as per pre 1.12.2 timings
|
|
|
|
- Profiler.get().pop();
|
|
+ //Profiler.get().pop(); // Purpur
|
|
}
|
|
|
|
private boolean checkIfClosed(long time) {
|
|
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
index b5d5dbc50a7b8c40739a15f164ffd08fdc534f9c..50bc64000f24aa2ae0df2ce7fc77f27d760b8764 100644
|
|
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
@@ -342,6 +342,20 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
private boolean justTeleported = false;
|
|
// CraftBukkit end
|
|
|
|
+ // 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
|
|
+
|
|
@Override
|
|
public void tick() {
|
|
if (this.ackBlockChangesUpTo > -1) {
|
|
@@ -398,6 +412,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
this.recipeSpamPackets.tick(); // Paper - auto recipe limit
|
|
this.dropSpamThrottler.tick();
|
|
if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L && !this.player.wonGame) { // Paper - Prevent AFK kick while watching end credits
|
|
+ // Purpur start
|
|
+ this.player.setAfk(true);
|
|
+ if (!this.player.level().purpurConfig.idleTimeoutKick || (!Boolean.parseBoolean(System.getenv("PURPUR_FORCE_IDLE_KICK")) && kickPermissionCache.getUnchecked(this.player.getBukkitEntity()))) {
|
|
+ return;
|
|
+ }
|
|
+ // Purpur end
|
|
this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854
|
|
this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause
|
|
}
|
|
@@ -663,6 +683,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
this.lastYaw = to.getYaw();
|
|
this.lastPitch = to.getPitch();
|
|
|
|
+ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetLastActionTime(); // Purpur
|
|
+
|
|
Location oldTo = to.clone();
|
|
PlayerMoveEvent event = new PlayerMoveEvent(player, from, to);
|
|
this.cserver.getPluginManager().callEvent(event);
|
|
@@ -739,6 +761,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
|
if (packet.getId() == this.awaitingTeleport) {
|
|
if (this.awaitingPositionFromClient == null) {
|
|
+ ServerGamePacketListenerImpl.LOGGER.warn("Disconnected on accept teleport packet. Was not expecting position data from client at this time"); // Purpur
|
|
this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause
|
|
return;
|
|
}
|
|
@@ -1180,6 +1203,10 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
final int maxBookPageSize = pageMax.intValue();
|
|
final double multiplier = Math.clamp(io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.totalMultiplier, 0.3D, 1D);
|
|
long byteAllowed = maxBookPageSize;
|
|
+ // Purpur start
|
|
+ int slot = packet.slot();
|
|
+ ItemStack itemstack = Inventory.isHotbarSlot(slot) || slot == Inventory.SLOT_OFFHAND ? this.player.getInventory().getItem(slot) : ItemStack.EMPTY;
|
|
+ // Purpur end
|
|
for (final String page : pageList) {
|
|
final int byteLength = page.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;
|
|
byteTotal += byteLength;
|
|
@@ -1204,7 +1231,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
}
|
|
|
|
if (byteTotal > byteAllowed) {
|
|
- ServerGamePacketListenerImpl.LOGGER.warn("{} tried to send a book too large. Book size: {} - Allowed: {} - Pages: {}", this.player.getScoreboardName(), byteTotal, byteAllowed, pageList.size());
|
|
+ ServerGamePacketListenerImpl.LOGGER.warn("{} tried to send too large of a book. Book size: {} - Allowed: {} - Pages: {}", this.player.getScoreboardName(), byteTotal, byteAllowed, pageList.size());
|
|
+ org.purpurmc.purpur.event.player.PlayerBookTooLargeEvent event = new org.purpurmc.purpur.event.player.PlayerBookTooLargeEvent(player.getBukkitEntity(), itemstack.asBukkitCopy()); if (event.shouldKickPlayer()) // Purpur
|
|
this.disconnectAsync(Component.literal("Book too large!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause // Paper - add proper async disconnect
|
|
return;
|
|
}
|
|
@@ -1226,10 +1254,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
Objects.requireNonNull(list);
|
|
optional.ifPresent(list::add);
|
|
list.addAll(packet.pages());
|
|
+ // Purpur start
|
|
+ boolean hasEditPerm = getCraftPlayer().hasPermission("purpur.book.color.edit");
|
|
+ boolean hasSignPerm = hasEditPerm || getCraftPlayer().hasPermission("purpur.book.color.sign");
|
|
+ // Purpur end
|
|
Consumer<List<FilteredText>> consumer = optional.isPresent() ? (list1) -> {
|
|
- this.signBook((FilteredText) list1.get(0), list1.subList(1, list1.size()), i);
|
|
+ this.signBook((FilteredText) list1.get(0), list1.subList(1, list1.size()), i, hasSignPerm); // Purpur
|
|
} : (list1) -> {
|
|
- this.updateBookContents(list1, i);
|
|
+ this.updateBookContents(list1, i, hasEditPerm); // Purpur
|
|
};
|
|
|
|
this.filterTextPacket((List) list).thenAcceptAsync(consumer, this.server);
|
|
@@ -1237,13 +1269,18 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
}
|
|
|
|
private void updateBookContents(List<FilteredText> pages, int slotId) {
|
|
+ // Purpur start
|
|
+ updateBookContents(pages, slotId, false);
|
|
+ }
|
|
+ private void updateBookContents(List<FilteredText> pages, int slotId, boolean hasPerm) {
|
|
+ // Purpur end
|
|
// CraftBukkit start
|
|
ItemStack handItem = this.player.getInventory().getItem(slotId);
|
|
ItemStack itemstack = handItem.copy();
|
|
// CraftBukkit end
|
|
|
|
if (itemstack.has(DataComponents.WRITABLE_BOOK_CONTENT)) {
|
|
- List<Filterable<String>> list1 = pages.stream().map(this::filterableFromOutgoing).toList();
|
|
+ List<Filterable<String>> list1 = pages.stream().map(filteredText -> filterableFromOutgoing(filteredText).map(s -> color(s, hasPerm))).toList(); // Purpur
|
|
|
|
itemstack.set(DataComponents.WRITABLE_BOOK_CONTENT, new WritableBookContent(list1));
|
|
this.player.getInventory().setItem(slotId, CraftEventFactory.handleEditBookEvent(this.player, slotId, handItem, itemstack)); // CraftBukkit // Paper - Don't ignore result (see other callsite for handleEditBookEvent)
|
|
@@ -1251,6 +1288,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
}
|
|
|
|
private void signBook(FilteredText title, List<FilteredText> pages, int slotId) {
|
|
+ // Purpur start
|
|
+ signBook(title, pages, slotId, false);
|
|
+ }
|
|
+ private void signBook(FilteredText title, List<FilteredText> pages, int slotId, boolean hasPerm) {
|
|
+ // Purpur end
|
|
ItemStack itemstack = this.player.getInventory().getItem(slotId);
|
|
|
|
if (itemstack.has(DataComponents.WRITABLE_BOOK_CONTENT)) {
|
|
@@ -1258,10 +1300,10 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
|
|
itemstack1.remove(DataComponents.WRITABLE_BOOK_CONTENT);
|
|
List<Filterable<Component>> list1 = (List<Filterable<Component>>) (List) pages.stream().map((filteredtext1) -> { // CraftBukkit - decompile error
|
|
- return this.filterableFromOutgoing(filteredtext1).map(Component::literal);
|
|
+ return this.filterableFromOutgoing(filteredtext1).map(s -> hexColor(s, hasPerm)); // Purpur
|
|
}).toList();
|
|
|
|
- itemstack1.set(DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(this.filterableFromOutgoing(title), this.player.getName().getString(), 0, list1, true));
|
|
+ itemstack1.set(DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(this.filterableFromOutgoing(title).map(s -> color(s, hasPerm)), this.player.getName().getString(), 0, list1, true)); // Purpur
|
|
CraftEventFactory.handleEditBookEvent(this.player, slotId, itemstack, itemstack1); // CraftBukkit
|
|
this.player.getInventory().setItem(slotId, itemstack); // CraftBukkit - event factory updates the hand book
|
|
}
|
|
@@ -1271,6 +1313,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
return this.player.isTextFilteringEnabled() ? Filterable.passThrough(message.filteredOrEmpty()) : Filterable.from(message);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ private Component hexColor(String str, boolean hasPerm) {
|
|
+ return hasPerm ? PaperAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize(str)) : Component.literal(str);
|
|
+ }
|
|
+
|
|
+ private String color(String str, boolean hasPerm) {
|
|
+ return hasPerm ? org.bukkit.ChatColor.color(str, false) : str;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public void handleEntityTagQuery(ServerboundEntityTagQueryPacket packet) {
|
|
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
|
@@ -1320,7 +1372,15 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
@Override
|
|
public void handleMovePlayer(ServerboundMovePlayerPacket packet) {
|
|
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
|
- if (ServerGamePacketListenerImpl.containsInvalidValues(packet.getX(0.0D), packet.getY(0.0D), packet.getZ(0.0D), packet.getYRot(0.0F), packet.getXRot(0.0F))) {
|
|
+ // Purpur start
|
|
+ boolean invalidX = Double.isNaN(packet.getX(0.0D));
|
|
+ boolean invalidY = Double.isNaN(packet.getY(0.0D));
|
|
+ boolean invalidZ = Double.isNaN(packet.getZ(0.0D));
|
|
+ boolean invalidYaw = !Floats.isFinite(packet.getYRot(0.0F));
|
|
+ boolean invalidPitch = !Floats.isFinite(packet.getXRot(0.0F));
|
|
+ if (invalidX || invalidY || invalidZ || invalidYaw || invalidPitch) {
|
|
+ ServerGamePacketListenerImpl.LOGGER.warn(String.format("Disconnected on move player packet. Invalid data: x=%b, y=%b, z=%b, yaw=%b, pitch=%b", invalidX, invalidY, invalidZ, invalidYaw, invalidPitch)); // Purpur
|
|
+ // Purpur end
|
|
this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause
|
|
} else {
|
|
ServerLevel worldserver = this.player.serverLevel();
|
|
@@ -1500,7 +1560,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
movedWrongly = true;
|
|
if (event.getLogWarning())
|
|
// Paper end
|
|
- ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString());
|
|
+ ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!, ({})", this.player.getName().getString(), d11); // Purpur
|
|
} // Paper
|
|
}
|
|
|
|
@@ -1568,6 +1628,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
this.lastYaw = to.getYaw();
|
|
this.lastPitch = to.getPitch();
|
|
|
|
+ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetLastActionTime(); // Purpur
|
|
+
|
|
Location oldTo = to.clone();
|
|
PlayerMoveEvent event = new PlayerMoveEvent(player, from, to);
|
|
this.cserver.getPluginManager().callEvent(event);
|
|
@@ -1613,6 +1675,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
this.player.tryResetCurrentImpulseContext();
|
|
}
|
|
|
|
+ // Purpur Start
|
|
+ if (this.player.level().purpurConfig.dontRunWithScissors && this.player.isSprinting() && !(this.player.level().purpurConfig.ignoreScissorsInWater && this.player.isInWater()) && !(this.player.level().purpurConfig.ignoreScissorsInLava && this.player.isInLava()) && (isScissor(this.player.getItemInHand(InteractionHand.MAIN_HAND)) || isScissor(this.player.getItemInHand(InteractionHand.OFF_HAND))) && (int) (Math.random() * 10) == 0) {
|
|
+ this.player.hurt(this.player.damageSources().scissors(), (float) this.player.level().purpurConfig.scissorsRunningDamage);
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.dontRunWithScissors.isBlank()) this.player.sendActionBarMessage(org.purpurmc.purpur.PurpurConfig.dontRunWithScissors);
|
|
+ }
|
|
+ // Purpur End
|
|
+
|
|
this.player.checkMovementStatistics(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5);
|
|
this.lastGoodX = this.player.getX();
|
|
this.lastGoodY = this.player.getY();
|
|
@@ -1652,6 +1721,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
}
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public boolean isScissor(ItemStack stack) {
|
|
+ if (!stack.is(Items.SHEARS)) return false;
|
|
+ net.minecraft.world.item.component.CustomModelData customModelData = stack.get(net.minecraft.core.component.DataComponents.CUSTOM_MODEL_DATA);
|
|
+ return customModelData == null || customModelData.value() == 0;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
// Paper start - optimise out extra getCubes
|
|
private boolean hasNewCollision(final ServerLevel world, final Entity entity, final AABB oldBox, final AABB newBox) {
|
|
final List<AABB> collisionsBB = new java.util.ArrayList<>();
|
|
@@ -2025,6 +2102,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
|
|
boolean cancelled;
|
|
if (movingobjectposition == null || movingobjectposition.getType() != HitResult.Type.BLOCK) {
|
|
+ if (this.player.gameMode.shiftClickMended(itemstack)) return; // Purpur
|
|
org.bukkit.event.player.PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.RIGHT_CLICK_AIR, itemstack, enumhand);
|
|
cancelled = event.useItemInHand() == Event.Result.DENY;
|
|
} else {
|
|
@@ -2808,6 +2886,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
AABB axisalignedbb = entity.getBoundingBox();
|
|
|
|
if (this.player.canInteractWithEntity(axisalignedbb, io.papermc.paper.configuration.GlobalConfiguration.get().misc.clientInteractionLeniencyDistance.or(3.0D))) { // Paper - configurable lenience value for interact range
|
|
+ if (entity instanceof Mob mob) mob.ticksSinceLastInteraction = 0; // Purpur
|
|
packet.dispatch(new ServerboundInteractPacket.Handler() {
|
|
private void performInteraction(InteractionHand enumhand, ServerGamePacketListenerImpl.EntityInteraction playerconnection_a, PlayerInteractEntityEvent event) { // CraftBukkit
|
|
ItemStack itemstack = ServerGamePacketListenerImpl.this.player.getItemInHand(enumhand);
|
|
@@ -2821,6 +2900,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
|
|
ServerGamePacketListenerImpl.this.cserver.getPluginManager().callEvent(event);
|
|
|
|
+ player.processClick(enumhand); // Purpur
|
|
+
|
|
// Entity in bucket - SPIGOT-4048 and SPIGOT-6859a
|
|
if ((entity instanceof Bucketable && entity instanceof LivingEntity && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) {
|
|
entity.resendPossiblyDesyncedEntityData(ServerGamePacketListenerImpl.this.player); // Paper - The entire mob gets deleted, so resend it
|
|
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
|
index 033755682c61c889723c3669b5cff4de147f637e..16069b9cbf6c7679c28a2e9a54e77d23cd10e541 100644
|
|
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
|
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
|
@@ -322,7 +322,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
|
ServerLoginPacketListenerImpl.LOGGER.warn("Failed to verify username but will let them in anyway!");
|
|
ServerLoginPacketListenerImpl.this.startClientVerification(ServerLoginPacketListenerImpl.this.createOfflineProfile(s1)); // Spigot
|
|
} else {
|
|
- ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.unverified_username"));
|
|
+ ServerLoginPacketListenerImpl.this.disconnect(org.purpurmc.purpur.PurpurConfig.unverifiedUsername.equals("default") ? Component.translatable("multiplayer.disconnect.unverified_username") : io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.unverifiedUsername))); // Purpur
|
|
ServerLoginPacketListenerImpl.LOGGER.error("Username '{}' tried to join with an invalid session", s1);
|
|
}
|
|
} catch (AuthenticationUnavailableException authenticationunavailableexception) {
|
|
diff --git a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
|
|
index 532f09089b8d6798999cf3f83e852df7479e450e..43c63d203859eaa0999937e2f9254c22510139aa 100644
|
|
--- a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
|
|
+++ b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
|
|
@@ -154,6 +154,7 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
|
|
this.connection.send(new ClientboundStatusResponsePacket(ping));
|
|
// CraftBukkit end
|
|
*/
|
|
+ if (MinecraftServer.getServer().getStatus().version().isEmpty()) return; // Purpur - do not respond to pings before we know the protocol version
|
|
com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.processRequest(MinecraftServer.getServer(), this.connection);
|
|
// Paper end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/packs/resources/ResourceManagerReloadListener.java b/src/main/java/net/minecraft/server/packs/resources/ResourceManagerReloadListener.java
|
|
index d2d82e4f22bfeac8881b6815e4bef56c254fded9..abc92e09b7bb636612f04ace8232947c8d454e68 100644
|
|
--- a/src/main/java/net/minecraft/server/packs/resources/ResourceManagerReloadListener.java
|
|
+++ b/src/main/java/net/minecraft/server/packs/resources/ResourceManagerReloadListener.java
|
|
@@ -12,10 +12,10 @@ public interface ResourceManagerReloadListener extends PreparableReloadListener
|
|
PreparableReloadListener.PreparationBarrier synchronizer, ResourceManager manager, Executor prepareExecutor, Executor applyExecutor
|
|
) {
|
|
return synchronizer.wait(Unit.INSTANCE).thenRunAsync(() -> {
|
|
- ProfilerFiller profilerFiller = Profiler.get();
|
|
- profilerFiller.push("listener");
|
|
+ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur
|
|
+ //profilerFiller.push("listener"); // Purpur
|
|
this.onResourceManagerReload(manager);
|
|
- profilerFiller.pop();
|
|
+ //profilerFiller.pop(); // Purpur
|
|
}, applyExecutor);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
|
index 1fcd9cd9344b0d2c4752042b07142db7d727dce8..7d57f9b7fc4837f0f44f5c1cb76a5751a15b9254 100644
|
|
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
|
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
|
@@ -419,6 +419,7 @@ public abstract class PlayerList {
|
|
scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
|
|
}
|
|
// Paper end - Configurable player collision
|
|
+ org.purpurmc.purpur.task.BossBarTask.addToAll(player); // Purpur
|
|
PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ());
|
|
// Paper start - Send empty chunk, so players aren't stuck in the world loading screen with our chunk system not sending chunks when dead
|
|
if (player.isDeadOrDying()) {
|
|
@@ -540,6 +541,7 @@ public abstract class PlayerList {
|
|
}
|
|
public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer, net.kyori.adventure.text.Component leaveMessage) {
|
|
// Paper end - Fix kick event leave message not being sent
|
|
+ org.purpurmc.purpur.task.BossBarTask.removeFromAll(entityplayer.getBukkitEntity()); // Purpur
|
|
ServerLevel worldserver = entityplayer.serverLevel();
|
|
|
|
entityplayer.awardStat(Stats.LEAVE_GAME);
|
|
@@ -709,7 +711,7 @@ public abstract class PlayerList {
|
|
event.disallow(PlayerLoginEvent.Result.KICK_BANNED, io.papermc.paper.adventure.PaperAdventure.asAdventure(ichatmutablecomponent)); // Paper - Adventure
|
|
} else {
|
|
// return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile) ? IChatBaseComponent.translatable("multiplayer.disconnect.server_full") : null;
|
|
- if (this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile)) {
|
|
+ if (this.players.size() >= this.maxPlayers && !(player.hasPermission("purpur.joinfullserver") || this.canBypassPlayerLimit(gameprofile))) { // Purpur
|
|
event.disallow(PlayerLoginEvent.Result.KICK_FULL, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.serverFullMessage)); // Spigot // Paper - Adventure
|
|
}
|
|
}
|
|
@@ -991,6 +993,20 @@ public abstract class PlayerList {
|
|
}
|
|
// CraftBukkit end
|
|
|
|
+ // Purpur Start
|
|
+ public void broadcastMiniMessage(@Nullable String message, boolean overlay) {
|
|
+ if (message != null && !message.isEmpty()) {
|
|
+ this.broadcastMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message), overlay);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void broadcastMessage(@Nullable net.kyori.adventure.text.Component message, boolean overlay) {
|
|
+ if (message != null) {
|
|
+ this.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message), overlay);
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public void broadcastAll(Packet<?> packet, ResourceKey<Level> dimension) {
|
|
Iterator iterator = this.players.iterator();
|
|
|
|
@@ -1094,6 +1110,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));
|
|
}
|
|
@@ -1102,6 +1119,27 @@ public abstract class PlayerList {
|
|
player.getBukkitEntity().recalculatePermissions(); // CraftBukkit
|
|
this.server.getCommands().sendCommands(player);
|
|
} // Paper - Add sendOpLevel API
|
|
+
|
|
+ // Purpur start
|
|
+ if (org.purpurmc.purpur.PurpurConfig.enderChestSixRows && org.purpurmc.purpur.PurpurConfig.enderChestPermissionRows) {
|
|
+ org.bukkit.craftbukkit.entity.CraftHumanEntity bukkit = player.getBukkitEntity();
|
|
+ if (bukkit.hasPermission("purpur.enderchest.rows.six")) {
|
|
+ player.sixRowEnderchestSlotCount = 54;
|
|
+ } else if (bukkit.hasPermission("purpur.enderchest.rows.five")) {
|
|
+ player.sixRowEnderchestSlotCount = 45;
|
|
+ } else if (bukkit.hasPermission("purpur.enderchest.rows.four")) {
|
|
+ player.sixRowEnderchestSlotCount = 36;
|
|
+ } else if (bukkit.hasPermission("purpur.enderchest.rows.three")) {
|
|
+ player.sixRowEnderchestSlotCount = 27;
|
|
+ } else if (bukkit.hasPermission("purpur.enderchest.rows.two")) {
|
|
+ player.sixRowEnderchestSlotCount = 18;
|
|
+ } else if (bukkit.hasPermission("purpur.enderchest.rows.one")) {
|
|
+ player.sixRowEnderchestSlotCount = 9;
|
|
+ }
|
|
+ } else {
|
|
+ player.sixRowEnderchestSlotCount = -1;
|
|
+ }
|
|
+ //Purpur end
|
|
}
|
|
|
|
public boolean isWhiteListed(GameProfile profile) {
|
|
diff --git a/src/main/java/net/minecraft/server/players/SleepStatus.java b/src/main/java/net/minecraft/server/players/SleepStatus.java
|
|
index 823efad652d8ff9e96b99375b102fef6f017716e..caa8a69bde0c212c36dd990a67836ac2f95548c0 100644
|
|
--- a/src/main/java/net/minecraft/server/players/SleepStatus.java
|
|
+++ b/src/main/java/net/minecraft/server/players/SleepStatus.java
|
|
@@ -19,7 +19,7 @@ public class SleepStatus {
|
|
|
|
public boolean areEnoughDeepSleeping(int percentage, List<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/stats/ServerRecipeBook.java b/src/main/java/net/minecraft/stats/ServerRecipeBook.java
|
|
index 5c7484ce2850a2eb698a2183b81134b89b0bbcc7..fef09e71f73f6f24a01289ef05c20a5ffc5fadb1 100644
|
|
--- a/src/main/java/net/minecraft/stats/ServerRecipeBook.java
|
|
+++ b/src/main/java/net/minecraft/stats/ServerRecipeBook.java
|
|
@@ -159,6 +159,7 @@ public class ServerRecipeBook extends RecipeBook {
|
|
ResourceKey<Recipe<?>> resourcekey = ResourceKey.create(Registries.RECIPE, ResourceLocation.parse(s));
|
|
|
|
if (!validPredicate.test(resourcekey)) {
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressUnrecognizedRecipeErrors) // Purpur
|
|
ServerRecipeBook.LOGGER.error("Tried to load unrecognized recipe: {} removed now.", resourcekey);
|
|
} else {
|
|
handler.accept(resourcekey);
|
|
diff --git a/src/main/java/net/minecraft/util/StringUtil.java b/src/main/java/net/minecraft/util/StringUtil.java
|
|
index 6c33002dc8bbb3759c3156302ab7d1f26ce5e8ee..c89fc375aff548a2b03eaf4da3b6a075012df012 100644
|
|
--- a/src/main/java/net/minecraft/util/StringUtil.java
|
|
+++ b/src/main/java/net/minecraft/util/StringUtil.java
|
|
@@ -69,6 +69,7 @@ public class StringUtil {
|
|
|
|
// Paper start - Username validation
|
|
public static boolean isReasonablePlayerName(final String name) {
|
|
+ if (true) return org.purpurmc.purpur.PurpurConfig.usernameValidCharactersPattern.matcher(name).matches(); // Purpur
|
|
if (name.isEmpty() || name.length() > 16) {
|
|
return false;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/util/profiling/ActiveProfiler.java b/src/main/java/net/minecraft/util/profiling/ActiveProfiler.java
|
|
index bce2dac613d29083dd5fbb68739304cc5a6d4d27..600a7036b503f60cc9c95f189f73c2dbf020e2e1 100644
|
|
--- a/src/main/java/net/minecraft/util/profiling/ActiveProfiler.java
|
|
+++ b/src/main/java/net/minecraft/util/profiling/ActiveProfiler.java
|
|
@@ -55,7 +55,7 @@ public class ActiveProfiler implements ProfileCollector {
|
|
this.started = true;
|
|
this.path = "";
|
|
this.paths.clear();
|
|
- this.push("root");
|
|
+ //this.push("root"); // Purpur
|
|
}
|
|
}
|
|
|
|
@@ -64,7 +64,7 @@ public class ActiveProfiler implements ProfileCollector {
|
|
if (!this.started) {
|
|
LOGGER.error("Profiler tick already ended - missing startTick()?");
|
|
} else {
|
|
- this.pop();
|
|
+ //this.pop(); // Purpur
|
|
this.started = false;
|
|
if (!this.path.isEmpty()) {
|
|
LOGGER.error(
|
|
@@ -93,7 +93,7 @@ public class ActiveProfiler implements ProfileCollector {
|
|
|
|
@Override
|
|
public void push(Supplier<String> locationGetter) {
|
|
- this.push(locationGetter.get());
|
|
+ //this.push(locationGetter.get()); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -132,14 +132,14 @@ public class ActiveProfiler implements ProfileCollector {
|
|
|
|
@Override
|
|
public void popPush(String location) {
|
|
- this.pop();
|
|
- this.push(location);
|
|
+ //this.pop(); // Purpur
|
|
+ //this.push(location); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void popPush(Supplier<String> locationGetter) {
|
|
- this.pop();
|
|
- this.push(locationGetter);
|
|
+ //this.pop(); // Purpur
|
|
+ //this.push(locationGetter); // Purpur
|
|
}
|
|
|
|
private ActiveProfiler.PathEntry getCurrentEntry() {
|
|
diff --git a/src/main/java/net/minecraft/util/profiling/ProfilerFiller.java b/src/main/java/net/minecraft/util/profiling/ProfilerFiller.java
|
|
index bc5c8879befe849ce81becf5e3fba6757b01cb70..ce81d6bd87f688a24003f2fbf6d5010ad6273917 100644
|
|
--- a/src/main/java/net/minecraft/util/profiling/ProfilerFiller.java
|
|
+++ b/src/main/java/net/minecraft/util/profiling/ProfilerFiller.java
|
|
@@ -6,51 +6,68 @@ import net.minecraft.util.profiling.metrics.MetricCategory;
|
|
public interface ProfilerFiller {
|
|
String ROOT = "root";
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
void startTick();
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
void endTick();
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
void push(String location);
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
void push(Supplier<String> locationGetter);
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
void pop();
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
void popPush(String location);
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
void popPush(Supplier<String> locationGetter);
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
default void addZoneText(String label) {
|
|
}
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
default void addZoneValue(long value) {
|
|
}
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
default void setZoneColor(int color) {
|
|
}
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
default Zone zone(String name) {
|
|
this.push(name);
|
|
return new Zone(this);
|
|
}
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
default Zone zone(Supplier<String> nameSupplier) {
|
|
this.push(nameSupplier);
|
|
return new Zone(this);
|
|
}
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
void markForCharting(MetricCategory type);
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
default void incrementCounter(String marker) {
|
|
- this.incrementCounter(marker, 1);
|
|
+ //this.incrementCounter(marker, 1); // Purpur
|
|
}
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
void incrementCounter(String marker, int num);
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
default void incrementCounter(Supplier<String> markerGetter) {
|
|
- this.incrementCounter(markerGetter, 1);
|
|
+ //this.incrementCounter(markerGetter, 1); // Purpur
|
|
}
|
|
|
|
+ @io.papermc.paper.annotation.DoNotUse // Purpur
|
|
void incrementCounter(Supplier<String> markerGetter, int num);
|
|
|
|
static ProfilerFiller combine(ProfilerFiller first, ProfilerFiller second) {
|
|
@@ -72,80 +89,80 @@ public interface ProfilerFiller {
|
|
|
|
@Override
|
|
public void startTick() {
|
|
- this.first.startTick();
|
|
- this.second.startTick();
|
|
+ //this.first.startTick(); // Purpur
|
|
+ //this.second.startTick(); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void endTick() {
|
|
- this.first.endTick();
|
|
- this.second.endTick();
|
|
+ //this.first.endTick(); // Purpur
|
|
+ //this.second.endTick(); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void push(String location) {
|
|
- this.first.push(location);
|
|
- this.second.push(location);
|
|
+ //this.first.push(location); // Purpur
|
|
+ //this.second.push(location); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void push(Supplier<String> locationGetter) {
|
|
- this.first.push(locationGetter);
|
|
- this.second.push(locationGetter);
|
|
+ //this.first.push(locationGetter); // Purpur
|
|
+ //this.second.push(locationGetter); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void markForCharting(MetricCategory type) {
|
|
- this.first.markForCharting(type);
|
|
- this.second.markForCharting(type);
|
|
+ //this.first.markForCharting(type); // Purpur
|
|
+ //this.second.markForCharting(type); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void pop() {
|
|
- this.first.pop();
|
|
- this.second.pop();
|
|
+ //this.first.pop(); // Purpur
|
|
+ //this.second.pop(); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void popPush(String location) {
|
|
- this.first.popPush(location);
|
|
- this.second.popPush(location);
|
|
+ //this.first.popPush(location); // Purpur
|
|
+ //this.second.popPush(location); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void popPush(Supplier<String> locationGetter) {
|
|
- this.first.popPush(locationGetter);
|
|
- this.second.popPush(locationGetter);
|
|
+ //this.first.popPush(locationGetter); // Purpur
|
|
+ //this.second.popPush(locationGetter); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void incrementCounter(String marker, int num) {
|
|
- this.first.incrementCounter(marker, num);
|
|
- this.second.incrementCounter(marker, num);
|
|
+ //this.first.incrementCounter(marker, num); // Purpur
|
|
+ //this.second.incrementCounter(marker, num); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void incrementCounter(Supplier<String> markerGetter, int num) {
|
|
- this.first.incrementCounter(markerGetter, num);
|
|
- this.second.incrementCounter(markerGetter, num);
|
|
+ //this.first.incrementCounter(markerGetter, num); // Purpur
|
|
+ //this.second.incrementCounter(markerGetter, num); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void addZoneText(String label) {
|
|
- this.first.addZoneText(label);
|
|
- this.second.addZoneText(label);
|
|
+ //this.first.addZoneText(label); // Purpur
|
|
+ //this.second.addZoneText(label); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void addZoneValue(long value) {
|
|
- this.first.addZoneValue(value);
|
|
- this.second.addZoneValue(value);
|
|
+ //this.first.addZoneValue(value); // Purpur
|
|
+ //this.second.addZoneValue(value); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void setZoneColor(int color) {
|
|
- this.first.setZoneColor(color);
|
|
- this.second.setZoneColor(color);
|
|
+ //this.first.setZoneColor(color); // Purpur
|
|
+ //this.second.setZoneColor(color); // Purpur
|
|
}
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/damagesource/CombatRules.java b/src/main/java/net/minecraft/world/damagesource/CombatRules.java
|
|
index 064c1e33f3feee77837bb57887877ae1ca39548d..ffd009bca3fdbfd0b14df78072ef8d472a57cd65 100644
|
|
--- a/src/main/java/net/minecraft/world/damagesource/CombatRules.java
|
|
+++ b/src/main/java/net/minecraft/world/damagesource/CombatRules.java
|
|
@@ -15,7 +15,7 @@ public class CombatRules {
|
|
|
|
public static float getDamageAfterAbsorb(LivingEntity armorWearer, float damageAmount, DamageSource damageSource, float armor, float armorToughness) {
|
|
float f = 2.0F + armorToughness / 4.0F;
|
|
- float g = Mth.clamp(armor - damageAmount / f, armor * 0.2F, 20.0F);
|
|
+ float g = Mth.clamp(armor - damageAmount / f, armor * 0.2F, org.purpurmc.purpur.PurpurConfig.limitArmor ? 20F : Float.MAX_VALUE); // Purpur
|
|
float h = g / 25.0F;
|
|
ItemStack itemStack = damageSource.getWeaponItem();
|
|
float i;
|
|
@@ -30,7 +30,7 @@ public class CombatRules {
|
|
}
|
|
|
|
public static float getDamageAfterMagicAbsorb(float damageDealt, float protection) {
|
|
- float f = Mth.clamp(protection, 0.0F, 20.0F);
|
|
+ float f = Mth.clamp(protection, 0.0F, org.purpurmc.purpur.PurpurConfig.limitArmor ? 20F : Float.MAX_VALUE); // Purpur
|
|
return damageDealt * (1.0F - f / 25.0F);
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java
|
|
index 99a7e9eb75231c15bd8bb24fbb4e296bc9fdedff..4fb025a63628eb60509d90b680922a0220104bcb 100644
|
|
--- a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java
|
|
+++ b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java
|
|
@@ -54,7 +54,7 @@ public class CombatTracker {
|
|
|
|
private Component getMessageForAssistedFall(Entity attacker, Component attackerDisplayName, String itemDeathTranslationKey, String deathTranslationKey) {
|
|
ItemStack itemStack = attacker instanceof LivingEntity livingEntity ? livingEntity.getMainHandItem() : ItemStack.EMPTY;
|
|
- return !itemStack.isEmpty() && itemStack.has(DataComponents.CUSTOM_NAME)
|
|
+ return !itemStack.isEmpty() && (org.purpurmc.purpur.PurpurConfig.playerDeathsAlwaysShowItem || itemStack.has(DataComponents.CUSTOM_NAME)) // Purpur
|
|
? Component.translatable(itemDeathTranslationKey, this.mob.getDisplayName(), attackerDisplayName, itemStack.getDisplayName())
|
|
: Component.translatable(deathTranslationKey, this.mob.getDisplayName(), attackerDisplayName);
|
|
}
|
|
@@ -98,6 +98,13 @@ public class CombatTracker {
|
|
Component component = ComponentUtils.wrapInSquareBrackets(Component.translatable(string + ".link")).withStyle(INTENTIONAL_GAME_DESIGN_STYLE);
|
|
return Component.translatable(string + ".message", this.mob.getDisplayName(), component);
|
|
} else {
|
|
+ // Purpur start
|
|
+ if (damageSource.isScissors()) {
|
|
+ return damageSource.getLocalizedDeathMessage(org.purpurmc.purpur.PurpurConfig.deathMsgRunWithScissors, this.mob);
|
|
+ } else if (damageSource.isStonecutter()) {
|
|
+ return damageSource.getLocalizedDeathMessage(org.purpurmc.purpur.PurpurConfig.deathMsgStonecutter, this.mob);
|
|
+ }
|
|
+ // Purpur end
|
|
return damageSource.getLocalizedDeathMessage(this.mob);
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java
|
|
index bb1a60180e58c1333e7bb33e8acf1b0225eda8a8..4a96d914f8aa6f0c5f13fc85369a311f25835ac2 100644
|
|
--- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java
|
|
+++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java
|
|
@@ -29,6 +29,8 @@ public class DamageSource {
|
|
private boolean sweep = false;
|
|
private boolean melting = false;
|
|
private boolean poison = false;
|
|
+ private boolean scissors = false; // Purpur
|
|
+ private boolean stonecutter = false; // Purpur
|
|
@Nullable
|
|
private Entity customEventDamager = null; // This field is a helper for when causing entity damage is not set by vanilla // Paper - fix DamageSource API
|
|
|
|
@@ -59,6 +61,26 @@ public class DamageSource {
|
|
return this.poison;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public DamageSource scissors() {
|
|
+ this.scissors = true;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ public boolean isScissors() {
|
|
+ return this.scissors;
|
|
+ }
|
|
+
|
|
+ public DamageSource stonecutter() {
|
|
+ this.stonecutter = true;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ public boolean isStonecutter() {
|
|
+ return this.stonecutter;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
// Paper start - fix DamageSource API
|
|
@Nullable
|
|
public Entity getCustomEventDamager() {
|
|
@@ -117,6 +139,8 @@ public class DamageSource {
|
|
damageSource.sweep = this.isSweep();
|
|
damageSource.poison = this.isPoison();
|
|
damageSource.melting = this.isMelting();
|
|
+ damageSource.scissors = this.isScissors(); // Purpur
|
|
+ damageSource.stonecutter = this.isStonecutter(); // Purpur
|
|
return damageSource;
|
|
}
|
|
// CraftBukkit end
|
|
@@ -194,10 +218,19 @@ public class DamageSource {
|
|
|
|
ItemStack itemstack1 = itemstack;
|
|
|
|
- return !itemstack1.isEmpty() && itemstack1.has(DataComponents.CUSTOM_NAME) ? Component.translatable(s + ".item", killed.getDisplayName(), ichatbasecomponent, itemstack1.getDisplayName()) : Component.translatable(s, killed.getDisplayName(), ichatbasecomponent);
|
|
+ return !itemstack1.isEmpty() && (org.purpurmc.purpur.PurpurConfig.playerDeathsAlwaysShowItem || itemstack1.has(DataComponents.CUSTOM_NAME)) ? Component.translatable(s + ".item", killed.getDisplayName(), ichatbasecomponent, itemstack1.getDisplayName()) : Component.translatable(s, killed.getDisplayName(), ichatbasecomponent);
|
|
}
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public Component getLocalizedDeathMessage(String str, LivingEntity entity) {
|
|
+ net.kyori.adventure.text.Component name = io.papermc.paper.adventure.PaperAdventure.asAdventure(entity.getDisplayName());
|
|
+ net.kyori.adventure.text.minimessage.tag.resolver.TagResolver template = net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("player", name);
|
|
+ net.kyori.adventure.text.Component component = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(str, template);
|
|
+ return io.papermc.paper.adventure.PaperAdventure.asVanilla(component);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public String getMsgId() {
|
|
return this.type().msgId();
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSources.java b/src/main/java/net/minecraft/world/damagesource/DamageSources.java
|
|
index be87cb3cfa15a7d889118cdc4b87232e30749023..d343fd5c9f31073f1b3a0f91b8ea61a67077cc12 100644
|
|
--- a/src/main/java/net/minecraft/world/damagesource/DamageSources.java
|
|
+++ b/src/main/java/net/minecraft/world/damagesource/DamageSources.java
|
|
@@ -46,11 +46,15 @@ public class DamageSources {
|
|
// CraftBukkit start
|
|
private final DamageSource melting;
|
|
private final DamageSource poison;
|
|
+ private final DamageSource scissors; // Purpur
|
|
+ private final DamageSource stonecutter; // Purpur
|
|
|
|
public DamageSources(RegistryAccess registryManager) {
|
|
this.damageTypes = registryManager.lookupOrThrow(Registries.DAMAGE_TYPE);
|
|
this.melting = this.source(DamageTypes.ON_FIRE).melting();
|
|
this.poison = this.source(DamageTypes.MAGIC).poison();
|
|
+ this.scissors = this.source(DamageTypes.MAGIC).scissors(); // Purpur
|
|
+ this.stonecutter = this.source(DamageTypes.MAGIC).stonecutter(); // Purpur
|
|
// CraftBukkit end
|
|
this.inFire = this.source(DamageTypes.IN_FIRE);
|
|
this.campfire = this.source(DamageTypes.CAMPFIRE);
|
|
@@ -101,6 +105,15 @@ public class DamageSources {
|
|
}
|
|
// CraftBukkit end
|
|
|
|
+ // Purpur start
|
|
+ public DamageSource scissors() {
|
|
+ return this.scissors;
|
|
+ }
|
|
+ public DamageSource stonecutter() {
|
|
+ return this.stonecutter;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public DamageSource inFire() {
|
|
return this.inFire;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/effect/HungerMobEffect.java b/src/main/java/net/minecraft/world/effect/HungerMobEffect.java
|
|
index 11d1ee8fae7670f02cb3f5d57f4774dbde77f48c..88cf1353892a7ead4e0f16822216b151726ac0e4 100644
|
|
--- a/src/main/java/net/minecraft/world/effect/HungerMobEffect.java
|
|
+++ b/src/main/java/net/minecraft/world/effect/HungerMobEffect.java
|
|
@@ -13,7 +13,7 @@ class HungerMobEffect extends MobEffect {
|
|
@Override
|
|
public boolean applyEffectTick(ServerLevel world, LivingEntity entity, int amplifier) {
|
|
if (entity instanceof Player entityhuman) {
|
|
- entityhuman.causeFoodExhaustion(0.005F * (float) (amplifier + 1), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.HUNGER_EFFECT); // CraftBukkit - EntityExhaustionEvent
|
|
+ entityhuman.causeFoodExhaustion(entity.level().purpurConfig.humanHungerExhaustionAmount * (float) (amplifier + 1), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.HUNGER_EFFECT); // CraftBukkit - EntityExhaustionEvent // Purpur
|
|
}
|
|
|
|
return true;
|
|
diff --git a/src/main/java/net/minecraft/world/effect/PoisonMobEffect.java b/src/main/java/net/minecraft/world/effect/PoisonMobEffect.java
|
|
index 83c6d17f75c3f0b531bdfd5b5f9bc2a5b3eb7a2c..df43c007e7b9fee58b2cd0892b966ce88cb1f890 100644
|
|
--- a/src/main/java/net/minecraft/world/effect/PoisonMobEffect.java
|
|
+++ b/src/main/java/net/minecraft/world/effect/PoisonMobEffect.java
|
|
@@ -11,8 +11,8 @@ class PoisonMobEffect extends MobEffect {
|
|
|
|
@Override
|
|
public boolean applyEffectTick(ServerLevel world, LivingEntity entity, int amplifier) {
|
|
- if (entity.getHealth() > 1.0F) {
|
|
- entity.hurtServer(world, entity.damageSources().poison(), 1.0F); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON
|
|
+ if (entity.getHealth() > entity.level().purpurConfig.entityMinimalHealthPoison) { // Purpur
|
|
+ entity.hurtServer(world, entity.damageSources().poison(), entity.level().purpurConfig.entityPoisonDegenerationAmount); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON // Purpur
|
|
}
|
|
|
|
return true;
|
|
diff --git a/src/main/java/net/minecraft/world/effect/RegenerationMobEffect.java b/src/main/java/net/minecraft/world/effect/RegenerationMobEffect.java
|
|
index b43e573e91d1f1b407774bb2d60ee5f099f171e7..25aa932fc03eeebc5aabca6c5eae0cbfc8ad8396 100644
|
|
--- a/src/main/java/net/minecraft/world/effect/RegenerationMobEffect.java
|
|
+++ b/src/main/java/net/minecraft/world/effect/RegenerationMobEffect.java
|
|
@@ -12,7 +12,7 @@ class RegenerationMobEffect extends MobEffect {
|
|
@Override
|
|
public boolean applyEffectTick(ServerLevel world, LivingEntity entity, int amplifier) {
|
|
if (entity.getHealth() < entity.getMaxHealth()) {
|
|
- entity.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC_REGEN); // CraftBukkit
|
|
+ entity.heal(entity.level().purpurConfig.entityHealthRegenAmount, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC_REGEN); // CraftBukkit // Purpur
|
|
}
|
|
|
|
return true;
|
|
diff --git a/src/main/java/net/minecraft/world/effect/SaturationMobEffect.java b/src/main/java/net/minecraft/world/effect/SaturationMobEffect.java
|
|
index 98b74649a667fb9b10afef0ba5383a73022d8c71..0c7c0524e487ff32e16dd9939d92bc6441602747 100644
|
|
--- a/src/main/java/net/minecraft/world/effect/SaturationMobEffect.java
|
|
+++ b/src/main/java/net/minecraft/world/effect/SaturationMobEffect.java
|
|
@@ -21,7 +21,8 @@ class SaturationMobEffect extends InstantenousMobEffect {
|
|
int oldFoodLevel = entityhuman.getFoodData().foodLevel;
|
|
org.bukkit.event.entity.FoodLevelChangeEvent event = CraftEventFactory.callFoodLevelChangeEvent(entityhuman, amplifier + 1 + oldFoodLevel);
|
|
if (!event.isCancelled()) {
|
|
- entityhuman.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 1.0F);
|
|
+ if (entityhuman.level().purpurConfig.playerBurpWhenFull && event.getFoodLevel() == 20 && oldFoodLevel < 20) entityhuman.burpDelay = entityhuman.level().purpurConfig.playerBurpDelay; // Purpur
|
|
+ entityhuman.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, entity.level().purpurConfig.humanSaturationRegenAmount); // Purpur
|
|
}
|
|
|
|
((CraftPlayer) entityhuman.getBukkitEntity()).sendHealthUpdate();
|
|
diff --git a/src/main/java/net/minecraft/world/effect/WitherMobEffect.java b/src/main/java/net/minecraft/world/effect/WitherMobEffect.java
|
|
index 303cefba51e19ac43b1f6188ad64ef480715ebaf..98ec88751b3e71c2e7aad633096b7f41608c0b33 100644
|
|
--- a/src/main/java/net/minecraft/world/effect/WitherMobEffect.java
|
|
+++ b/src/main/java/net/minecraft/world/effect/WitherMobEffect.java
|
|
@@ -10,7 +10,7 @@ class WitherMobEffect extends MobEffect {
|
|
|
|
@Override
|
|
public boolean applyEffectTick(ServerLevel world, LivingEntity entity, int amplifier) {
|
|
- entity.hurtServer(world, entity.damageSources().wither(), 1.0F);
|
|
+ entity.hurtServer(world, entity.damageSources().wither(), entity.level().purpurConfig.entityWitherDegenerationAmount); // Purpur
|
|
return true;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
index 341c324d15996a74b113f8879d7da737a1be86a1..aac88848871d236bc440ee1a7e6fe09201cac2a1 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
@@ -176,7 +176,7 @@ import org.bukkit.plugin.PluginManager;
|
|
// CraftBukkit end
|
|
|
|
public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity { // Paper - rewrite chunk system // Paper - optimise entity tracker
|
|
-
|
|
+ public static javax.script.ScriptEngine scriptEngine = new javax.script.ScriptEngineManager().getEngineByName("rhino"); // Purpur
|
|
// CraftBukkit start
|
|
private static final int CURRENT_LEVEL = 2;
|
|
public boolean preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; keep initial motion on first setPositionRotation
|
|
@@ -343,6 +343,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
public double xOld;
|
|
public double yOld;
|
|
public double zOld;
|
|
+ public float maxUpStep; // Purpur
|
|
public boolean noPhysics;
|
|
private boolean wasOnFire;
|
|
public final RandomSource random;
|
|
@@ -383,7 +384,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
private final Set<String> tags;
|
|
private final double[] pistonDeltas;
|
|
private long pistonDeltasGameTime;
|
|
- private EntityDimensions dimensions;
|
|
+ protected EntityDimensions dimensions; // Purpur - private -> protected
|
|
private float eyeHeight;
|
|
public boolean isInPowderSnow;
|
|
public boolean wasInPowderSnow;
|
|
@@ -431,6 +432,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
private UUID originWorld;
|
|
public boolean freezeLocked = false; // Paper - Freeze Tick Lock API
|
|
public boolean fixedPose = false; // Paper - Expand Pose API
|
|
+ public @Nullable Boolean immuneToFire = null; // Purpur - Fire immune API
|
|
|
|
public void setOrigin(@javax.annotation.Nonnull Location location) {
|
|
this.origin = location.toVector();
|
|
@@ -610,6 +612,27 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
}
|
|
}
|
|
// Paper end - optimise entity tracker
|
|
+ // Purpur start
|
|
+ public boolean canSaveToDisk() {
|
|
+ return true;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ // Purpur start - copied from Mob - API for any mob to burn daylight
|
|
+ public boolean isSunBurnTick() {
|
|
+ if (this.level().isDay() && !this.level().isClientSide) {
|
|
+ float f = this.getLightLevelDependentMagicValue();
|
|
+ BlockPos blockposition = BlockPos.containing(this.getX(), this.getEyeY(), this.getZ());
|
|
+ boolean flag = this.isInWaterRainOrBubble() || this.isInPowderSnow || this.wasInPowderSnow;
|
|
+
|
|
+ if (f > 0.5F && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && !flag && this.level().canSeeSky(blockposition)) {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+ }
|
|
+ // Purpur end - copied from Mob - API for any mob to burn daylight
|
|
|
|
public Entity(EntityType<?> type, Level world) {
|
|
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
|
@@ -618,7 +641,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
this.bb = Entity.INITIAL_AABB;
|
|
this.stuckSpeedMultiplier = Vec3.ZERO;
|
|
this.nextStep = 1.0F;
|
|
- this.random = SHARED_RANDOM; // Paper - Share random for entities to make them more random
|
|
+ this.random = world == null || world.purpurConfig.entitySharedRandom ? SHARED_RANDOM : RandomSource.create(); // Paper - Share random for entities to make them more random // Purpur
|
|
this.remainingFireTicks = -this.getFireImmuneTicks();
|
|
this.fluidHeight = new Object2DoubleArrayMap(2);
|
|
this.fluidOnEyes = new HashSet();
|
|
@@ -924,9 +947,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
// CraftBukkit end
|
|
|
|
public void baseTick() {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("entityBaseTick");
|
|
+ //gameprofilerfiller.push("entityBaseTick"); // Purpur
|
|
if (firstTick && this instanceof net.minecraft.world.entity.NeutralMob neutralMob) neutralMob.tickInitialPersistentAnger(level); // Paper - Prevent entity loading causing async lookups
|
|
this.inBlockState = null;
|
|
if (this.isPassenger() && this.getVehicle().isRemoved()) {
|
|
@@ -995,7 +1018,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
}
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
public void setSharedFlagOnFire(boolean onFire) {
|
|
@@ -1009,6 +1032,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
&& this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> this.getY() >= v)
|
|
&& (!(this instanceof Player player) || !player.getAbilities().invulnerable))) {
|
|
// Paper end - Configurable nether ceiling damage
|
|
+ if (this.level().purpurConfig.teleportOnNetherCeilingDamage && this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER && this instanceof ServerPlayer player) player.teleport(io.papermc.paper.util.MCUtil.toLocation(this.level, this.level.getSharedSpawnPos())); else // Purpur
|
|
this.onBelowWorld();
|
|
}
|
|
|
|
@@ -1221,9 +1245,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
}
|
|
}
|
|
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("move");
|
|
+ //gameprofilerfiller.push("move"); // Purpur
|
|
if (this.stuckSpeedMultiplier.lengthSqr() > 1.0E-7D) {
|
|
movement = movement.multiply(this.stuckSpeedMultiplier);
|
|
this.stuckSpeedMultiplier = Vec3.ZERO;
|
|
@@ -1232,7 +1256,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
// Paper start - ignore movement changes while inactive.
|
|
if (isTemporarilyActive && !(this instanceof ItemEntity) && movement == getDeltaMovement() && type == MoverType.SELF) {
|
|
setDeltaMovement(Vec3.ZERO);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
return;
|
|
}
|
|
// Paper end
|
|
@@ -1253,8 +1277,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
this.setPos(this.getX() + vec3d1.x, this.getY() + vec3d1.y, this.getZ() + vec3d1.z);
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("rest");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("rest"); // Purpur
|
|
boolean flag = !Mth.equal(movement.x, vec3d1.x);
|
|
boolean flag1 = !Mth.equal(movement.z, vec3d1.z);
|
|
|
|
@@ -1276,7 +1300,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
}
|
|
|
|
if (this.isRemoved()) {
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
} else {
|
|
if (this.horizontalCollision) {
|
|
Vec3 vec3d2 = this.getDeltaMovement();
|
|
@@ -1325,7 +1349,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
float f = this.getBlockSpeedFactor();
|
|
|
|
this.setDeltaMovement(this.getDeltaMovement().multiply((double) f, 1.0D, (double) f));
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
}
|
|
// Paper start - detailed watchdog information
|
|
@@ -1970,7 +1994,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
}
|
|
|
|
public boolean fireImmune() {
|
|
- return this.getType().fireImmune();
|
|
+ return this.immuneToFire != null ? immuneToFire : this.getType().fireImmune(); // Purpur - add fire immune API
|
|
}
|
|
|
|
public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) {
|
|
@@ -2043,7 +2067,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
return this.isInWater() || flag;
|
|
}
|
|
|
|
- void updateInWaterStateAndDoWaterCurrentPushing() {
|
|
+ public void updateInWaterStateAndDoWaterCurrentPushing() { // Purpur - package-private -> public
|
|
Entity entity = this.getVehicle();
|
|
|
|
if (entity instanceof AbstractBoat abstractboat) {
|
|
@@ -2725,6 +2749,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
nbttagcompound.putBoolean("Paper.FreezeLock", true);
|
|
}
|
|
// Paper end
|
|
+ // Purpur start
|
|
+ if (immuneToFire != null) {
|
|
+ nbttagcompound.putBoolean("Purpur.FireImmune", immuneToFire);
|
|
+ }
|
|
+ // Purpur end
|
|
return nbttagcompound;
|
|
} catch (Throwable throwable) {
|
|
CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT");
|
|
@@ -2873,6 +2902,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
freezeLocked = nbt.getBoolean("Paper.FreezeLock");
|
|
}
|
|
// Paper end
|
|
+ // Purpur start
|
|
+ if (nbt.contains("Purpur.FireImmune")) {
|
|
+ immuneToFire = nbt.getBoolean("Purpur.FireImmune");
|
|
+ }
|
|
+ // Purpur end
|
|
|
|
} catch (Throwable throwable) {
|
|
CrashReport crashreport = CrashReport.forThrowable(throwable, "Loading entity NBT");
|
|
@@ -3124,6 +3158,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
if (this.isAlive() && this instanceof Leashable leashable) {
|
|
if (leashable.getLeashHolder() == player) {
|
|
if (!this.level().isClientSide()) {
|
|
+ if (hand == InteractionHand.OFF_HAND && (level().purpurConfig.villagerCanBeLeashed || level().purpurConfig.wanderingTraderCanBeLeashed) && this instanceof net.minecraft.world.entity.npc.AbstractVillager) return InteractionResult.CONSUME; // Purpur
|
|
// CraftBukkit start - fire PlayerUnleashEntityEvent
|
|
// Paper start - Expand EntityUnleashEvent
|
|
org.bukkit.event.player.PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(this, player, hand, !player.hasInfiniteMaterials());
|
|
@@ -3329,6 +3364,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
this.passengers = ImmutableList.copyOf(list);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ if (isRidable() && this.passengers.get(0) == passenger && passenger instanceof Player player) {
|
|
+ onMount(player);
|
|
+ this.rider = player;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
this.gameEvent(GameEvent.ENTITY_MOUNT, passenger);
|
|
}
|
|
}
|
|
@@ -3368,6 +3410,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
return false;
|
|
}
|
|
// CraftBukkit end
|
|
+
|
|
+ // Purpur start
|
|
+ if (this.rider != null && this.passengers.get(0) == this.rider) {
|
|
+ onDismount(this.rider);
|
|
+ this.rider = null;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
if (this.passengers.size() == 1 && this.passengers.get(0) == entity) {
|
|
this.passengers = ImmutableList.of();
|
|
} else {
|
|
@@ -3448,14 +3498,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
return Vec3.directionFromRotation(this.getRotationVector());
|
|
}
|
|
|
|
+ public BlockPos portalPos = BlockPos.ZERO; // Purpur
|
|
public void setAsInsidePortal(Portal portal, BlockPos pos) {
|
|
if (this.isOnPortalCooldown()) {
|
|
+ if (!(level().purpurConfig.playerFixStuckPortal && this instanceof Player && !pos.equals(this.portalPos))) // Purpur - Fix stuck in portals
|
|
this.setPortalCooldown();
|
|
- } else {
|
|
+ } else if (this.level.purpurConfig.entitiesCanUsePortals || this instanceof ServerPlayer) { // Purpur - Entities can use portals
|
|
if (this.portalProcess != null && this.portalProcess.isSamePortal(portal)) {
|
|
if (!this.portalProcess.isInsidePortalThisTick()) {
|
|
this.portalProcess.updateEntryPosition(pos.immutable());
|
|
this.portalProcess.setAsInsidePortalThisTick(true);
|
|
+ this.portalPos = BlockPos.ZERO; // Purpur - Fix stuck in portals
|
|
}
|
|
} else {
|
|
this.portalProcess = new PortalProcessor(portal, pos.immutable());
|
|
@@ -3471,9 +3524,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
this.processPortalCooldown();
|
|
if (this.portalProcess != null) {
|
|
if (this.portalProcess.processPortalTeleportation(worldserver, this, this.canUsePortal(false))) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("portal");
|
|
+ //gameprofilerfiller.push("portal"); // Purpur
|
|
this.setPortalCooldown();
|
|
TeleportTransition teleporttransition = this.portalProcess.getPortalDestination(worldserver, this);
|
|
|
|
@@ -3485,7 +3538,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
}
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
} else if (this.portalProcess.hasExpired()) {
|
|
this.portalProcess = null;
|
|
}
|
|
@@ -3672,7 +3725,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
}
|
|
|
|
public int getMaxAirSupply() {
|
|
- return this.maxAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir()
|
|
+ return this.level == null? this.maxAirTicks : this.level().purpurConfig.drowningAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() // Purpur
|
|
}
|
|
|
|
public int getAirSupply() {
|
|
@@ -4038,12 +4091,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
}
|
|
}
|
|
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("teleportCrossDimension");
|
|
+ //gameprofilerfiller.push("teleportCrossDimension"); // Purpur
|
|
entity = this.getType().create(world, EntitySpawnReason.DIMENSION_TRAVEL);
|
|
if (entity == null) {
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
return null;
|
|
} else {
|
|
// Paper start - Fix item duplication and teleport issues
|
|
@@ -4069,7 +4122,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
|
|
world.resetEmptyTime();
|
|
teleportTarget.postTeleportTransition().onTransition(entity);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
return entity;
|
|
}
|
|
}
|
|
@@ -4170,7 +4223,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
// CraftBukkit end
|
|
|
|
public boolean canUsePortal(boolean allowVehicles) {
|
|
- return (allowVehicles || !this.isPassenger()) && this.isAlive();
|
|
+ return (allowVehicles || !this.isPassenger()) && this.isAlive() && (this.level.purpurConfig.entitiesCanUsePortals || this instanceof ServerPlayer); // Purpur - Entities can use portals
|
|
}
|
|
|
|
public boolean canTeleport(Level from, Level to) {
|
|
@@ -4729,6 +4782,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
return Mth.lerp(delta, this.yRotO, this.yRot);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public AABB getAxisForFluidCheck() {
|
|
+ return this.getBoundingBox().deflate(0.001D);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
// Paper start - optimise collisions
|
|
public boolean updateFluidHeightAndDoFluidPushing(final TagKey<Fluid> fluid, final double flowScale) {
|
|
if (this.touchingUnloadedChunk()) {
|
|
@@ -5130,7 +5189,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
}
|
|
|
|
public float maxUpStep() {
|
|
- return 0.0F;
|
|
+ return maxUpStep;
|
|
}
|
|
|
|
public void onExplosionHit(@Nullable Entity entity) {}
|
|
@@ -5331,4 +5390,44 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
return ((net.minecraft.server.level.ServerChunkCache) level.getChunkSource()).isPositionTicking(this);
|
|
}
|
|
// Paper end - Expose entity id counter
|
|
+ // Purpur start
|
|
+ @Nullable
|
|
+ private Player rider = null;
|
|
+
|
|
+ @Nullable
|
|
+ public Player getRider() {
|
|
+ return rider;
|
|
+ }
|
|
+
|
|
+ public boolean isRidable() {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ public boolean isControllable() {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ public void onMount(Player rider) {
|
|
+ if (this instanceof Mob) {
|
|
+ ((Mob) this).setTarget(null, null, false);
|
|
+ ((Mob) this).getNavigation().stop();
|
|
+ }
|
|
+ rider.setJumping(false); // fixes jump on mount
|
|
+ }
|
|
+
|
|
+ public void onDismount(Player player) {
|
|
+ }
|
|
+
|
|
+ public boolean onSpacebar() {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ public boolean onClick(InteractionHand hand) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ public boolean processClick(InteractionHand hand) {
|
|
+ return false;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
|
index 6bf691fcc6486bde73bae30eff09142802c29eda..59c4d3753c7084e92402608b7fb3c4adbc6c2f65 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
|
@@ -39,6 +39,7 @@ public final class EntitySelector {
|
|
return net.minecraft.util.Mth.clamp(serverPlayer.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= playerInsomniaTicks;
|
|
};
|
|
// Paper end - Ability to control player's insomnia and phantoms
|
|
+ public static Predicate<Player> notAfk = (player) -> !player.isAfk(); // Purpur
|
|
|
|
private EntitySelector() {}
|
|
// Paper start - Affects Spawning API
|
|
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
|
|
index c8c2394558952d7ca57d29874485251b8f2b3400..c1a870fd22b193388513aad0ac4f3ce0ad7c8195 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
|
|
@@ -388,7 +388,8 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
|
|
@Nullable
|
|
private Component description;
|
|
private final Optional<ResourceKey<LootTable>> lootTable;
|
|
- private final EntityDimensions dimensions;
|
|
+ private EntityDimensions dimensions; // Purpur - remove final
|
|
+ public void setDimensions(EntityDimensions dimensions) { this.dimensions = dimensions; } // Purpur
|
|
private final float spawnDimensionsScale;
|
|
private final FeatureFlagSet requiredFeatures;
|
|
|
|
@@ -404,6 +405,16 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
|
|
return EntityType.register(EntityType.vanillaEntityId(id), type);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public static EntityType<?> getFromBukkitType(org.bukkit.entity.EntityType bukkitType) {
|
|
+ return getFromKey(ResourceLocation.parse(bukkitType.getKey().toString()));
|
|
+ }
|
|
+
|
|
+ public static EntityType<?> getFromKey(ResourceLocation location) {
|
|
+ return BuiltInRegistries.ENTITY_TYPE.getValue(location);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public static ResourceLocation getKey(EntityType<?> type) {
|
|
return BuiltInRegistries.ENTITY_TYPE.getKey(type);
|
|
}
|
|
@@ -604,6 +615,16 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
|
|
return this.category;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public String getName() {
|
|
+ return BuiltInRegistries.ENTITY_TYPE.getKey(this).getPath();
|
|
+ }
|
|
+
|
|
+ public String getTranslatedName() {
|
|
+ return getDescription().getString();
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public String getDescriptionId() {
|
|
return this.descriptionId;
|
|
}
|
|
@@ -661,6 +682,12 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
|
|
entity.load(nbt);
|
|
}, () -> {
|
|
EntityType.LOGGER.warn("Skipping Entity with id {}", nbt.getString("id"));
|
|
+ // Purpur start - log skipped entity's position
|
|
+ try {
|
|
+ ListTag pos = nbt.getList("Pos", 6);
|
|
+ EntityType.LOGGER.warn("Location: {} {},{},{}", world.getWorld().getName(), pos.getDouble(0), pos.getDouble(1), pos.getDouble(2));
|
|
+ } catch (Throwable ignore) {}
|
|
+ // Purpur end
|
|
});
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
|
index bf0838f574fa3fb9654e087d602b8d380bd7fb28..32a0db7e8f974712bd8a05f16f3bd48ac66142d5 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
|
@@ -333,7 +333,7 @@ public class ExperienceOrb extends Entity {
|
|
public void playerTouch(Player player) {
|
|
if (player instanceof ServerPlayer entityplayer) {
|
|
if (player.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(entityplayer.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent
|
|
- player.takeXpDelay = CraftEventFactory.callPlayerXpCooldownEvent(player, 2, PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2;
|
|
+ player.takeXpDelay = CraftEventFactory.callPlayerXpCooldownEvent(player, this.level().purpurConfig.playerExpPickupDelay, PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2; // Purpur
|
|
player.take(this, 1);
|
|
int i = this.repairPlayerItems(entityplayer, this.value);
|
|
|
|
@@ -351,7 +351,7 @@ public class ExperienceOrb extends Entity {
|
|
}
|
|
|
|
private int repairPlayerItems(ServerPlayer player, int amount) {
|
|
- Optional<EnchantedItemInUse> optional = EnchantmentHelper.getRandomItemWith(EnchantmentEffectComponents.REPAIR_WITH_XP, player, ItemStack::isDamaged);
|
|
+ Optional<EnchantedItemInUse> optional = level().purpurConfig.useBetterMending ? EnchantmentHelper.getMostDamagedItemWith(EnchantmentEffectComponents.REPAIR_WITH_XP, player) : EnchantmentHelper.getRandomItemWith(EnchantmentEffectComponents.REPAIR_WITH_XP, player, ItemStack::isDamaged); // Purpur - Add option to mend the most damaged equipment first
|
|
|
|
if (optional.isPresent()) {
|
|
ItemStack itemstack = ((EnchantedItemInUse) optional.get()).itemStack();
|
|
diff --git a/src/main/java/net/minecraft/world/entity/GlowSquid.java b/src/main/java/net/minecraft/world/entity/GlowSquid.java
|
|
index b851c3ee1426bc0a259bf6c4a662af0c9883dd71..3283228d7ebf98ce98780725a0a412bea4200da5 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/GlowSquid.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/GlowSquid.java
|
|
@@ -25,6 +25,39 @@ public class GlowSquid extends Squid {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.glowSquidRidable;
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.glowSquidControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.glowSquidMaxHealth);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canFly() {
|
|
+ return this.level().purpurConfig.glowSquidsCanFly;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.glowSquidTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.glowSquidAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected ParticleOptions getInkParticle() {
|
|
return ParticleTypes.GLOW_SQUID_INK;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
|
index 9c61225a728a2ca91a1c71dead75fc7cd93668b6..3349eefb4363041f77f95667a61d4468284b0858 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
|
@@ -248,9 +248,9 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
protected int deathScore;
|
|
public float lastHurt;
|
|
public boolean jumping;
|
|
- public float xxa;
|
|
- public float yya;
|
|
- public float zza;
|
|
+ public float xxa; public float getStrafeMot() { return xxa; } public void setStrafeMot(float strafe) { xxa = strafe; } // Purpur - OBFHELPER
|
|
+ public float yya; public float getVerticalMot() { return yya; } public void setVerticalMot(float vertical) { yya = vertical; } // Purpur - OBFHELPER
|
|
+ public float zza; public float getForwardMot() { return zza; } public void setForwardMot(float forward) { zza = forward; } // Purpur - OBFHELPER
|
|
protected int lerpSteps;
|
|
protected double lerpX;
|
|
protected double lerpY;
|
|
@@ -297,6 +297,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper
|
|
public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event
|
|
public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API
|
|
+ protected boolean shouldBurnInDay = false; public boolean shouldBurnInDay() { return this.shouldBurnInDay; } public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } // Purpur - API for any mob to burn daylight
|
|
|
|
@Override
|
|
public float getBukkitYaw() {
|
|
@@ -325,7 +326,8 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
this.lastClimbablePos = Optional.empty();
|
|
this.activeLocationDependentEnchantments = new EnumMap(EquipmentSlot.class);
|
|
this.appliedScale = 1.0F;
|
|
- this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type));
|
|
+ this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type), this); // Purpur
|
|
+ this.initAttributes(); // Purpur
|
|
this.craftAttributes = new CraftAttributeMap(this.attributes); // CraftBukkit
|
|
// CraftBukkit - setHealth(getMaxHealth()) inlined and simplified to skip the instanceof check for EntityPlayer, as getBukkitEntity() is not initialized in constructor
|
|
this.entityData.set(LivingEntity.DATA_HEALTH_ID, (float) this.getAttribute(Attributes.MAX_HEALTH).getValue());
|
|
@@ -340,6 +342,8 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
this.brain = this.makeBrain(new Dynamic(dynamicopsnbt, (Tag) dynamicopsnbt.createMap((Map) ImmutableMap.of(dynamicopsnbt.createString("memories"), (Tag) dynamicopsnbt.emptyMap()))));
|
|
}
|
|
|
|
+ protected void initAttributes() {}// Purpur
|
|
+
|
|
public Brain<?> getBrain() {
|
|
return this.brain;
|
|
}
|
|
@@ -375,6 +379,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
public static AttributeSupplier.Builder createLivingAttributes() {
|
|
return AttributeSupplier.builder().add(Attributes.MAX_HEALTH).add(Attributes.KNOCKBACK_RESISTANCE).add(Attributes.MOVEMENT_SPEED).add(Attributes.ARMOR).add(Attributes.ARMOR_TOUGHNESS).add(Attributes.MAX_ABSORPTION).add(Attributes.STEP_HEIGHT).add(Attributes.SCALE).add(Attributes.GRAVITY).add(Attributes.SAFE_FALL_DISTANCE).add(Attributes.FALL_DAMAGE_MULTIPLIER).add(Attributes.JUMP_STRENGTH).add(Attributes.OXYGEN_BONUS).add(Attributes.BURNING_TIME).add(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE).add(Attributes.WATER_MOVEMENT_EFFICIENCY).add(Attributes.MOVEMENT_EFFICIENCY).add(Attributes.ATTACK_KNOCKBACK);
|
|
}
|
|
+ public boolean shouldSendAttribute(Attribute attribute) { return true; } // Purpur
|
|
|
|
@Override
|
|
protected void checkFallDamage(double heightDifference, boolean onGround, BlockState state, BlockPos landedPosition) {
|
|
@@ -452,9 +457,9 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
}
|
|
|
|
super.baseTick();
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("livingEntityBaseTick");
|
|
+ //gameprofilerfiller.push("livingEntityBaseTick"); // Purpur
|
|
if (this.fireImmune() || this.level().isClientSide) {
|
|
this.clearFire();
|
|
}
|
|
@@ -475,6 +480,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
if (d1 < 0.0D) {
|
|
d0 = this.level().getWorldBorder().getDamagePerBlock();
|
|
if (d0 > 0.0D) {
|
|
+ if (level().purpurConfig.teleportIfOutsideBorder && this instanceof ServerPlayer serverPlayer) { serverPlayer.teleport(io.papermc.paper.util.MCUtil.toLocation(level(), ((ServerLevel) level()).getSharedSpawnPos())); return; } // Purpur
|
|
this.hurtServer(worldserver1, this.damageSources().outOfBorder(), (float) Math.max(1, Mth.floor(-d1 * d0)));
|
|
}
|
|
}
|
|
@@ -486,7 +492,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
|
|
if (flag1) {
|
|
this.setAirSupply(this.decreaseAirSupply(this.getAirSupply()));
|
|
- if (this.getAirSupply() == -20) {
|
|
+ if (this.getAirSupply() == -this.level().purpurConfig.drowningDamageInterval) { // Purpur
|
|
this.setAirSupply(0);
|
|
Vec3 vec3d = this.getDeltaMovement();
|
|
|
|
@@ -498,7 +504,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
this.level().addParticle(ParticleTypes.BUBBLE, this.getX() + d0, this.getY() + d2, this.getZ() + d3, vec3d.x, vec3d.y, vec3d.z);
|
|
}
|
|
|
|
- this.hurt(this.damageSources().drown(), 2.0F);
|
|
+ this.hurt(this.damageSources().drown(), (float) this.level().purpurConfig.damageFromDrowning); // Purpur
|
|
}
|
|
}
|
|
|
|
@@ -561,7 +567,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
this.yHeadRotO = this.yHeadRot;
|
|
this.yRotO = this.getYRot();
|
|
this.xRotO = this.getXRot();
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -834,6 +840,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> {
|
|
nbt.put("Brain", nbtbase);
|
|
});
|
|
+ nbt.putBoolean("Purpur.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - API for any mob to burn daylight
|
|
}
|
|
|
|
@Override
|
|
@@ -922,6 +929,11 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
this.brain = this.makeBrain(new Dynamic(NbtOps.INSTANCE, nbt.get("Brain")));
|
|
}
|
|
|
|
+ // Purpur start - API for any mob to burn daylight
|
|
+ if (nbt.contains("Purpur.ShouldBurnInDay")) {
|
|
+ this.shouldBurnInDay = nbt.getBoolean("Purpur.ShouldBurnInDay");
|
|
+ }
|
|
+ // Purpur end - API for any mob to burn daylight
|
|
}
|
|
|
|
// CraftBukkit start
|
|
@@ -1057,9 +1069,31 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD);
|
|
EntityType<?> entitytypes = entity.getType();
|
|
|
|
- if (entitytypes == EntityType.SKELETON && itemstack.is(Items.SKELETON_SKULL) || entitytypes == EntityType.ZOMBIE && itemstack.is(Items.ZOMBIE_HEAD) || entitytypes == EntityType.PIGLIN && itemstack.is(Items.PIGLIN_HEAD) || entitytypes == EntityType.PIGLIN_BRUTE && itemstack.is(Items.PIGLIN_HEAD) || entitytypes == EntityType.CREEPER && itemstack.is(Items.CREEPER_HEAD)) {
|
|
- d0 *= 0.5D;
|
|
+ // Purpur start
|
|
+ if (entitytypes == EntityType.SKELETON && itemstack.is(Items.SKELETON_SKULL)) {
|
|
+ d0 *= entity.level().purpurConfig.skeletonHeadVisibilityPercent;
|
|
+ }
|
|
+ else if (entitytypes == EntityType.ZOMBIE && itemstack.is(Items.ZOMBIE_HEAD)) {
|
|
+ d0 *= entity.level().purpurConfig.zombieHeadVisibilityPercent;
|
|
}
|
|
+ else if (entitytypes == EntityType.CREEPER && itemstack.is(Items.CREEPER_HEAD)) {
|
|
+ d0 *= entity.level().purpurConfig.creeperHeadVisibilityPercent;
|
|
+ }
|
|
+ else if ((entitytypes == EntityType.PIGLIN || entitytypes == EntityType.PIGLIN_BRUTE) && itemstack.is(Items.PIGLIN_HEAD)) {
|
|
+ d0 *= entity.level().purpurConfig.piglinHeadVisibilityPercent;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ // Purpur start
|
|
+ if (entity instanceof LivingEntity entityliving) {
|
|
+ if (entityliving.hasEffect(MobEffects.BLINDNESS)) {
|
|
+ int amplifier = entityliving.getEffect(MobEffects.BLINDNESS).getAmplifier();
|
|
+ for (int i = 0; i < amplifier; i++) {
|
|
+ d0 *= this.level().purpurConfig.mobsBlindnessMultiplier;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
|
|
return d0;
|
|
@@ -1115,6 +1149,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
|
|
while (iterator.hasNext()) {
|
|
MobEffectInstance effect = iterator.next();
|
|
+ if (cause == EntityPotionEffectEvent.Cause.MILK && !this.level().purpurConfig.milkClearsBeneficialEffects && effect.getEffect().value().isBeneficial()) continue; // Purpur
|
|
EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, effect, null, cause, EntityPotionEffectEvent.Action.CLEARED);
|
|
if (event.isCancelled()) {
|
|
continue;
|
|
@@ -1450,6 +1485,24 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
this.stopSleeping();
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ if (source.getEntity() instanceof net.minecraft.world.entity.player.Player player && source.getEntity().level().purpurConfig.creativeOnePunch && !source.is(DamageTypeTags.IS_PROJECTILE)) {
|
|
+ if (player.isCreative()) {
|
|
+ org.apache.commons.lang3.mutable.MutableDouble attackDamage = new org.apache.commons.lang3.mutable.MutableDouble();
|
|
+ player.getMainHandItem().forEachModifier(EquipmentSlot.MAINHAND, (attributeHolder, attributeModifier) -> {
|
|
+ if (attributeModifier.operation() == AttributeModifier.Operation.ADD_VALUE) {
|
|
+ attackDamage.addAndGet(attributeModifier.amount());
|
|
+ }
|
|
+ });
|
|
+
|
|
+ if (attackDamage.doubleValue() == 0.0D) {
|
|
+ // One punch!
|
|
+ amount = 9999F;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
this.noActionTime = 0;
|
|
if (amount < 0.0F) {
|
|
amount = 0.0F;
|
|
@@ -1549,13 +1602,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
if (entity1 instanceof net.minecraft.world.entity.player.Player) {
|
|
net.minecraft.world.entity.player.Player entityhuman = (net.minecraft.world.entity.player.Player) entity1;
|
|
|
|
- this.lastHurtByPlayerTime = 100;
|
|
+ this.lastHurtByPlayerTime = this.level().purpurConfig.mobLastHurtByPlayerTime; // Purpur
|
|
this.lastHurtByPlayer = entityhuman;
|
|
} else if (entity1 instanceof Wolf) {
|
|
Wolf entitywolf = (Wolf) entity1;
|
|
|
|
if (entitywolf.isTame()) {
|
|
- this.lastHurtByPlayerTime = 100;
|
|
+ this.lastHurtByPlayerTime = this.level().purpurConfig.mobLastHurtByPlayerTime; // Purpur
|
|
LivingEntity entityliving2 = entitywolf.getOwner();
|
|
|
|
if (entityliving2 instanceof net.minecraft.world.entity.player.Player) {
|
|
@@ -1702,6 +1755,18 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
}
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ if (level().purpurConfig.totemOfUndyingWorksInInventory && this instanceof ServerPlayer player && (itemstack == null || itemstack.getItem() != Items.TOTEM_OF_UNDYING) && player.getBukkitEntity().hasPermission("purpur.inventory_totem")) {
|
|
+ for (ItemStack item : player.getInventory().items) {
|
|
+ if (item.getItem() == Items.TOTEM_OF_UNDYING) {
|
|
+ itemstack1 = item;
|
|
+ itemstack = item.copy();
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
org.bukkit.inventory.EquipmentSlot handSlot = (hand != null) ? org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand) : null;
|
|
EntityResurrectEvent event = new EntityResurrectEvent((org.bukkit.entity.LivingEntity) this.getBukkitEntity(), handSlot);
|
|
event.setCancelled(itemstack == null);
|
|
@@ -1867,7 +1932,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
boolean flag = false;
|
|
|
|
if (this.dead && adversary instanceof WitherBoss) { // Paper
|
|
- if (worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
|
+ if (worldserver.purpurConfig.witherBypassMobGriefing || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur
|
|
BlockPos blockposition = this.blockPosition();
|
|
BlockState iblockdata = Blocks.WITHER_ROSE.defaultBlockState();
|
|
|
|
@@ -1904,6 +1969,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
|
|
this.dropEquipment(world); // CraftBukkit - from below
|
|
if (this.shouldDropLoot() && world.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
|
|
+ if (!(damageSource.is(net.minecraft.world.damagesource.DamageTypes.CRAMMING) && level().purpurConfig.disableDropsOnCrammingDeath)) { // Purpur
|
|
this.dropFromLootTable(world, damageSource, flag);
|
|
// Paper start
|
|
final boolean prev = this.clearEquipmentSlots;
|
|
@@ -1912,6 +1978,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
// Paper end
|
|
this.dropCustomDeathLoot(world, damageSource, flag);
|
|
this.clearEquipmentSlots = prev; // Paper
|
|
+ } // Purpur
|
|
}
|
|
// CraftBukkit start - Call death event // Paper start - call advancement triggers with correct entity equipment
|
|
org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops, () -> {
|
|
@@ -3123,6 +3190,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
|
|
if (f > 0.0F) {
|
|
this.playSound(this.getFallDamageSound((int) f), 1.0F, 1.0F);
|
|
+ if (level().purpurConfig.elytraKineticDamage) // Purpur
|
|
this.hurt(this.damageSources().flyIntoWall(), f);
|
|
}
|
|
}
|
|
@@ -3315,12 +3383,12 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
}
|
|
|
|
this.run += (f3 - this.run) * 0.3F;
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("headTurn");
|
|
+ //gameprofilerfiller.push("headTurn"); // Purpur
|
|
f2 = this.tickHeadTurn(f1, f2);
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("rangeChecks");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("rangeChecks"); // Purpur
|
|
|
|
// Paper start - stop large pitch and yaw changes from crashing the server
|
|
this.yRotO += Math.round((this.getYRot() - this.yRotO) / 360.0F) * 360.0F;
|
|
@@ -3332,7 +3400,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
this.yHeadRotO += Math.round((this.yHeadRot - this.yHeadRotO) / 360.0F) * 360.0F;
|
|
// Paper end
|
|
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
this.animStep += f2;
|
|
if (this.isFallFlying()) {
|
|
++this.fallFlyTicks;
|
|
@@ -3562,21 +3630,21 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
}
|
|
|
|
this.setDeltaMovement(d0, d1, d2);
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("ai");
|
|
+ //gameprofilerfiller.push("ai"); // Purpur
|
|
if (this.isImmobile()) {
|
|
this.jumping = false;
|
|
this.xxa = 0.0F;
|
|
this.zza = 0.0F;
|
|
} else if (this.isEffectiveAi()) {
|
|
- gameprofilerfiller.push("newAi");
|
|
+ //gameprofilerfiller.push("newAi"); // Purpur
|
|
this.serverAiStep();
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("jump");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("jump"); // Purpur
|
|
if (this.jumping && this.isAffectedByFluids()) {
|
|
double d3;
|
|
|
|
@@ -3603,8 +3671,8 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
this.noJumpDelay = 0;
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("travel");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("travel"); // Purpur
|
|
this.xxa *= 0.98F;
|
|
this.zza *= 0.98F;
|
|
if (this.isFallFlying()) {
|
|
@@ -3637,8 +3705,8 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
}
|
|
|
|
this.calculateEntityAnimation(this instanceof FlyingAnimal);
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("freezing");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("freezing"); // Purpur
|
|
if (!this.level().isClientSide && !this.isDeadOrDying() && !this.freezeLocked) { // Paper - Freeze Tick Lock API
|
|
int i = this.getTicksFrozen();
|
|
|
|
@@ -3659,18 +3727,20 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
}
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("push");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("push"); // Purpur
|
|
if (this.autoSpinAttackTicks > 0) {
|
|
--this.autoSpinAttackTicks;
|
|
this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox());
|
|
}
|
|
|
|
this.pushEntities();
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
// Paper start - Add EntityMoveEvent
|
|
- if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof net.minecraft.world.entity.player.Player)) {
|
|
- if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) {
|
|
+ // Purpur start
|
|
+ if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) {
|
|
+ if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof net.minecraft.world.entity.player.Player)) {
|
|
+ // Purpur end
|
|
Location from = new Location(this.level().getWorld(), this.xo, this.yo, this.zo, this.yRotO, this.xRotO);
|
|
Location to = new Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
|
|
io.papermc.paper.event.entity.EntityMoveEvent event = new io.papermc.paper.event.entity.EntityMoveEvent(this.getBukkitLivingEntity(), from, to.clone());
|
|
@@ -3680,6 +3750,21 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
this.absMoveTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch());
|
|
}
|
|
}
|
|
+ // Purpur start
|
|
+ if (getRider() != null) {
|
|
+ getRider().resetLastActionTime();
|
|
+ if (((ServerLevel) level()).hasRidableMoveEvent && this instanceof Mob) {
|
|
+ Location from = new Location(level().getWorld(), xo, yo, zo, this.yRotO, this.xRotO);
|
|
+ Location to = new Location(level().getWorld(), getX(), getY(), getZ(), this.getYRot(), this.getXRot());
|
|
+ org.purpurmc.purpur.event.entity.RidableMoveEvent event = new org.purpurmc.purpur.event.entity.RidableMoveEvent((org.bukkit.entity.Mob) getBukkitLivingEntity(), (Player) getRider().getBukkitEntity(), from, to.clone());
|
|
+ if (!event.callEvent()) {
|
|
+ absMoveTo(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch());
|
|
+ } else if (!to.equals(event.getTo())) {
|
|
+ absMoveTo(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
// Paper end - Add EntityMoveEvent
|
|
world = this.level();
|
|
@@ -3689,6 +3774,34 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
}
|
|
}
|
|
|
|
+ // Purpur start - copied from Zombie - API for any mob to burn daylight
|
|
+ if (this.isAlive()) {
|
|
+ boolean flag = this.shouldBurnInDay() && this.isSunBurnTick(); // Paper - shouldBurnInDay API // Purpur - use shouldBurnInDay() method to handle Phantoms properly - API for any mob to burn daylight
|
|
+
|
|
+ if (flag) {
|
|
+ ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD);
|
|
+
|
|
+ if (!itemstack.isEmpty()) {
|
|
+ if (itemstack.isDamageableItem()) {
|
|
+ Item item = itemstack.getItem();
|
|
+
|
|
+ itemstack.setDamageValue(itemstack.getDamageValue() + this.random.nextInt(2));
|
|
+ if (itemstack.getDamageValue() >= itemstack.getMaxDamage()) {
|
|
+ this.onEquippedItemBroken(item, EquipmentSlot.HEAD);
|
|
+ this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ flag = false;
|
|
+ }
|
|
+
|
|
+ if (flag) {
|
|
+ if (getRider() == null || !this.isControllable()) // Purpur - ignore mobs which are uncontrollable or without rider - API for any mob to burn daylight
|
|
+ this.igniteForSeconds(8.0F);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Purpur end - copied from Zombie - API for any mob to burn daylight
|
|
}
|
|
|
|
public boolean isSensitiveToWater() {
|
|
@@ -3715,7 +3828,17 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
}).toList();
|
|
EquipmentSlot enumitemslot = (EquipmentSlot) Util.getRandom(list, this.random);
|
|
|
|
- this.getItemBySlot(enumitemslot).hurtAndBreak(1, this, enumitemslot);
|
|
+ // Purpur start
|
|
+ int damage = level().purpurConfig.elytraDamagePerSecond;
|
|
+ if (level().purpurConfig.elytraDamageMultiplyBySpeed > 0) {
|
|
+ double speed = getDeltaMovement().lengthSqr();
|
|
+ if (speed > level().purpurConfig.elytraDamageMultiplyBySpeed) {
|
|
+ damage *= (int) speed;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ this.getItemBySlot(enumitemslot).hurtAndBreak(damage, this, enumitemslot);
|
|
+ // Purpur end
|
|
}
|
|
|
|
this.gameEvent(GameEvent.ELYTRA_GLIDE);
|
|
@@ -3724,7 +3847,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
|
|
}
|
|
|
|
- protected boolean canGlide() {
|
|
+ public boolean canGlide() { // Purpur
|
|
if (!this.onGround() && !this.isPassenger() && !this.hasEffect(MobEffects.LEVITATION)) {
|
|
Iterator iterator = EquipmentSlot.VALUES.iterator();
|
|
|
|
@@ -4646,7 +4769,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
if (equippable != null && equippable.dispensable()) {
|
|
EquipmentSlot enumitemslot = equippable.slot();
|
|
|
|
- return this.canUseSlot(enumitemslot) && equippable.canBeEquippedBy(this.getType()) ? this.getItemBySlot(enumitemslot).isEmpty() && this.canDispenserEquipIntoSlot(enumitemslot) : false;
|
|
+ return this.canUseSlot(enumitemslot) && equippable.canBeEquippedBy(this.getType()) && this.getItemBySlot(enumitemslot).isEmpty() && this.canDispenserEquipIntoSlot(enumitemslot);
|
|
} else {
|
|
return false;
|
|
}
|
|
@@ -4671,6 +4794,12 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
return equippable == null ? slot == EquipmentSlot.MAINHAND && this.canUseSlot(EquipmentSlot.MAINHAND) : slot == equippable.slot() && this.canUseSlot(equippable.slot()) && equippable.canBeEquippedBy(this.getType());
|
|
}
|
|
|
|
+ // Purpur start - Dispenser curse of binding protection
|
|
+ public @Nullable EquipmentSlot getEquipmentSlotForDispenserItem(ItemStack itemstack) {
|
|
+ return EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.BINDING_CURSE, itemstack) > 0 ? null : this.getEquipmentSlotForItem(itemstack);
|
|
+ }
|
|
+ // Purpur end - Dispenser curse of binding protection
|
|
+
|
|
private static SlotAccess createEquipmentSlotAccess(LivingEntity entity, EquipmentSlot slot) {
|
|
return slot != EquipmentSlot.HEAD && slot != EquipmentSlot.MAINHAND && slot != EquipmentSlot.OFFHAND ? SlotAccess.forEquipmentSlot(entity, slot, (itemstack) -> {
|
|
return itemstack.isEmpty() || entity.getEquipmentSlotForItem(itemstack) == slot;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
|
index dbd321f3dc3cc80737830db63aed47a6935e8e89..ff9d23aef4658922692b43a859bd83632fe23612 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
|
@@ -148,6 +148,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
private BlockPos restrictCenter;
|
|
private float restrictRadius;
|
|
|
|
+ public int ticksSinceLastInteraction; // Purpur
|
|
public boolean aware = true; // CraftBukkit
|
|
|
|
protected Mob(EntityType<? extends Mob> type, Level world) {
|
|
@@ -163,8 +164,8 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
this.restrictRadius = -1.0F;
|
|
this.goalSelector = new GoalSelector();
|
|
this.targetSelector = new GoalSelector();
|
|
- this.lookControl = new LookControl(this);
|
|
- this.moveControl = new MoveControl(this);
|
|
+ this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this); // Purpur
|
|
+ this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this); // Purpur
|
|
this.jumpControl = new JumpControl(this);
|
|
this.bodyRotationControl = this.createBodyControl();
|
|
this.navigation = this.createNavigation(world);
|
|
@@ -334,6 +335,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
entityliving = null;
|
|
}
|
|
}
|
|
+ if (entityliving instanceof net.minecraft.server.level.ServerPlayer) this.ticksSinceLastInteraction = 0; // Purpur
|
|
this.target = entityliving;
|
|
return true;
|
|
// CraftBukkit end
|
|
@@ -369,17 +371,37 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
@Override
|
|
public void baseTick() {
|
|
super.baseTick();
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("mobBaseTick");
|
|
+ //gameprofilerfiller.push("mobBaseTick"); // Purpur
|
|
if (this.isAlive() && this.random.nextInt(1000) < this.ambientSoundTime++) {
|
|
this.resetAmbientSoundTime();
|
|
this.playAmbientSound();
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ incrementTicksSinceLastInteraction(); // Purpur
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ private void incrementTicksSinceLastInteraction() {
|
|
+ ++this.ticksSinceLastInteraction;
|
|
+ if (getRider() != null) {
|
|
+ this.ticksSinceLastInteraction = 0;
|
|
+ return;
|
|
+ }
|
|
+ if (this.level().purpurConfig.entityLifeSpan <= 0) {
|
|
+ return; // feature disabled
|
|
+ }
|
|
+ if (!this.removeWhenFarAway(0) || isPersistenceRequired() || requiresCustomPersistence() || hasCustomName()) {
|
|
+ return; // mob persistent
|
|
+ }
|
|
+ if (this.ticksSinceLastInteraction > this.level().purpurConfig.entityLifeSpan) {
|
|
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void playHurtSound(DamageSource damageSource) {
|
|
this.resetAmbientSoundTime();
|
|
@@ -547,6 +569,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
}
|
|
|
|
nbt.putBoolean("Bukkit.Aware", this.aware); // CraftBukkit
|
|
+ nbt.putInt("Purpur.ticksSinceLastInteraction", this.ticksSinceLastInteraction); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -624,6 +647,11 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
this.aware = nbt.getBoolean("Bukkit.Aware");
|
|
}
|
|
// CraftBukkit end
|
|
+ // Purpur start
|
|
+ if (nbt.contains("Purpur.ticksSinceLastInteraction")) {
|
|
+ this.ticksSinceLastInteraction = nbt.getInt("Purpur.ticksSinceLastInteraction");
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
|
|
@Override
|
|
@@ -670,13 +698,13 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
@Override
|
|
public void aiStep() {
|
|
super.aiStep();
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("looting");
|
|
+ //gameprofilerfiller.push("looting"); // Purpur
|
|
Level world = this.level();
|
|
|
|
if (world instanceof ServerLevel worldserver) {
|
|
- if (this.canPickUpLoot() && this.isAlive() && !this.dead && worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
|
+ if (this.canPickUpLoot() && this.isAlive() && !this.dead && (worldserver.purpurConfig.entitiesPickUpLootBypassMobGriefing || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // Purpur
|
|
Vec3i baseblockposition = this.getPickupReach();
|
|
List<ItemEntity> list = this.level().getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate((double) baseblockposition.getX(), (double) baseblockposition.getY(), (double) baseblockposition.getZ()));
|
|
Iterator iterator = list.iterator();
|
|
@@ -696,7 +724,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
}
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
protected Vec3i getPickupReach() {
|
|
@@ -918,44 +946,44 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
return;
|
|
}
|
|
// Paper end - Allow nerfed mobs to jump and float
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("sensing");
|
|
+ //gameprofilerfiller.push("sensing"); // Purpur
|
|
this.sensing.tick();
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
int i = this.tickCount + this.getId();
|
|
|
|
if (i % 2 != 0 && this.tickCount > 1) {
|
|
- gameprofilerfiller.push("targetSelector");
|
|
+ //gameprofilerfiller.push("targetSelector"); // Purpur
|
|
this.targetSelector.tickRunningGoals(false);
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("goalSelector");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("goalSelector"); // Purpur
|
|
this.goalSelector.tickRunningGoals(false);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
} else {
|
|
- gameprofilerfiller.push("targetSelector");
|
|
+ //gameprofilerfiller.push("targetSelector"); // Purpur
|
|
this.targetSelector.tick();
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("goalSelector");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("goalSelector"); // Purpur
|
|
this.goalSelector.tick();
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
- gameprofilerfiller.push("navigation");
|
|
+ //gameprofilerfiller.push("navigation"); // Purpur
|
|
this.navigation.tick();
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("mob tick");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("mob tick"); // Purpur
|
|
this.customServerAiStep((ServerLevel) this.level());
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("controls");
|
|
- gameprofilerfiller.push("move");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("controls"); // Purpur
|
|
+ //gameprofilerfiller.push("move"); // Purpur
|
|
this.moveControl.tick();
|
|
- gameprofilerfiller.popPush("look");
|
|
+ //gameprofilerfiller.popPush("look"); // Purpur
|
|
this.lookControl.tick();
|
|
- gameprofilerfiller.popPush("jump");
|
|
+ //gameprofilerfiller.popPush("jump"); // Purpur
|
|
this.jumpControl.tick();
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
this.sendDebugPackets();
|
|
}
|
|
|
|
@@ -1394,7 +1422,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
attributemodifiable.addPermanentModifier(new AttributeModifier(Mob.RANDOM_SPAWN_BONUS_ID, randomsource.triangle(0.0D, 0.11485000000000001D), AttributeModifier.Operation.ADD_MULTIPLIED_BASE));
|
|
}
|
|
|
|
- this.setLeftHanded(randomsource.nextFloat() < 0.05F);
|
|
+ this.setLeftHanded(randomsource.nextFloat() < world.getLevel().purpurConfig.entityLeftHandedChance); // Purpur
|
|
return entityData;
|
|
}
|
|
|
|
@@ -1496,7 +1524,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
protected void onOffspringSpawnedFromEgg(Player player, Mob child) {}
|
|
|
|
protected InteractionResult mobInteract(Player player, InteractionHand hand) {
|
|
- return InteractionResult.PASS;
|
|
+ return tryRide(player, hand); // Purpur
|
|
}
|
|
|
|
public boolean isWithinRestriction() {
|
|
@@ -1735,23 +1763,15 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
this.playAttackSound();
|
|
}
|
|
|
|
+ if (target instanceof net.minecraft.server.level.ServerPlayer) this.ticksSinceLastInteraction = 0; // Purpur
|
|
return flag;
|
|
}
|
|
|
|
protected void playAttackSound() {}
|
|
|
|
public boolean isSunBurnTick() {
|
|
- if (this.level().isDay() && !this.level().isClientSide) {
|
|
- float f = this.getLightLevelDependentMagicValue();
|
|
- BlockPos blockposition = BlockPos.containing(this.getX(), this.getEyeY(), this.getZ());
|
|
- boolean flag = this.isInWaterRainOrBubble() || this.isInPowderSnow || this.wasInPowderSnow;
|
|
-
|
|
- if (f > 0.5F && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && !flag && this.level().canSeeSky(blockposition)) {
|
|
- return true;
|
|
- }
|
|
- }
|
|
-
|
|
- return false;
|
|
+ // Purpur - implemented in Entity - API for any mob to burn daylight
|
|
+ return super.isSunBurnTick();
|
|
}
|
|
|
|
@Override
|
|
@@ -1813,4 +1833,58 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
|
public float[] getArmorDropChances() {
|
|
return this.armorDropChances;
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ public double getMaxY() {
|
|
+ return level().getHeight();
|
|
+ }
|
|
+
|
|
+ public InteractionResult tryRide(Player player, InteractionHand hand) {
|
|
+ return tryRide(player, hand, InteractionResult.PASS);
|
|
+ }
|
|
+
|
|
+ public InteractionResult tryRide(Player player, InteractionHand hand, InteractionResult result) {
|
|
+ if (!isRidable()) {
|
|
+ return result;
|
|
+ }
|
|
+ if (hand != InteractionHand.MAIN_HAND) {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+ if (player.isShiftKeyDown()) {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+ if (!player.getItemInHand(hand).isEmpty()) {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+ if (!passengers.isEmpty() || player.isPassenger()) {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+ if (this instanceof TamableAnimal tamable) {
|
|
+ if (tamable.isTame() && !tamable.isOwnedBy(player)) {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+ if (!tamable.isTame() && !level().purpurConfig.untamedTamablesAreRidable) {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+ }
|
|
+ if (this instanceof AgeableMob ageable) {
|
|
+ if (ageable.isBaby() && !level().purpurConfig.babiesAreRidable) {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+ }
|
|
+ if (!player.getBukkitEntity().hasPermission("allow.ride." + net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getKey(getType()).getPath())) {
|
|
+ if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
|
|
+ serverPlayer.sendMiniMessage(org.purpurmc.purpur.PurpurConfig.cannotRideMob);
|
|
+ }
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+ player.setYRot(this.getYRot());
|
|
+ player.setXRot(this.getXRot());
|
|
+ if (player.startRiding(this)) {
|
|
+ return InteractionResult.SUCCESS;
|
|
+ } else {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
|
index 94d04a20f97405e02d7cccaabadc7a7e86e336f7..06b890275d1a171d609b91a1d1a018c43b943ab2 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
|
@@ -23,14 +23,21 @@ public class AttributeMap {
|
|
private final Set<AttributeInstance> attributesToSync = new ObjectOpenHashSet<>();
|
|
private final Set<AttributeInstance> attributesToUpdate = new ObjectOpenHashSet<>();
|
|
private final AttributeSupplier supplier;
|
|
+ private final net.minecraft.world.entity.LivingEntity entity; // Purpur
|
|
|
|
public AttributeMap(AttributeSupplier defaultAttributes) {
|
|
+ // Purpur start
|
|
+ this(defaultAttributes, null);
|
|
+ }
|
|
+ public AttributeMap(AttributeSupplier defaultAttributes, net.minecraft.world.entity.LivingEntity entity) {
|
|
+ this.entity = entity;
|
|
+ // Purpur end
|
|
this.supplier = defaultAttributes;
|
|
}
|
|
|
|
private void onAttributeModified(AttributeInstance instance) {
|
|
this.attributesToUpdate.add(instance);
|
|
- if (instance.getAttribute().value().isClientSyncable()) {
|
|
+ if (instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))) { // Purpur
|
|
this.attributesToSync.add(instance);
|
|
}
|
|
}
|
|
@@ -44,7 +51,7 @@ public class AttributeMap {
|
|
}
|
|
|
|
public Collection<AttributeInstance> getSyncableAttributes() {
|
|
- return this.attributes.values().stream().filter(attribute -> attribute.getAttribute().value().isClientSyncable()).collect(Collectors.toList());
|
|
+ return this.attributes.values().stream().filter(attribute -> attribute.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(attribute.getAttribute().value()))).collect(Collectors.toList()); // Purpur
|
|
}
|
|
|
|
@Nullable
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java b/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java
|
|
index 386f9bca728055f7b75fb690b307ff4510068105..157fe8979c780300b6f72cbaa17729031e3b386d 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java
|
|
@@ -130,7 +130,7 @@ public class DefaultAttributes {
|
|
.put(EntityType.OCELOT, Ocelot.createAttributes().build())
|
|
.put(EntityType.PANDA, Panda.createAttributes().build())
|
|
.put(EntityType.PARROT, Parrot.createAttributes().build())
|
|
- .put(EntityType.PHANTOM, Monster.createMonsterAttributes().build())
|
|
+ .put(EntityType.PHANTOM, net.minecraft.world.entity.monster.Phantom.createAttributes().build()) // Purpur
|
|
.put(EntityType.PIG, Pig.createAttributes().build())
|
|
.put(EntityType.PIGLIN, Piglin.createAttributes().build())
|
|
.put(EntityType.PIGLIN_BRUTE, PiglinBrute.createAttributes().build())
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/RangedAttribute.java b/src/main/java/net/minecraft/world/entity/ai/attributes/RangedAttribute.java
|
|
index f0703302e7dbbda88de8c648d20d87c55ed9b1e0..a913ebabaa5f443afa987b972355a8f8d1723c78 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/attributes/RangedAttribute.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/attributes/RangedAttribute.java
|
|
@@ -29,6 +29,7 @@ public class RangedAttribute extends Attribute {
|
|
|
|
@Override
|
|
public double sanitizeValue(double value) {
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.clampAttributes) return Double.isNaN(value) ? this.minValue : value; // Purpur
|
|
return Double.isNaN(value) ? this.minValue : Mth.clamp(value, this.minValue, this.maxValue);
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
|
index e1b6fe9ecda25f86431baf414f1bfd3a26a8b2bd..3d7578605812021bc84b99d4db1672a682d897ad 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
|
@@ -73,7 +73,7 @@ public class AcquirePoi {
|
|
};
|
|
// Paper start - optimise POI access
|
|
java.util.List<Pair<Holder<PoiType>, BlockPos>> poiposes = new java.util.ArrayList<>();
|
|
- io.papermc.paper.util.PoiAccess.findNearestPoiPositions(poiManager, poiPredicate, predicate2, entity.blockPosition(), 48, 48*48, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes);
|
|
+ io.papermc.paper.util.PoiAccess.findNearestPoiPositions(poiManager, poiPredicate, predicate2, entity.blockPosition(), world.purpurConfig.villagerAcquirePoiSearchRadius, world.purpurConfig.villagerAcquirePoiSearchRadius*world.purpurConfig.villagerAcquirePoiSearchRadius, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes);
|
|
Set<Pair<Holder<PoiType>, BlockPos>> set = new java.util.HashSet<>(poiposes);
|
|
// Paper end - optimise POI access
|
|
Path path = findPathToPois(entity, set);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
|
|
index 2ade08d1466660ee1787fa97908002ef56389712..8d4e206aa05b95b7bfec5d23496085cf55a3e1de 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
|
|
@@ -41,17 +41,19 @@ public class HarvestFarmland extends Behavior<Villager> {
|
|
private long nextOkStartTime;
|
|
private int timeWorkedSoFar;
|
|
private final List<BlockPos> validFarmlandAroundVillager = Lists.newArrayList();
|
|
+ private boolean clericWartFarmer = false; // Purpur
|
|
|
|
public HarvestFarmland() {
|
|
super(ImmutableMap.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT, MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT, MemoryModuleType.SECONDARY_JOB_SITE, MemoryStatus.VALUE_PRESENT));
|
|
}
|
|
|
|
protected boolean checkExtraStartConditions(ServerLevel world, Villager entity) {
|
|
- if (!world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
|
+ if (!world.purpurConfig.villagerBypassMobGriefing && !world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur
|
|
return false;
|
|
- } else if (entity.getVillagerData().getProfession() != VillagerProfession.FARMER) {
|
|
+ } else if (entity.getVillagerData().getProfession() != VillagerProfession.FARMER && !(world.purpurConfig.villagerClericsFarmWarts && entity.getVillagerData().getProfession() == VillagerProfession.CLERIC)) { // Purpur
|
|
return false;
|
|
} else {
|
|
+ if (!this.clericWartFarmer && entity.getVillagerData().getProfession() == VillagerProfession.CLERIC) this.clericWartFarmer = true; // Purpur
|
|
BlockPos.MutableBlockPos blockposition_mutableblockposition = entity.blockPosition().mutable();
|
|
|
|
this.validFarmlandAroundVillager.clear();
|
|
@@ -82,6 +84,7 @@ public class HarvestFarmland extends Behavior<Villager> {
|
|
Block block = iblockdata.getBlock();
|
|
Block block1 = world.getBlockState(pos.below()).getBlock();
|
|
|
|
+ if (this.clericWartFarmer) return block == Blocks.NETHER_WART && iblockdata.getValue(net.minecraft.world.level.block.NetherWartBlock.AGE) == 3 || iblockdata.isAir() && block1 == Blocks.SOUL_SAND; // Purpur
|
|
return block instanceof CropBlock && ((CropBlock) block).isMaxAge(iblockdata) || iblockdata.isAir() && block1 instanceof FarmBlock;
|
|
}
|
|
|
|
@@ -107,20 +110,20 @@ public class HarvestFarmland extends Behavior<Villager> {
|
|
Block block = iblockdata.getBlock();
|
|
Block block1 = world.getBlockState(this.aboveFarmlandPos.below()).getBlock();
|
|
|
|
- if (block instanceof CropBlock && ((CropBlock) block).isMaxAge(iblockdata)) {
|
|
+ if (block instanceof CropBlock && ((CropBlock) block).isMaxAge(iblockdata) && !this.clericWartFarmer || this.clericWartFarmer && block == Blocks.NETHER_WART && iblockdata.getValue(net.minecraft.world.level.block.NetherWartBlock.AGE) == 3) { // Purpur
|
|
if (CraftEventFactory.callEntityChangeBlockEvent(entity, this.aboveFarmlandPos, iblockdata.getFluidState().createLegacyBlock())) { // CraftBukkit // Paper - fix wrong block state
|
|
world.destroyBlock(this.aboveFarmlandPos, true, entity);
|
|
} // CraftBukkit
|
|
}
|
|
|
|
- if (iblockdata.isAir() && block1 instanceof FarmBlock && entity.hasFarmSeeds()) {
|
|
+ if (iblockdata.isAir() && (block1 instanceof FarmBlock && !this.clericWartFarmer || this.clericWartFarmer && block1 == Blocks.SOUL_SAND) && entity.hasFarmSeeds()) { // Purpur
|
|
SimpleContainer inventorysubcontainer = entity.getInventory();
|
|
|
|
for (int j = 0; j < inventorysubcontainer.getContainerSize(); ++j) {
|
|
ItemStack itemstack = inventorysubcontainer.getItem(j);
|
|
boolean flag = false;
|
|
|
|
- if (!itemstack.isEmpty() && itemstack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS)) {
|
|
+ if (!itemstack.isEmpty() && (itemstack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS) || this.clericWartFarmer && itemstack.getItem() == net.minecraft.world.item.Items.NETHER_WART)) {
|
|
Item item = itemstack.getItem();
|
|
|
|
if (item instanceof BlockItem) {
|
|
@@ -136,7 +139,7 @@ public class HarvestFarmland extends Behavior<Villager> {
|
|
}
|
|
|
|
if (flag) {
|
|
- world.playSound((Player) null, (double) this.aboveFarmlandPos.getX(), (double) this.aboveFarmlandPos.getY(), (double) this.aboveFarmlandPos.getZ(), SoundEvents.CROP_PLANTED, SoundSource.BLOCKS, 1.0F, 1.0F);
|
|
+ world.playSound((Player) null, (double) this.aboveFarmlandPos.getX(), (double) this.aboveFarmlandPos.getY(), (double) this.aboveFarmlandPos.getZ(), this.clericWartFarmer ? SoundEvents.NETHER_WART_PLANTED : SoundEvents.CROP_PLANTED, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur
|
|
itemstack.shrink(1);
|
|
if (itemstack.isEmpty()) {
|
|
inventorysubcontainer.setItem(j, ItemStack.EMPTY);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java b/src/main/java/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java
|
|
index 3513b15f6622bfc134ecfcd9129f81a8acc2c601..6e70579a58a1bf906b176b81713e55318199cef6 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java
|
|
@@ -57,7 +57,7 @@ public class InteractWithDoor {
|
|
|
|
if (iblockdata.is(BlockTags.MOB_INTERACTABLE_DOORS, (blockbase_blockdata) -> {
|
|
return blockbase_blockdata.getBlock() instanceof DoorBlock;
|
|
- })) {
|
|
+ }) && !DoorBlock.requiresRedstone(entityliving.level(), iblockdata, blockposition)) { // Purpur
|
|
DoorBlock blockdoor = (DoorBlock) iblockdata.getBlock();
|
|
|
|
if (!blockdoor.isOpen(iblockdata)) {
|
|
@@ -79,7 +79,7 @@ public class InteractWithDoor {
|
|
|
|
if (iblockdata1.is(BlockTags.MOB_INTERACTABLE_DOORS, (blockbase_blockdata) -> {
|
|
return blockbase_blockdata.getBlock() instanceof DoorBlock;
|
|
- })) {
|
|
+ }) && !DoorBlock.requiresRedstone(entityliving.level(), iblockdata, blockposition1)) { // Purpur
|
|
DoorBlock blockdoor1 = (DoorBlock) iblockdata1.getBlock();
|
|
|
|
if (!blockdoor1.isOpen(iblockdata1)) {
|
|
@@ -122,7 +122,7 @@ public class InteractWithDoor {
|
|
|
|
if (!iblockdata.is(BlockTags.MOB_INTERACTABLE_DOORS, (blockbase_blockdata) -> {
|
|
return blockbase_blockdata.getBlock() instanceof DoorBlock;
|
|
- })) {
|
|
+ }) || DoorBlock.requiresRedstone(entity.level(), iblockdata, blockposition)) { // Purpur
|
|
iterator.remove();
|
|
} else {
|
|
DoorBlock blockdoor = (DoorBlock) iblockdata.getBlock();
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java b/src/main/java/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java
|
|
index 18dad0825616c4167a0a7555689ee64910a87e09..6945992491027d43eca4f1ca697ad45ce06ded55 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java
|
|
@@ -46,6 +46,7 @@ public class ShowTradesToPlayer extends Behavior<Villager> {
|
|
|
|
@Override
|
|
public boolean canStillUse(ServerLevel world, Villager entity, long time) {
|
|
+ if (!entity.level().purpurConfig.villagerDisplayTradeItem) return false; // Purpur
|
|
return this.checkExtraStartConditions(world, entity)
|
|
&& this.lookTime > 0
|
|
&& entity.getBrain().getMemory(MemoryModuleType.INTERACTION_TARGET).isPresent();
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java b/src/main/java/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java
|
|
index 8508ac7de8cda3127b73e11ff4aee62502e65ead..b1544e028d5a9b84b944e1fb5a12bb163067fb54 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java
|
|
@@ -59,6 +59,12 @@ public class TradeWithVillager extends Behavior<Villager> {
|
|
throwHalfStack(entity, ImmutableSet.of(Items.WHEAT), villager);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ if (world.purpurConfig.villagerClericsFarmWarts && world.purpurConfig.villagerClericFarmersThrowWarts && entity.getVillagerData().getProfession() == VillagerProfession.CLERIC && entity.getInventory().countItem(Items.NETHER_WART) > Items.NETHER_WART.getDefaultMaxStackSize() / 2) {
|
|
+ throwHalfStack(entity, ImmutableSet.of(Items.NETHER_WART), villager);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
if (!this.trades.isEmpty() && entity.getInventory().hasAnyOf(this.trades)) {
|
|
throwHalfStack(entity, this.trades, villager);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java
|
|
index bb65d46967cb04f611b3c9c97d5732cfb21ede9b..7f4156e4690bbd57f9e9141f008851062cae733d 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java
|
|
@@ -52,8 +52,13 @@ public class VillagerGoalPackages {
|
|
}
|
|
|
|
public static ImmutableList<Pair<Integer, ? extends BehaviorControl<? super Villager>>> getWorkPackage(VillagerProfession profession, float speed) {
|
|
+ // Purpur start
|
|
+ return getWorkPackage(profession, speed, false);
|
|
+ }
|
|
+ public static ImmutableList<Pair<Integer, ? extends BehaviorControl<? super Villager>>> getWorkPackage(VillagerProfession profession, float speed, boolean clericsFarmWarts) {
|
|
+ // Purpur end
|
|
WorkAtPoi workAtPoi;
|
|
- if (profession == VillagerProfession.FARMER) {
|
|
+ if (profession == VillagerProfession.FARMER || (clericsFarmWarts && profession == VillagerProfession.CLERIC)) { // Purpur
|
|
workAtPoi = new WorkAtComposter();
|
|
} else {
|
|
workAtPoi = new WorkAtPoi();
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java
|
|
index 0a608418f87b71d5d71706712e1f82da0d7e4d34..03e7ca83e4c28dfaa5b52bcb100bd542db105970 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java
|
|
@@ -125,8 +125,10 @@ public class VillagerMakeLove extends Behavior<Villager> {
|
|
return Optional.empty();
|
|
}
|
|
// Move age setting down
|
|
- parent.setAge(6000);
|
|
- partner.setAge(6000);
|
|
+ // Purpur start
|
|
+ parent.setAge(world.purpurConfig.villagerBreedingTicks);
|
|
+ partner.setAge(world.purpurConfig.villagerBreedingTicks);
|
|
+ // Purpur end
|
|
world.addFreshEntityWithPassengers(entityvillager2, CreatureSpawnEvent.SpawnReason.BREEDING);
|
|
// CraftBukkit end
|
|
world.broadcastEntityEvent(entityvillager2, (byte) 12);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java b/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java
|
|
index c8fd5696de7c3623cdb4f498190a5c2708cf843e..e403d9dfeeaa3dcf53be790d761e7e922419efb0 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java
|
|
@@ -29,6 +29,20 @@ public class MoveControl implements Control {
|
|
this.mob = entity;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public void setSpeedModifier(double speed) {
|
|
+ this.speedModifier = speed;
|
|
+ }
|
|
+
|
|
+ public void setForward(float forward) {
|
|
+ this.strafeForwards = forward;
|
|
+ }
|
|
+
|
|
+ public void setStrafe(float strafe) {
|
|
+ this.strafeRight = strafe;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public boolean hasWanted() {
|
|
return this.operation == MoveControl.Operation.MOVE_TO;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java b/src/main/java/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java
|
|
index fbfc2f2515ad709b2c1212aef9521e795547d66b..e77bd11af62682d5eca41f6c9e1aed30eb6879ce 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java
|
|
@@ -3,7 +3,7 @@ package net.minecraft.world.entity.ai.control;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.entity.Mob;
|
|
|
|
-public class SmoothSwimmingLookControl extends LookControl {
|
|
+public class SmoothSwimmingLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur
|
|
private final int maxYRotFromCenter;
|
|
private static final int HEAD_TILT_X = 10;
|
|
private static final int HEAD_TILT_Y = 20;
|
|
@@ -14,7 +14,7 @@ public class SmoothSwimmingLookControl extends LookControl {
|
|
}
|
|
|
|
@Override
|
|
- public void tick() {
|
|
+ public void vanillaTick() { // Purpur
|
|
if (this.lookAtCooldown > 0) {
|
|
this.lookAtCooldown--;
|
|
this.getYRotD().ifPresent(yaw -> this.mob.yHeadRot = this.rotateTowards(this.mob.yHeadRot, yaw + 20.0F, this.yMaxRotSpeed));
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
|
|
index 7324da6b7dd2623ce394e3827ff77ef684a3b98b..4b7cfca51ced0f781561ecd68484de4adb23e082 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
|
|
@@ -33,7 +33,7 @@ public class BreakDoorGoal extends DoorInteractGoal {
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
- return !super.canUse() ? false : (!getServerLevel((Entity) this.mob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? false : this.isValidDifficulty(this.mob.level().getDifficulty()) && !this.isOpen());
|
|
+ return !super.canUse() ? false : ((!this.mob.level().purpurConfig.zombieBypassMobGriefing && !getServerLevel((Entity) this.mob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) ? false : this.isValidDifficulty(this.mob.level().getDifficulty()) && !this.isOpen()); // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
|
|
index 32bb591371fe78ba10a2bc52389ef33978cbc0eb..f3697510974be0c3cfdb0e2179d89c8109152829 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
|
|
@@ -74,7 +74,7 @@ public class EatBlockGoal extends Goal {
|
|
|
|
final BlockState blockState = this.level.getBlockState(blockposition); // Paper - fix wrong block state
|
|
if (EatBlockGoal.IS_TALL_GRASS.test(blockState)) { // Paper - fix wrong block state
|
|
- if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - fix wrong block state
|
|
+ if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).purpurConfig.sheepBypassMobGriefing && !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - fix wrong block state // Purpur
|
|
this.level.destroyBlock(blockposition, false);
|
|
}
|
|
|
|
@@ -83,7 +83,7 @@ public class EatBlockGoal extends Goal {
|
|
BlockPos blockposition1 = blockposition.below();
|
|
|
|
if (this.level.getBlockState(blockposition1).is(Blocks.GRASS_BLOCK)) {
|
|
- if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - Fix wrong block state
|
|
+ if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).purpurConfig.sheepBypassMobGriefing && !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - Fix wrong block state // Purpur
|
|
this.level.levelEvent(2001, blockposition1, Block.getId(Blocks.GRASS_BLOCK.defaultBlockState()));
|
|
this.level.setBlock(blockposition1, Blocks.DIRT.defaultBlockState(), 2);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
|
index 29ae74339a4831ccef3d01e8054931715ba192ad..74c5914bc51cff128d4b86853316e5e51e02b416 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
|
@@ -82,8 +82,8 @@ public class GoalSelector {
|
|
}
|
|
|
|
public void tick() {
|
|
- ProfilerFiller profilerFiller = Profiler.get();
|
|
- profilerFiller.push("goalCleanup");
|
|
+ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur
|
|
+ //profilerFiller.push("goalCleanup"); // Purpur
|
|
|
|
for (WrappedGoal wrappedGoal : this.availableGoals) {
|
|
if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams
|
|
@@ -92,8 +92,8 @@ public class GoalSelector {
|
|
}
|
|
|
|
this.lockedFlags.entrySet().removeIf(entry -> !entry.getValue().isRunning());
|
|
- profilerFiller.pop();
|
|
- profilerFiller.push("goalUpdate");
|
|
+ //profilerFiller.pop(); // Purpur
|
|
+ //profilerFiller.push("goalUpdate"); // Purpur
|
|
|
|
for (WrappedGoal wrappedGoal2 : this.availableGoals) {
|
|
// Paper start
|
|
@@ -113,13 +113,13 @@ public class GoalSelector {
|
|
}
|
|
}
|
|
|
|
- profilerFiller.pop();
|
|
+ //profilerFiller.pop(); // Purpur
|
|
this.tickRunningGoals(true);
|
|
}
|
|
|
|
public void tickRunningGoals(boolean tickAll) {
|
|
- ProfilerFiller profilerFiller = Profiler.get();
|
|
- profilerFiller.push("goalTick");
|
|
+ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur
|
|
+ //profilerFiller.push("goalTick"); // Purpur
|
|
|
|
for (WrappedGoal wrappedGoal : this.availableGoals) {
|
|
if (wrappedGoal.isRunning() && (tickAll || wrappedGoal.requiresUpdateEveryTick())) {
|
|
@@ -127,7 +127,7 @@ public class GoalSelector {
|
|
}
|
|
}
|
|
|
|
- profilerFiller.pop();
|
|
+ //profilerFiller.pop(); // Purpur
|
|
}
|
|
|
|
public Set<WrappedGoal> getAvailableGoals() {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java
|
|
index df695b444fa2a993d381e2f197182c3e91a68502..0f4f546cd0eda4bd82b47446ae23ac32da8a9556 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java
|
|
@@ -22,6 +22,7 @@ public class LlamaFollowCaravanGoal extends Goal {
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
+ if (!this.llama.level().purpurConfig.llamaJoinCaravans || !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.0, 4.0, 9.0), entity -> {
|
|
EntityType<?> entityType = entity.getType();
|
|
@@ -71,6 +72,7 @@ public class LlamaFollowCaravanGoal extends Goal {
|
|
|
|
@Override
|
|
public boolean canContinueToUse() {
|
|
+ if (!this.llama.shouldJoinCaravan) return false; // Purpur
|
|
if (this.llama.inCaravan() && this.llama.getCaravanHead().isAlive() && this.firstIsLeashed(this.llama, 0)) {
|
|
double d = this.llama.distanceToSqr(this.llama.getCaravanHead());
|
|
if (d > 676.0) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java
|
|
index 515c1f671cb2c3a7cc23053aedf404bbbe77af3e..42a1e5b9c08a9245dd0ce6d4025e3bb5d60feb62 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java
|
|
@@ -116,9 +116,9 @@ public class RangedBowAttackGoal<T extends Monster & RangedAttackMob> extends Go
|
|
}
|
|
|
|
this.mob.lookAt(livingEntity, 30.0F, 30.0F);
|
|
- } else {
|
|
+ } //else { // Purpur - fix MC-121706
|
|
this.mob.getLookControl().setLookAt(livingEntity, 30.0F, 30.0F);
|
|
- }
|
|
+ //} // Purpur
|
|
|
|
if (this.mob.isUsingItem()) {
|
|
if (!bl && this.seeTime < -60) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
|
|
index 9d245d08be61d7edee9138196ae3bf52023e3993..d002acdac893e2744cde5f1145d29ac2c8ff6959 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
|
|
@@ -41,7 +41,7 @@ public class RemoveBlockGoal extends MoveToBlockGoal {
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
- if (!getServerLevel((Entity) this.removerMob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
|
+ if (!getServerLevel((Entity) this.removerMob).purpurConfig.zombieBypassMobGriefing && !getServerLevel((Entity) this.removerMob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur
|
|
return false;
|
|
} else if (this.nextStartTick > 0) {
|
|
--this.nextStartTick;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java
|
|
index b0944fa1f3849dd24cd010fa0a6638f5fd7179d1..d409ae987088df3d47192128401d7491aaabc87c 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java
|
|
@@ -67,7 +67,7 @@ public class RunAroundLikeCrazyGoal extends Goal {
|
|
int i = this.horse.getTemper();
|
|
int j = this.horse.getMaxTemper();
|
|
|
|
- if (j > 0 && this.horse.getRandom().nextInt(j) < i && !CraftEventFactory.callEntityTameEvent(this.horse, ((CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled()) { // CraftBukkit - fire EntityTameEvent
|
|
+ if ((this.horse.level().purpurConfig.alwaysTameInCreative && entityhuman.hasInfiniteMaterials()) || (j > 0 && this.horse.getRandom().nextInt(j) < i && !CraftEventFactory.callEntityTameEvent(this.horse, ((CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled())) { // CraftBukkit - fire EntityTameEvent // Purpur
|
|
this.horse.tameWithName(entityhuman);
|
|
return;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java
|
|
index 137ec75ee803789deb7b1ca93dd9369c9af362b9..ca95d25af3e9a0536868b0c7fd8e7d2ff1154ee3 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java
|
|
@@ -54,6 +54,14 @@ public class SwellGoal extends Goal {
|
|
this.creeper.setSwellDir(-1);
|
|
} else {
|
|
this.creeper.setSwellDir(1);
|
|
+ // Purpur start
|
|
+ if (this.creeper.level().purpurConfig.creeperEncircleTarget) {
|
|
+ net.minecraft.world.phys.Vec3 relative = this.creeper.position().subtract(this.target.position());
|
|
+ relative = relative.yRot((float) Math.PI / 3).normalize().multiply(2, 2, 2);
|
|
+ net.minecraft.world.phys.Vec3 destination = this.target.position().add(relative);
|
|
+ this.creeper.getNavigation().moveTo(destination.x, destination.y, destination.z, 1);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java
|
|
index 84ab90dd1fe693da71732533ccff940c1007e1b6..179fdf7b7f68db610925a9d7b88879289b1b98b8 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
|
|
@@ -67,7 +67,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/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
|
index 48c0de870a5bbf647309e69361dfb10ab56c65ab..a5289b6c453c24cb7b8b3a301b72c3adf92c1d13 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
|
@@ -188,13 +188,13 @@ public abstract class PathNavigation {
|
|
}
|
|
}
|
|
// Paper end - EntityPathfindEvent
|
|
- ProfilerFiller profilerFiller = Profiler.get();
|
|
- profilerFiller.push("pathfind");
|
|
+ //ProfilerFiller profilerFiller = Profiler.get();
|
|
+ //profilerFiller.push("pathfind"); // Purpur
|
|
BlockPos blockPos = useHeadPos ? this.mob.blockPosition().above() : this.mob.blockPosition();
|
|
int i = (int)(followRange + (float)range);
|
|
PathNavigationRegion pathNavigationRegion = new PathNavigationRegion(this.level, blockPos.offset(-i, -i, -i), blockPos.offset(i, i, i));
|
|
Path path = this.pathFinder.findPath(pathNavigationRegion, this.mob, positions, followRange, distance, this.maxVisitedNodesMultiplier);
|
|
- profilerFiller.pop();
|
|
+ //profilerFiller.pop(); // Purpur
|
|
if (path != null && path.getTarget() != null) {
|
|
this.targetPos = path.getTarget();
|
|
this.reachRange = distance;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
|
index 92731b6b593289e9f583c9b705b219e81fcd8e73..9104d7010bda6f9f73b478c11490ef9c53f76da2 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
|
@@ -56,7 +56,7 @@ public class NearestBedSensor extends Sensor<Mob> {
|
|
// Paper start - optimise POI access
|
|
java.util.List<Pair<Holder<PoiType>, BlockPos>> poiposes = new java.util.ArrayList<>();
|
|
// don't ask me why it's unbounded. ask mojang.
|
|
- io.papermc.paper.util.PoiAccess.findAnyPoiPositions(poiManager, type -> type.is(PoiTypes.HOME), predicate, entity.blockPosition(), 48, PoiManager.Occupancy.ANY, false, Integer.MAX_VALUE, poiposes);
|
|
+ io.papermc.paper.util.PoiAccess.findAnyPoiPositions(poiManager, type -> type.is(PoiTypes.HOME), predicate, entity.blockPosition(), world.purpurConfig.villagerNearestBedSensorSearchRadius, PoiManager.Occupancy.ANY, false, Integer.MAX_VALUE, poiposes); // Purpur
|
|
Path path = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes));
|
|
// Paper end - optimise POI access
|
|
if (path != null && path.canReach()) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java
|
|
index a0e0692d17760f440fe81d52887284c787e562db..ab9bebc07b5228dbc0d3ba4b0f7d1bbe41814c9b 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java
|
|
@@ -22,6 +22,13 @@ public class SecondaryPoiSensor extends Sensor<Villager> {
|
|
|
|
@Override
|
|
protected void doTick(ServerLevel world, Villager entity) {
|
|
+ // Purpur start - make sure clerics don't wander to soul sand when the option is off
|
|
+ Brain<?> brain = entity.getBrain();
|
|
+ if (!world.purpurConfig.villagerClericsFarmWarts && entity.getVillagerData().getProfession() == net.minecraft.world.entity.npc.VillagerProfession.CLERIC) {
|
|
+ brain.eraseMemory(MemoryModuleType.SECONDARY_JOB_SITE);
|
|
+ return;
|
|
+ }
|
|
+ // Purpur end
|
|
ResourceKey<Level> resourceKey = world.dimension();
|
|
BlockPos blockPos = entity.blockPosition();
|
|
List<GlobalPos> list = Lists.newArrayList();
|
|
@@ -38,7 +45,7 @@ public class SecondaryPoiSensor extends Sensor<Villager> {
|
|
}
|
|
}
|
|
|
|
- Brain<?> brain = entity.getBrain();
|
|
+ //Brain<?> brain = entity.getBrain(); // Purpur - moved up
|
|
if (!list.isEmpty()) {
|
|
brain.setMemory(MemoryModuleType.SECONDARY_JOB_SITE, list);
|
|
} else {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java
|
|
index 116b1e251ffe68bae5c404d0823c2bc7c1afddf6..8f5a5db1a07fa6a95ecfacaab2f9de609202faf4 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java
|
|
@@ -28,10 +28,10 @@ public class Sensing {
|
|
} else if (this.unseen.contains(i)) {
|
|
return false;
|
|
} else {
|
|
- ProfilerFiller profilerFiller = Profiler.get();
|
|
- profilerFiller.push("hasLineOfSight");
|
|
+ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur
|
|
+ //profilerFiller.push("hasLineOfSight"); // Purpur
|
|
boolean bl = this.mob.hasLineOfSight(entity);
|
|
- profilerFiller.pop();
|
|
+ //profilerFiller.pop(); // Purpur
|
|
if (bl) {
|
|
this.seen.add(i);
|
|
} else {
|
|
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 52982c1e6a4da36392569c791853279f5f9ac31a..b3d4c61b1769b6fcc98b7af854f774d24bf39d98 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
|
|
@@ -64,6 +64,10 @@ public class TargetingConditions {
|
|
return false;
|
|
} else if (this.selector != null && !this.selector.test(target, world)) {
|
|
return false;
|
|
+ // Purpur start
|
|
+ } else if (!world.purpurConfig.idleTimeoutTargetPlayer && target instanceof net.minecraft.server.level.ServerPlayer player && player.isAfk()) {
|
|
+ return false;
|
|
+ // Purpur end
|
|
} else {
|
|
if (tester == null) {
|
|
if (this.isCombat && (!target.canBeSeenAsEnemy() || world.getDifficulty() == Difficulty.PEACEFUL)) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java
|
|
index 60c2868f255d372226e0c1389caaa5477bbef41e..2d4fe19da8d53d47df36399531e78da2c961aecd 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java
|
|
@@ -47,12 +47,59 @@ public class Bat extends AmbientCreature {
|
|
|
|
public Bat(EntityType<? extends Bat> type, Level world) {
|
|
super(type, world);
|
|
+ this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.075F); // Purpur
|
|
if (!world.isClientSide) {
|
|
this.setResting(true);
|
|
}
|
|
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean shouldSendAttribute(net.minecraft.world.entity.ai.attributes.Attribute attribute) { return attribute != Attributes.FLYING_SPEED.value(); } // Fixes log spam on clients
|
|
+
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.batRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.batRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.batControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double getMaxY() {
|
|
+ return level().purpurConfig.batMaxY;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onMount(Player rider) {
|
|
+ super.onMount(rider);
|
|
+ if (isResting()) {
|
|
+ setResting(false);
|
|
+ level().levelEvent(null, 1025, new BlockPos(this).above(), 0);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void travel(Vec3 vec3) {
|
|
+ super.travel(vec3);
|
|
+ if (getRider() != null && this.isControllable() && !onGround) {
|
|
+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2;
|
|
+ setSpeed(speed);
|
|
+ Vec3 mot = getDeltaMovement();
|
|
+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.25, speed));
|
|
+ setDeltaMovement(mot.scale(0.9D));
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public boolean isFlapping() {
|
|
return !this.isResting() && (float) this.tickCount % 10.0F == 0.0F;
|
|
@@ -102,7 +149,7 @@ public class Bat extends AmbientCreature {
|
|
protected void pushEntities() {}
|
|
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0D);
|
|
+ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur
|
|
}
|
|
|
|
public boolean isResting() {
|
|
@@ -135,6 +182,14 @@ public class Bat extends AmbientCreature {
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
+ // Purpur start
|
|
+ if (getRider() != null && this.isControllable()) {
|
|
+ Vec3 mot = getDeltaMovement();
|
|
+ setDeltaMovement(mot.x(), mot.y() + (getVerticalMot() > 0 ? 0.07D : 0.0D), mot.z());
|
|
+ return;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
super.customServerAiStep(world);
|
|
BlockPos blockposition = this.blockPosition();
|
|
BlockPos blockposition1 = blockposition.above();
|
|
@@ -213,6 +268,29 @@ public class Bat extends AmbientCreature {
|
|
}
|
|
}
|
|
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.batMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.batScale);
|
|
+ this.getAttribute(Attributes.FOLLOW_RANGE).setBaseValue(this.level().purpurConfig.batFollowRange);
|
|
+ this.getAttribute(Attributes.KNOCKBACK_RESISTANCE).setBaseValue(this.level().purpurConfig.batKnockbackResistance);
|
|
+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.batMovementSpeed);
|
|
+ this.getAttribute(Attributes.FLYING_SPEED).setBaseValue(this.level().purpurConfig.batFlyingSpeed);
|
|
+ this.getAttribute(Attributes.ARMOR).setBaseValue(this.level().purpurConfig.batArmor);
|
|
+ this.getAttribute(Attributes.ARMOR_TOUGHNESS).setBaseValue(this.level().purpurConfig.batArmorToughness);
|
|
+ this.getAttribute(Attributes.ATTACK_KNOCKBACK).setBaseValue(this.level().purpurConfig.batAttackKnockback);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.batTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.batAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
public void readAdditionalSaveData(CompoundTag nbt) {
|
|
super.readAdditionalSaveData(nbt);
|
|
@@ -232,7 +310,7 @@ public class Bat extends AmbientCreature {
|
|
int i = world.getMaxLocalRawBrightness(pos);
|
|
byte b0 = 4;
|
|
|
|
- if (Bat.isHalloween()) {
|
|
+ if (Bat.isHalloweenSeason(world.getMinecraftWorld())) { // Purpur
|
|
b0 = 7;
|
|
} else if (random.nextBoolean()) {
|
|
return false;
|
|
@@ -242,6 +320,11 @@ public class Bat extends AmbientCreature {
|
|
}
|
|
}
|
|
|
|
+ // Pufferfish start - only check for spooky season once an hour
|
|
+ private static boolean isSpookySeason = false;
|
|
+ private static final int ONE_HOUR = 20 * 60 * 60;
|
|
+ private static int lastSpookyCheck = -ONE_HOUR;
|
|
+ public static boolean isHalloweenSeason(Level level) { return level.purpurConfig.forceHalloweenSeason || isHalloween(); } // Purpur
|
|
private static boolean isHalloween() {
|
|
LocalDate localdate = LocalDate.now();
|
|
int i = localdate.get(ChronoField.DAY_OF_MONTH);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java
|
|
index 9aedc62b1766f6a7db4da7eba55167d21d698791..9708ed3e00059fdf5d1d60e0c607d0ab153d1d3f 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java
|
|
@@ -87,6 +87,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
|
|
@Override
|
|
protected void registerGoals() {
|
|
super.registerGoals();
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(0, new PanicGoal(this, 1.25));
|
|
this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 1.6, 1.4, EntitySelector.NO_SPECTATORS::test));
|
|
this.goalSelector.addGoal(4, new AbstractFish.FishSwimGoal(this));
|
|
@@ -100,7 +101,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
|
|
@Override
|
|
public void travel(Vec3 movementInput) {
|
|
if (this.isControlledByLocalInstance() && this.isInWater()) {
|
|
- this.moveRelative(0.01F, movementInput);
|
|
+ this.moveRelative(getRider() != null ? getSpeed() : 0.01F, movementInput); // Purpur
|
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
|
this.setDeltaMovement(this.getDeltaMovement().scale(0.9));
|
|
if (this.getTarget() == null) {
|
|
@@ -161,7 +162,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
|
|
protected void playStepSound(BlockPos pos, BlockState state) {
|
|
}
|
|
|
|
- static class FishMoveControl extends MoveControl {
|
|
+ static class FishMoveControl extends org.purpurmc.purpur.controller.WaterMoveControllerWASD { // Purpur
|
|
private final AbstractFish fish;
|
|
|
|
FishMoveControl(AbstractFish owner) {
|
|
@@ -169,14 +170,22 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
|
|
this.fish = owner;
|
|
}
|
|
|
|
+ // Purpur start
|
|
@Override
|
|
- public void tick() {
|
|
+ public void purpurTick(Player rider) {
|
|
+ super.purpurTick(rider);
|
|
+ fish.setDeltaMovement(fish.getDeltaMovement().add(0.0D, 0.005D, 0.0D));
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void vanillaTick() { // Purpur
|
|
if (this.fish.isEyeInFluid(FluidTags.WATER)) {
|
|
this.fish.setDeltaMovement(this.fish.getDeltaMovement().add(0.0, 0.005, 0.0));
|
|
}
|
|
|
|
if (this.operation == MoveControl.Operation.MOVE_TO && !this.fish.getNavigation().isDone()) {
|
|
- float f = (float)(this.speedModifier * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED));
|
|
+ float f = (float)(this.getSpeedModifier() * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur
|
|
this.fish.setSpeed(Mth.lerp(0.125F, this.fish.getSpeed(), f));
|
|
double d = this.wantedX - this.fish.getX();
|
|
double e = this.wantedY - this.fish.getY();
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Animal.java b/src/main/java/net/minecraft/world/entity/animal/Animal.java
|
|
index 5677dc97ed83652f261100cf391883cfac7d16fe..9987d28ea145f6d0126cb4ea22001e0922fb51bd 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Animal.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Animal.java
|
|
@@ -49,6 +49,7 @@ public abstract class Animal extends AgeableMob {
|
|
@Nullable
|
|
public UUID loveCause;
|
|
public ItemStack breedItem; // CraftBukkit - Add breedItem variable
|
|
+ public abstract int getPurpurBreedTime(); // Purpur
|
|
|
|
protected Animal(EntityType<? extends Animal> type, Level world) {
|
|
super(type, world);
|
|
@@ -157,7 +158,7 @@ public abstract class Animal extends AgeableMob {
|
|
if (this.isFood(itemstack)) {
|
|
int i = this.getAge();
|
|
|
|
- if (!this.level().isClientSide && i == 0 && this.canFallInLove()) {
|
|
+ if (!this.level().isClientSide && i == 0 && this.canFallInLove() && (this.level().purpurConfig.animalBreedingCooldownSeconds <= 0 || !this.level().hasBreedingCooldown(player.getUUID(), this.getClass()))) { // Purpur
|
|
final ItemStack breedCopy = itemstack.copy(); // Paper - Fix EntityBreedEvent copying
|
|
this.usePlayerItem(player, hand, itemstack);
|
|
this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying
|
|
@@ -261,12 +262,20 @@ public abstract class Animal extends AgeableMob {
|
|
AgeableMob entityageable = this.getBreedOffspring(world, other);
|
|
|
|
if (entityageable != null) {
|
|
- entityageable.setBaby(true);
|
|
- entityageable.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F);
|
|
- // CraftBukkit start - call EntityBreedEvent
|
|
+ // Purpur start
|
|
ServerPlayer breeder = Optional.ofNullable(this.getLoveCause()).or(() -> {
|
|
return Optional.ofNullable(other.getLoveCause());
|
|
}).orElse(null);
|
|
+ if (breeder != null && world.purpurConfig.animalBreedingCooldownSeconds > 0) {
|
|
+ if (world.hasBreedingCooldown(breeder.getUUID(), this.getClass())) {
|
|
+ return;
|
|
+ }
|
|
+ world.addBreedingCooldown(breeder.getUUID(), this.getClass());
|
|
+ }
|
|
+ entityageable.setBaby(true);
|
|
+ entityageable.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F);
|
|
+ // CraftBukkit start - call EntityBreedEvent
|
|
+ // Purpur end
|
|
int experience = this.getRandom().nextInt(7) + 1;
|
|
EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(entityageable, this, other, breeder, this.breedItem, experience);
|
|
if (entityBreedEvent.isCancelled()) {
|
|
@@ -294,8 +303,10 @@ public abstract class Animal extends AgeableMob {
|
|
entityplayer.awardStat(Stats.ANIMALS_BRED);
|
|
CriteriaTriggers.BRED_ANIMALS.trigger(entityplayer, this, entityanimal, entityageable);
|
|
} // Paper
|
|
- this.setAge(6000);
|
|
- entityanimal.setAge(6000);
|
|
+ // Purpur start
|
|
+ this.setAge(this.getPurpurBreedTime());
|
|
+ entityanimal.setAge(entityanimal.getPurpurBreedTime());
|
|
+ // Purpur end
|
|
this.resetLove();
|
|
entityanimal.resetLove();
|
|
worldserver.broadcastEntityEvent(this, (byte) 18);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
|
index 42276acfeadec6e7aa9a91d3f446f4fedb04829d..dc8df0912c1d18176e18a8f4dc43c4f60f81b659 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
|
@@ -150,6 +150,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
|
public Bee(EntityType<? extends Bee> type, Level world) {
|
|
super(type, world);
|
|
this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(this.random, 20, 60);
|
|
+ final org.purpurmc.purpur.controller.FlyingMoveControllerWASD flyingController = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this, 0.25F, 1.0F, false); // Purpur
|
|
// Paper start - Fix MC-167279
|
|
class BeeFlyingMoveControl extends FlyingMoveControl {
|
|
public BeeFlyingMoveControl(final Mob entity, final int maxPitchChange, final boolean noGravity) {
|
|
@@ -158,22 +159,69 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
|
|
|
@Override
|
|
public void tick() {
|
|
+ // Purpur start
|
|
+ if (mob.getRider() != null && mob.isControllable()) {
|
|
+ flyingController.purpurTick(mob.getRider());
|
|
+ return;
|
|
+ }
|
|
+ // Purpur end
|
|
if (this.mob.getY() <= Bee.this.level().getMinY()) {
|
|
this.mob.setNoGravity(false);
|
|
}
|
|
super.tick();
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean hasWanted() {
|
|
+ return mob.getRider() != null || !mob.isControllable() || super.hasWanted();
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
this.moveControl = new BeeFlyingMoveControl(this, 20, true);
|
|
// Paper end - Fix MC-167279
|
|
this.lookControl = new Bee.BeeLookControl(this);
|
|
this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F);
|
|
- this.setPathfindingMalus(PathType.WATER, -1.0F);
|
|
+ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur
|
|
this.setPathfindingMalus(PathType.WATER_BORDER, 16.0F);
|
|
this.setPathfindingMalus(PathType.COCOA, -1.0F);
|
|
this.setPathfindingMalus(PathType.FENCE, -1.0F);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.beeRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.beeRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.beeControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double getMaxY() {
|
|
+ return level().purpurConfig.beeMaxY;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void travel(Vec3 vec3) {
|
|
+ super.travel(vec3);
|
|
+ if (getRider() != null && this.isControllable() && !onGround) {
|
|
+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2;
|
|
+ setSpeed(speed);
|
|
+ Vec3 mot = getDeltaMovement();
|
|
+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, speed, speed));
|
|
+ setDeltaMovement(mot.scale(0.9D));
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
|
super.defineSynchedData(builder);
|
|
@@ -188,6 +236,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
|
|
|
@Override
|
|
protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(0, new Bee.BeeAttackGoal(this, 1.399999976158142D, true));
|
|
this.goalSelector.addGoal(1, new Bee.BeeEnterHiveGoal());
|
|
this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D));
|
|
@@ -207,6 +256,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
|
this.goalSelector.addGoal(7, new Bee.BeeGrowCropGoal());
|
|
this.goalSelector.addGoal(8, new Bee.BeeWanderGoal());
|
|
this.goalSelector.addGoal(9, new FloatGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, (new Bee.BeeHurtByOtherGoal(this)).setAlertOthers(new Class[0]));
|
|
this.targetSelector.addGoal(2, new Bee.BeeBecomeAngryTargetGoal(this));
|
|
this.targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, true));
|
|
@@ -376,7 +426,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
|
}
|
|
|
|
public static boolean isNightOrRaining(Level world) {
|
|
- return world.dimensionType().hasSkyLight() && (world.isNight() || world.isRaining());
|
|
+ return world.dimensionType().hasSkyLight() && ((world.isNight() && !world.purpurConfig.beeCanWorkAtNight) || (world.isRaining() && !world.purpurConfig.beeCanWorkInRain)); // Purpur
|
|
}
|
|
|
|
public void setStayOutOfHiveCountdown(int cannotEnterHiveTicks) {
|
|
@@ -411,6 +461,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
|
this.hurtServer(world, this.damageSources().drown(), 1.0F);
|
|
}
|
|
|
|
+ if (flag && !this.level().purpurConfig.beeDiesAfterSting) setHasStung(false); else // Purpur
|
|
if (flag) {
|
|
++this.timeSinceSting;
|
|
if (this.timeSinceSting % 5 == 0 && this.random.nextInt(Mth.clamp(1200 - this.timeSinceSting, 1, 1200)) == 0) {
|
|
@@ -435,6 +486,27 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
|
return tileentitybeehive != null && tileentitybeehive.isFireNearby();
|
|
}
|
|
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.beeMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.beeScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.beeBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.beeTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.beeAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
public int getRemainingPersistentAngerTime() {
|
|
return (Integer) this.entityData.get(Bee.DATA_REMAINING_ANGER_TIME);
|
|
@@ -701,16 +773,16 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
|
this.hivePos = pos;
|
|
}
|
|
|
|
- private class BeeLookControl extends LookControl {
|
|
+ private class BeeLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur
|
|
|
|
BeeLookControl(final Mob entity) {
|
|
super(entity);
|
|
}
|
|
|
|
@Override
|
|
- public void tick() {
|
|
+ public void vanillaTick() { // Purpur
|
|
if (!Bee.this.isAngry()) {
|
|
- super.tick();
|
|
+ super.vanillaTick(); // Purpur
|
|
}
|
|
}
|
|
|
|
@@ -882,6 +954,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
|
if (optional.isPresent()) {
|
|
Bee.this.savedFlowerPos = (BlockPos) optional.get();
|
|
Bee.this.navigation.moveTo((double) Bee.this.savedFlowerPos.getX() + 0.5D, (double) Bee.this.savedFlowerPos.getY() + 0.5D, (double) Bee.this.savedFlowerPos.getZ() + 0.5D, 1.2000000476837158D);
|
|
+ new org.purpurmc.purpur.event.entity.BeeFoundFlowerEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(Bee.this.level(), Bee.this.savedFlowerPos)).callEvent(); // Purpur
|
|
return true;
|
|
} else {
|
|
Bee.this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(Bee.this.random, 20, 60);
|
|
@@ -925,6 +998,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
|
this.pollinating = false;
|
|
Bee.this.navigation.stop();
|
|
Bee.this.remainingCooldownBeforeLocatingNewFlower = 200;
|
|
+ new org.purpurmc.purpur.event.entity.BeeStopPollinatingEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), Bee.this.savedFlowerPos == null ? null : io.papermc.paper.util.MCUtil.toLocation(Bee.this.level(), Bee.this.savedFlowerPos), Bee.this.hasNectar()).callEvent(); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -974,6 +1048,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
|
this.setWantedPos();
|
|
}
|
|
|
|
+ if (this.successfulPollinatingTicks == 0) new org.purpurmc.purpur.event.entity.BeeStartedPollinatingEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(Bee.this.level(), Bee.this.savedFlowerPos)).callEvent(); // Purpur
|
|
++this.successfulPollinatingTicks;
|
|
if (Bee.this.random.nextFloat() < 0.05F && this.successfulPollinatingTicks > this.lastSoundPlayedTick + 60) {
|
|
this.lastSoundPlayedTick = this.successfulPollinatingTicks;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java
|
|
index 471d5727b964922d8e898be9e1d5c30f9d3bac97..4aad4fdc80070f4000e929fff126714fc67050b0 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Cat.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java
|
|
@@ -100,12 +100,59 @@ public class Cat extends TamableAnimal implements VariantHolder<Holder<CatVarian
|
|
this.reassessTameGoals();
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.catRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.catRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.catControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onMount(Player rider) {
|
|
+ super.onMount(rider);
|
|
+ setInSittingPose(false);
|
|
+ setLying(false);
|
|
+ setRelaxStateOne(false);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.catMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.catScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.catBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.catTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.catAlwaysDropExp;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.temptGoal = new Cat.CatTemptGoal(this, 0.6D, (itemstack) -> {
|
|
return itemstack.is(ItemTags.CAT_FOOD);
|
|
}, true);
|
|
this.goalSelector.addGoal(1, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new TamableAnimal.TamableAnimalPanicGoal(1.5D));
|
|
this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this));
|
|
this.goalSelector.addGoal(3, new Cat.CatRelaxOnOwnerGoal(this));
|
|
@@ -118,6 +165,7 @@ public class Cat extends TamableAnimal implements VariantHolder<Holder<CatVarian
|
|
this.goalSelector.addGoal(10, new BreedGoal(this, 0.8D));
|
|
this.goalSelector.addGoal(11, new WaterAvoidingRandomStrollGoal(this, 0.8D, 1.0000001E-5F));
|
|
this.goalSelector.addGoal(12, new LookAtPlayerGoal(this, Player.class, 10.0F));
|
|
+ this.targetSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Rabbit.class, false, (TargetingConditions.Selector) null));
|
|
this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR));
|
|
}
|
|
@@ -317,6 +365,14 @@ public class Cat extends TamableAnimal implements VariantHolder<Holder<CatVarian
|
|
return Mth.lerp(tickDelta, this.relaxStateOneAmountO, this.relaxStateOneAmount);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public void tame(Player player) {
|
|
+ setCollarColor(level().purpurConfig.catDefaultCollarColor);
|
|
+ super.tame(player);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Nullable
|
|
@Override
|
|
public Cat getBreedOffspring(ServerLevel world, AgeableMob entity) {
|
|
@@ -376,6 +432,7 @@ public class Cat extends TamableAnimal implements VariantHolder<Holder<CatVarian
|
|
|
|
@Override
|
|
public InteractionResult mobInteract(Player player, InteractionHand hand) {
|
|
+ if (getRider() != null) return InteractionResult.PASS; // Purpur
|
|
ItemStack itemstack = player.getItemInHand(hand);
|
|
Item item = itemstack.getItem();
|
|
InteractionResult enuminteractionresult;
|
|
@@ -470,7 +527,7 @@ public class Cat extends TamableAnimal implements VariantHolder<Holder<CatVarian
|
|
}
|
|
|
|
private void tryToTame(Player player) {
|
|
- if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit
|
|
+ if ((this.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials()) || this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit
|
|
this.tame(player);
|
|
this.setOrderedToSit(true);
|
|
this.level().broadcastEntityEvent(this, (byte) 7);
|
|
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 919406f18bccec676adec133a60a938dc77f81c4..2bf42a1b1aadcce3f94f3377025cf291aee321b3 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Chicken.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Chicken.java
|
|
@@ -53,10 +53,52 @@ public class Chicken extends Animal {
|
|
this.setPathfindingMalus(PathType.WATER, 0.0F);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.chickenRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.chickenRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.chickenControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.chickenMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.chickenScale);
|
|
+ if (level().purpurConfig.chickenRetaliate) {
|
|
+ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(2.0D);
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.chickenBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.chickenTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.chickenAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
- this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
+ // this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D)); // Purpur - moved down
|
|
this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(3, new TemptGoal(this, 1.0D, (itemstack) -> {
|
|
return itemstack.is(ItemTags.CHICKEN_FOOD);
|
|
@@ -65,6 +107,14 @@ public class Chicken extends Animal {
|
|
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F));
|
|
this.goalSelector.addGoal(7, new RandomLookAroundGoal(this));
|
|
+ // Purpur start
|
|
+ if (level().purpurConfig.chickenRetaliate) {
|
|
+ this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.0D, false));
|
|
+ this.targetSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal(this));
|
|
+ } else {
|
|
+ this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D));
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
|
|
@Override
|
|
@@ -73,7 +123,7 @@ public class Chicken extends Animal {
|
|
}
|
|
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
- return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 4.0D).add(Attributes.MOVEMENT_SPEED, 0.25D);
|
|
+ return Animal.createAnimalAttributes().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/minecraft/world/entity/animal/Cod.java b/src/main/java/net/minecraft/world/entity/animal/Cod.java
|
|
index 824e5e4fe7619ae46061c3c978c9a044db8c84ab..f0b6118a9995bb41836685bbf94d2e7fb15761eb 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Cod.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Cod.java
|
|
@@ -13,6 +13,33 @@ public class Cod extends AbstractSchoolingFish {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.codRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.codControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.codMaxHealth);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.codTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.codAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
public ItemStack getBucketItemStack() {
|
|
return new ItemStack(Items.COD_BUCKET);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Cow.java b/src/main/java/net/minecraft/world/entity/animal/Cow.java
|
|
index 3e00bbff266fc71b07014e7e047d77b7f809239f..6b517deec01445de4205eedb1557995a92d3ae67 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Cow.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Cow.java
|
|
@@ -37,6 +37,7 @@ import org.bukkit.event.player.PlayerBucketFillEvent;
|
|
// CraftBukkit end
|
|
|
|
public class Cow extends Animal {
|
|
+ private boolean isNaturallyAggressiveToPlayers; // Purpur
|
|
|
|
private static final EntityDimensions BABY_DIMENSIONS = EntityType.COW.getDimensions().scale(0.5F).withEyeHeight(0.665F);
|
|
|
|
@@ -44,18 +45,66 @@ public class Cow extends Animal {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.cowRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.cowRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.cowControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.cowMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.cowScale);
|
|
+ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(this.level().purpurConfig.cowNaturallyAggressiveToPlayersDamage); // Purpur
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.cowBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.cowTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.EntitySpawnReason spawnReason, net.minecraft.world.entity.SpawnGroupData entityData) {
|
|
+ this.isNaturallyAggressiveToPlayers = world.getLevel().purpurConfig.cowNaturallyAggressiveToPlayersChance > 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.cowNaturallyAggressiveToPlayersChance;
|
|
+ return super.finalizeSpawn(world, difficulty, spawnReason, entityData);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.cowAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new PanicGoal(this, 2.0D));
|
|
+ this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur
|
|
this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, (itemstack) -> {
|
|
- return itemstack.is(ItemTags.COW_FOOD);
|
|
+ return level().purpurConfig.cowFeedMushrooms > 0 && (itemstack.is(net.minecraft.world.level.block.Blocks.RED_MUSHROOM.asItem()) || itemstack.is(net.minecraft.world.level.block.Blocks.BROWN_MUSHROOM.asItem())) || itemstack.is(ItemTags.COW_FOOD); // Purpur
|
|
}, false));
|
|
this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25D));
|
|
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F));
|
|
this.goalSelector.addGoal(7, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (ignored, ignored2) -> isNaturallyAggressiveToPlayers)); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -64,7 +113,7 @@ public class Cow extends Animal {
|
|
}
|
|
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
- return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.MOVEMENT_SPEED, 0.20000000298023224D);
|
|
+ return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.MOVEMENT_SPEED, 0.20000000298023224D).add(Attributes.ATTACK_DAMAGE, 0.0D); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -94,6 +143,7 @@ public class Cow extends Animal {
|
|
|
|
@Override
|
|
public InteractionResult mobInteract(Player player, InteractionHand hand) {
|
|
+ if (getRider() != null) return InteractionResult.PASS; // Purpur
|
|
ItemStack itemstack = player.getItemInHand(hand);
|
|
|
|
if (itemstack.is(Items.BUCKET) && !this.isBaby()) {
|
|
@@ -102,7 +152,7 @@ public class Cow extends Animal {
|
|
|
|
if (event.isCancelled()) {
|
|
player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync
|
|
- return InteractionResult.PASS;
|
|
+ return tryRide(player, hand); // Purpur
|
|
}
|
|
// CraftBukkit end
|
|
|
|
@@ -111,6 +161,10 @@ public class Cow extends Animal {
|
|
|
|
player.setItemInHand(hand, itemstack1);
|
|
return InteractionResult.SUCCESS;
|
|
+ // 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);
|
|
}
|
|
@@ -126,4 +180,66 @@ public class Cow extends Animal {
|
|
public EntityDimensions getDefaultDimensions(Pose pose) {
|
|
return this.isBaby() ? Cow.BABY_DIMENSIONS : super.getDefaultDimensions(pose);
|
|
}
|
|
+
|
|
+ // Purpur start - feed mushroom to change to mooshroom
|
|
+ private int redMushroomsFed = 0;
|
|
+ private int brownMushroomsFed = 0;
|
|
+
|
|
+ private boolean isMushroom(ItemStack stack) {
|
|
+ return stack.getItem() == net.minecraft.world.level.block.Blocks.RED_MUSHROOM.asItem() || stack.getItem() == net.minecraft.world.level.block.Blocks.BROWN_MUSHROOM.asItem();
|
|
+ }
|
|
+
|
|
+ private int incrementFeedCount(ItemStack stack) {
|
|
+ if (stack.getItem() == net.minecraft.world.level.block.Blocks.RED_MUSHROOM.asItem()) {
|
|
+ return ++redMushroomsFed;
|
|
+ } else {
|
|
+ return ++brownMushroomsFed;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private InteractionResult feedMushroom(Player player, ItemStack stack) {
|
|
+ level().broadcastEntityEvent(this, (byte) 18); // hearts
|
|
+ playSound(SoundEvents.COW_MILK, 1.0F, 1.0F);
|
|
+ if (incrementFeedCount(stack) < level().purpurConfig.cowFeedMushrooms) {
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ stack.shrink(1);
|
|
+ }
|
|
+ return InteractionResult.CONSUME; // require 5 mushrooms to transform (prevents mushroom duping)
|
|
+ }
|
|
+ MushroomCow mooshroom = EntityType.MOOSHROOM.create(level(), EntitySpawnReason.CONVERSION);
|
|
+ if (mooshroom == null) {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+ if (stack.getItem() == net.minecraft.world.level.block.Blocks.BROWN_MUSHROOM.asItem()) {
|
|
+ mooshroom.setVariant(MushroomCow.Variant.BROWN);
|
|
+ } else {
|
|
+ mooshroom.setVariant(MushroomCow.Variant.RED);
|
|
+ }
|
|
+ mooshroom.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
|
|
+ mooshroom.setHealth(this.getHealth());
|
|
+ mooshroom.setAge(getAge());
|
|
+ mooshroom.copyPosition(this);
|
|
+ mooshroom.setYBodyRot(this.yBodyRot);
|
|
+ mooshroom.setYHeadRot(this.getYHeadRot());
|
|
+ mooshroom.yRotO = this.yRotO;
|
|
+ mooshroom.xRotO = this.xRotO;
|
|
+ if (this.hasCustomName()) {
|
|
+ mooshroom.setCustomName(this.getCustomName());
|
|
+ }
|
|
+ if (CraftEventFactory.callEntityTransformEvent(this, mooshroom, org.bukkit.event.entity.EntityTransformEvent.TransformReason.INFECTION).isCancelled()) {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+ this.level().addFreshEntity(mooshroom);
|
|
+ this.remove(RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ stack.shrink(1);
|
|
+ }
|
|
+ for (int i = 0; i < 15; ++i) {
|
|
+ ((ServerLevel) level()).sendParticles(((ServerLevel) level()).players(), null, net.minecraft.core.particles.ParticleTypes.HAPPY_VILLAGER,
|
|
+ getX() + random.nextFloat(), getY() + (random.nextFloat() * 2), getZ() + random.nextFloat(), 1,
|
|
+ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0, true);
|
|
+ }
|
|
+ return InteractionResult.SUCCESS;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java
|
|
index 5af4d590a9b0f17ba53c6959d9c18bd1269878a4..c1842894f96a567707992d8ff938dbf689dd0df6 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java
|
|
@@ -85,14 +85,99 @@ public class Dolphin extends AgeableWaterCreature {
|
|
return !entityitem.hasPickUpDelay() && entityitem.isAlive() && entityitem.isInWater();
|
|
};
|
|
public static final float BABY_SCALE = 0.65F;
|
|
+ private boolean isNaturallyAggressiveToPlayers; // Purpur
|
|
+ private int spitCooldown; // Purpur
|
|
|
|
public Dolphin(EntityType<? extends Dolphin> type, Level world) {
|
|
super(type, world);
|
|
- this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true);
|
|
+ // Purpur start
|
|
+ class DolphinMoveControl extends SmoothSwimmingMoveControl {
|
|
+ private final org.purpurmc.purpur.controller.WaterMoveControllerWASD waterMoveControllerWASD;
|
|
+ private final Dolphin dolphin;
|
|
+
|
|
+ public DolphinMoveControl(Dolphin dolphin, int pitchChange, int yawChange, float speedInWater, float speedInAir, boolean buoyant) {
|
|
+ super(dolphin, pitchChange, yawChange, speedInWater, speedInAir, buoyant);
|
|
+ this.dolphin = dolphin;
|
|
+ this.waterMoveControllerWASD = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(dolphin);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ if (dolphin.getRider() != null && dolphin.isControllable()) {
|
|
+ purpurTick(dolphin.getRider());
|
|
+ } else {
|
|
+ super.tick();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void purpurTick(Player rider) {
|
|
+ if (dolphin.getAirSupply() < 150) {
|
|
+ // if drowning override player WASD controls to find air
|
|
+ super.tick();
|
|
+ } else {
|
|
+ waterMoveControllerWASD.purpurTick(rider);
|
|
+ dolphin.setDeltaMovement(dolphin.getDeltaMovement().add(0.0D, 0.005D, 0.0D));
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+ this.moveControl = new DolphinMoveControl(this, 85, 10, 0.02F, 0.1F, true);
|
|
+ // Purpur end
|
|
this.lookControl = new SmoothSwimmingLookControl(this, 10);
|
|
this.setCanPickUpLoot(true);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.dolphinRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.dolphinControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean onSpacebar() {
|
|
+ if (spitCooldown == 0 && getRider() != null) {
|
|
+ spitCooldown = level().purpurConfig.dolphinSpitCooldown;
|
|
+
|
|
+ org.bukkit.craftbukkit.entity.CraftPlayer player = (org.bukkit.craftbukkit.entity.CraftPlayer) getRider().getBukkitEntity();
|
|
+ if (!player.hasPermission("allow.special.dolphin")) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ org.bukkit.Location loc = player.getEyeLocation();
|
|
+ loc.setPitch(loc.getPitch() - 10);
|
|
+ org.bukkit.util.Vector target = loc.getDirection().normalize().multiply(10).add(loc.toVector());
|
|
+
|
|
+ org.purpurmc.purpur.entity.DolphinSpit spit = new org.purpurmc.purpur.entity.DolphinSpit(level(), this);
|
|
+ spit.shoot(target.getX() - getX(), target.getY() - getY(), target.getZ() - getZ(), level().purpurConfig.dolphinSpitSpeed, 5.0F);
|
|
+
|
|
+ level().addFreshEntity(spit);
|
|
+ playSound(SoundEvents.DOLPHIN_ATTACK, 1.0F, 1.0F + (random.nextFloat() - random.nextFloat()) * 0.2F);
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.dolphinMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.dolphinScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.dolphinTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.dolphinAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Nullable
|
|
@Override
|
|
public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) {
|
|
@@ -101,6 +186,7 @@ public class Dolphin extends AgeableWaterCreature {
|
|
SpawnGroupData groupdataentity1 = (SpawnGroupData) Objects.requireNonNullElseGet(entityData, () -> {
|
|
return new AgeableMob.AgeableMobGroupData(0.1F);
|
|
});
|
|
+ this.isNaturallyAggressiveToPlayers = world.getLevel().purpurConfig.dolphinNaturallyAggressiveToPlayersChance > 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.dolphinNaturallyAggressiveToPlayersChance; // Purpur
|
|
|
|
return super.finalizeSpawn(world, difficulty, spawnReason, groupdataentity1);
|
|
}
|
|
@@ -177,17 +263,21 @@ public class Dolphin extends AgeableWaterCreature {
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(0, new BreathAirGoal(this));
|
|
this.goalSelector.addGoal(0, new TryFindWaterGoal(this));
|
|
+ this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new Dolphin.DolphinSwimToTreasureGoal(this));
|
|
this.goalSelector.addGoal(2, new Dolphin.DolphinSwimWithPlayerGoal(this, 4.0D));
|
|
this.goalSelector.addGoal(4, new RandomSwimmingGoal(this, 1.0D, 10));
|
|
this.goalSelector.addGoal(4, new RandomLookAroundGoal(this));
|
|
this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 6.0F));
|
|
this.goalSelector.addGoal(5, new DolphinJumpGoal(this, 10));
|
|
- this.goalSelector.addGoal(6, new MeleeAttackGoal(this, 1.2000000476837158D, true));
|
|
+ //this.goalSelector.addGoal(6, new MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur - moved up
|
|
this.goalSelector.addGoal(8, new Dolphin.PlayWithItemsGoal());
|
|
this.goalSelector.addGoal(8, new FollowBoatGoal(this));
|
|
this.goalSelector.addGoal(9, new AvoidEntityGoal<>(this, Guardian.class, 8.0F, 1.0D, 1.0D));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Guardian.class})).setAlertOthers());
|
|
+ this.targetSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (ignored, ignored2) -> isNaturallyAggressiveToPlayers)); // Purpur
|
|
}
|
|
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
@@ -231,7 +321,7 @@ public class Dolphin extends AgeableWaterCreature {
|
|
|
|
@Override
|
|
protected boolean canRide(Entity entity) {
|
|
- return true;
|
|
+ return boardingCooldown <= 0; // Purpur - make dolphin honor ride cooldown like all other non-boss mobs;
|
|
}
|
|
|
|
@Override
|
|
@@ -264,6 +354,11 @@ public class Dolphin extends AgeableWaterCreature {
|
|
@Override
|
|
public void tick() {
|
|
super.tick();
|
|
+ // Purpur start
|
|
+ if (spitCooldown > 0) {
|
|
+ spitCooldown--;
|
|
+ }
|
|
+ // Purpur end
|
|
if (this.isNoAi()) {
|
|
this.setAirSupply(this.getMaxAirSupply());
|
|
} else {
|
|
@@ -412,6 +507,7 @@ public class Dolphin extends AgeableWaterCreature {
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
+ if (this.dolphin.level().purpurConfig.dolphinDisableTreasureSearching) return false; // Purpur
|
|
return this.dolphin.gotFish() && this.dolphin.getAirSupply() >= 100;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java
|
|
index a9a8ebb2cebe668628d5bdb33fa1399e0ab1e08b..0e229955d9ea7036fab124fa7685df22280671f2 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java
|
|
@@ -144,6 +144,65 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
|
|
this.getNavigation().setRequiredPathLength(32.0F);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.foxRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.foxRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.foxControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public float getJumpPower() {
|
|
+ return getRider() != null && this.isControllable() ? 0.5F : super.getJumpPower();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onMount(Player rider) {
|
|
+ super.onMount(rider);
|
|
+ setCanPickUpLoot(false);
|
|
+ clearStates();
|
|
+ setIsPouncing(false);
|
|
+ spitOutItem(getItemBySlot(EquipmentSlot.MAINHAND));
|
|
+ setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onDismount(Player rider) {
|
|
+ super.onDismount(rider);
|
|
+ setCanPickUpLoot(true);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.foxMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.foxScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.foxBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.foxTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.foxAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
|
super.defineSynchedData(builder);
|
|
@@ -163,6 +222,7 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
|
|
return entityliving instanceof AbstractSchoolingFish;
|
|
});
|
|
this.goalSelector.addGoal(0, new Fox.FoxFloatGoal());
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(0, new ClimbOnTopOfPowderSnowGoal(this, this.level()));
|
|
this.goalSelector.addGoal(1, new Fox.FaceplantGoal());
|
|
this.goalSelector.addGoal(2, new Fox.FoxPanicGoal(2.2D));
|
|
@@ -189,6 +249,7 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
|
|
this.goalSelector.addGoal(11, new Fox.FoxSearchForItemsGoal());
|
|
this.goalSelector.addGoal(12, new Fox.FoxLookAtPlayerGoal(this, Player.class, 24.0F));
|
|
this.goalSelector.addGoal(13, new Fox.PerchAndSearchGoal());
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(3, new Fox.DefendTrustedTargetGoal(LivingEntity.class, false, false, (entityliving, worldserver) -> {
|
|
return Fox.TRUSTED_TARGET_SELECTOR.test(entityliving) && !this.trusts(entityliving.getUUID());
|
|
}));
|
|
@@ -338,6 +399,11 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
|
|
}
|
|
|
|
private void setTargetGoals() {
|
|
+ // Purpur start - do not add duplicate goals
|
|
+ this.targetSelector.removeGoal(this.landTargetGoal);
|
|
+ this.targetSelector.removeGoal(this.turtleEggTargetGoal);
|
|
+ this.targetSelector.removeGoal(this.fishTargetGoal);
|
|
+ // Purpur end
|
|
if (this.getVariant() == Fox.Variant.RED) {
|
|
this.targetSelector.addGoal(4, this.landTargetGoal);
|
|
this.targetSelector.addGoal(4, this.turtleEggTargetGoal);
|
|
@@ -367,6 +433,7 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
|
|
|
|
public void setVariant(Fox.Variant variant) {
|
|
this.entityData.set(Fox.DATA_TYPE_ID, variant.getId());
|
|
+ this.setTargetGoals(); // Purpur - fix API bug not updating pathfinders on type change
|
|
}
|
|
|
|
List<UUID> getTrustedUUIDs() {
|
|
@@ -702,6 +769,29 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
|
|
}
|
|
// Paper end
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public net.minecraft.world.InteractionResult mobInteract(Player player, net.minecraft.world.InteractionHand hand) {
|
|
+ if (level().purpurConfig.foxTypeChangesWithTulips) {
|
|
+ ItemStack itemstack = player.getItemInHand(hand);
|
|
+ if (getVariant() == Variant.RED && itemstack.getItem() == Items.WHITE_TULIP) {
|
|
+ setVariant(Variant.SNOW);
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ itemstack.shrink(1);
|
|
+ }
|
|
+ return net.minecraft.world.InteractionResult.SUCCESS;
|
|
+ } else if (getVariant() == Variant.SNOW && itemstack.getItem() == Items.ORANGE_TULIP) {
|
|
+ setVariant(Variant.RED);
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ itemstack.shrink(1);
|
|
+ }
|
|
+ return net.minecraft.world.InteractionResult.SUCCESS;
|
|
+ }
|
|
+ }
|
|
+ return super.mobInteract(player, hand);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
// Paper start - Cancellable death event
|
|
protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(ServerLevel world, DamageSource damageSource) {
|
|
@@ -754,16 +844,16 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
|
|
return new Vec3(0.0D, (double) (0.55F * this.getEyeHeight()), (double) (this.getBbWidth() * 0.4F));
|
|
}
|
|
|
|
- public class FoxLookControl extends LookControl {
|
|
+ public class FoxLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur
|
|
|
|
public FoxLookControl() {
|
|
super(Fox.this);
|
|
}
|
|
|
|
@Override
|
|
- public void tick() {
|
|
+ public void vanillaTick() { // Purpur
|
|
if (!Fox.this.isSleeping()) {
|
|
- super.tick();
|
|
+ super.vanillaTick(); // Purpur
|
|
}
|
|
|
|
}
|
|
@@ -774,16 +864,16 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
|
|
}
|
|
}
|
|
|
|
- private class FoxMoveControl extends MoveControl {
|
|
+ private class FoxMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur
|
|
|
|
public FoxMoveControl() {
|
|
super(Fox.this);
|
|
}
|
|
|
|
@Override
|
|
- public void tick() {
|
|
+ public void vanillaTick() { // Purpur
|
|
if (Fox.this.canMove()) {
|
|
- super.tick();
|
|
+ super.vanillaTick(); // Purpur
|
|
}
|
|
|
|
}
|
|
@@ -901,8 +991,10 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
|
|
CriteriaTriggers.BRED_ANIMALS.trigger(entityplayer2, this.animal, this.partner, entityfox);
|
|
}
|
|
|
|
- this.animal.setAge(6000);
|
|
- this.partner.setAge(6000);
|
|
+ // Purpur start
|
|
+ this.animal.setAge(this.animal.getPurpurBreedTime());
|
|
+ this.partner.setAge(this.partner.getPurpurBreedTime());
|
|
+ // Purpur end
|
|
this.animal.resetLove();
|
|
this.partner.resetLove();
|
|
worldserver.addFreshEntityWithPassengers(entityfox, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason
|
|
@@ -1288,7 +1380,7 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
|
|
}
|
|
|
|
protected void onReachedTarget() {
|
|
- if (getServerLevel(Fox.this.level()).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
|
+ if (getServerLevel(Fox.this.level()).purpurConfig.foxBypassMobGriefing || getServerLevel(Fox.this.level()).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur
|
|
BlockState iblockdata = Fox.this.level().getBlockState(this.blockPos);
|
|
|
|
if (iblockdata.is(Blocks.SWEET_BERRY_BUSH)) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
|
|
index e07b79ef172095c1800c88342b3ac8dc7703aea2..9a6471d2f1eb1c8af006b70b6bba0b668220fb00 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
|
|
@@ -57,13 +57,59 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
|
|
private int remainingPersistentAngerTime;
|
|
@Nullable
|
|
private UUID persistentAngerTarget;
|
|
+ @Nullable private UUID summoner; // Purpur
|
|
|
|
public IronGolem(EntityType<? extends IronGolem> type, Level world) {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.ironGolemRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ironGolemRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.ironGolemControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ironGolemMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.ironGolemScale);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.ironGolemTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
+ public UUID getSummoner() {
|
|
+ return summoner;
|
|
+ }
|
|
+
|
|
+ public void setSummoner(@Nullable UUID summoner) {
|
|
+ this.summoner = summoner;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.ironGolemAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
+ if (level().purpurConfig.ironGolemCanSwim) this.goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur
|
|
+ if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0D, true));
|
|
this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9D, 32.0F));
|
|
this.goalSelector.addGoal(2, new MoveBackToVillageGoal(this, 0.6D, false));
|
|
@@ -71,6 +117,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
|
|
this.goalSelector.addGoal(5, new OfferFlowerGoal(this));
|
|
this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F));
|
|
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new DefendVillageTargetGoal(this));
|
|
this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0]));
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt));
|
|
@@ -135,6 +182,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
|
|
public void addAdditionalSaveData(CompoundTag nbt) {
|
|
super.addAdditionalSaveData(nbt);
|
|
nbt.putBoolean("PlayerCreated", this.isPlayerCreated());
|
|
+ if (getSummoner() != null) nbt.putUUID("Purpur.Summoner", getSummoner()); // Purpur
|
|
this.addPersistentAngerSaveData(nbt);
|
|
}
|
|
|
|
@@ -142,6 +190,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
|
|
public void readAdditionalSaveData(CompoundTag nbt) {
|
|
super.readAdditionalSaveData(nbt);
|
|
this.setPlayerCreated(nbt.getBoolean("PlayerCreated"));
|
|
+ if (nbt.contains("Purpur.Summoner")) setSummoner(nbt.getUUID("Purpur.Summoner")); // Purpur
|
|
this.readPersistentAngerSaveData(this.level(), nbt);
|
|
}
|
|
|
|
@@ -267,18 +316,19 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
|
|
ItemStack itemstack = player.getItemInHand(hand);
|
|
|
|
if (!itemstack.is(Items.IRON_INGOT)) {
|
|
- return InteractionResult.PASS;
|
|
+ return tryRide(player, hand); // Purpur
|
|
} else {
|
|
float f = this.getHealth();
|
|
|
|
this.heal(25.0F);
|
|
if (this.getHealth() == f) {
|
|
- return InteractionResult.PASS;
|
|
+ return tryRide(player, hand); // Purpur
|
|
} else {
|
|
float f1 = 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F;
|
|
|
|
this.playSound(SoundEvents.IRON_GOLEM_REPAIR, 1.0F, f1);
|
|
itemstack.consume(1, player);
|
|
+ if (this.level().purpurConfig.ironGolemHealCalm && isAngry() && getHealth() == getMaxHealth()) stopBeingAngry(); // Purpur
|
|
return InteractionResult.SUCCESS;
|
|
}
|
|
}
|
|
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 feeb7bc34ae02e44d7f13f0bae5d175ef924c53a..529b1bef6abcecdd2c08afafc6548aeee7db9203 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java
|
|
@@ -65,6 +65,43 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder<Mushroo
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.mooshroomRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.mooshroomRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.mooshroomControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.mooshroomMaxHealth);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.mooshroomBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.mooshroomTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.mooshroomAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
public float getWalkTargetValue(BlockPos pos, LevelReader world) {
|
|
return world.getBlockState(pos.below()).is(Blocks.MYCELIUM) ? 10.0F : world.getPathfindingCostFromLightLevels(pos);
|
|
@@ -134,7 +171,7 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder<Mushroo
|
|
org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops);
|
|
if (event != null) {
|
|
if (event.isCancelled()) {
|
|
- return InteractionResult.PASS;
|
|
+ return tryRide(player, hand); // Purpur
|
|
}
|
|
drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops());
|
|
// Paper end - custom shear drops
|
|
@@ -155,7 +192,7 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder<Mushroo
|
|
Optional<SuspiciousStewEffects> optional = this.getEffectsFromItemStack(itemstack);
|
|
|
|
if (optional.isEmpty()) {
|
|
- return InteractionResult.PASS;
|
|
+ return tryRide(player, hand); // Purpur
|
|
}
|
|
|
|
itemstack.consume(1, player);
|
|
@@ -195,6 +232,13 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder<Mushroo
|
|
world.playSound((Player) null, (Entity) this, SoundEvents.MOOSHROOM_SHEAR, shearedSoundCategory, 1.0F, 1.0F);
|
|
this.convertTo(EntityType.COW, ConversionParams.single(this, false, false), (entitycow) -> {
|
|
world.sendParticles(ParticleTypes.EXPLOSION, this.getX(), this.getY(0.5D), this.getZ(), 1, 0.0D, 0.0D, 0.0D, 0.0D);
|
|
+ // Purpur start
|
|
+ entitycow.copyPosition(this);
|
|
+ entitycow.yBodyRot = this.yBodyRot;
|
|
+ entitycow.setYHeadRot(this.getYHeadRot());
|
|
+ entitycow.yRotO = this.yRotO;
|
|
+ entitycow.xRotO = this.xRotO;
|
|
+ // Purpur end
|
|
// Paper start - custom shear drops; moved drop generation to separate method
|
|
drops.forEach(itemstack1 -> {
|
|
for (final ItemStack drop : drops) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Ocelot.java b/src/main/java/net/minecraft/world/entity/animal/Ocelot.java
|
|
index 0554ee499c452db6c1e6852f5022b1f197adb024..dee59cb4b87845c940ee089aa932aa69dd2539d6 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Ocelot.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Ocelot.java
|
|
@@ -65,6 +65,44 @@ public class Ocelot extends Animal {
|
|
this.reassessTrustingGoals();
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.ocelotRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ocelotRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.ocelotControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ocelotMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.ocelotScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.ocelotBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.ocelotTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.ocelotAlwaysDropExp;
|
|
+ }
|
|
+
|
|
public boolean isTrusting() {
|
|
return (Boolean) this.entityData.get(Ocelot.DATA_TRUSTING);
|
|
}
|
|
@@ -98,12 +136,14 @@ public class Ocelot extends Animal {
|
|
return itemstack.is(ItemTags.OCELOT_FOOD);
|
|
}, true);
|
|
this.goalSelector.addGoal(1, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(3, this.temptGoal);
|
|
this.goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3F));
|
|
this.goalSelector.addGoal(8, new OcelotAttackGoal(this));
|
|
this.goalSelector.addGoal(9, new BreedGoal(this, 0.8D));
|
|
this.goalSelector.addGoal(10, new WaterAvoidingRandomStrollGoal(this, 0.8D, 1.0000001E-5F));
|
|
this.goalSelector.addGoal(11, new LookAtPlayerGoal(this, Player.class, 10.0F));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Chicken.class, false));
|
|
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, false, false, Turtle.BABY_ON_LAND_SELECTOR));
|
|
}
|
|
@@ -244,7 +284,7 @@ public class Ocelot extends Animal {
|
|
if (world.isUnobstructed(this) && !world.containsAnyLiquid(this.getBoundingBox())) {
|
|
BlockPos blockposition = this.blockPosition();
|
|
|
|
- if (blockposition.getY() < world.getSeaLevel()) {
|
|
+ if (!level().purpurConfig.ocelotSpawnUnderSeaLevel && blockposition.getY() < world.getSeaLevel()) {
|
|
return false;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java
|
|
index be753557d7ebd6f1e82b1bdb6d60ecc450f72eec..83372c86bd54eedd9b136ddfcbfc67d303058c0a 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Panda.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java
|
|
@@ -112,6 +112,54 @@ public class Panda extends Animal {
|
|
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.pandaRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.pandaRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.pandaControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onMount(Player rider) {
|
|
+ super.onMount(rider);
|
|
+ setForwardMot(0.0F);
|
|
+ sit(false);
|
|
+ eat(false);
|
|
+ setOnBack(false);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.pandaMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.pandaScale);
|
|
+ setAttributes();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.pandaBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.pandaTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.pandaAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected boolean canDispenserEquipIntoSlot(EquipmentSlot slot) {
|
|
return slot == EquipmentSlot.MAINHAND && this.canPickUpLoot();
|
|
@@ -271,6 +319,7 @@ public class Panda extends Animal {
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(2, new Panda.PandaPanicGoal(this, 2.0D));
|
|
this.goalSelector.addGoal(2, new Panda.PandaBreedGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(3, new Panda.PandaAttackGoal(this, 1.2000000476837158D, true));
|
|
@@ -288,6 +337,7 @@ public class Panda extends Animal {
|
|
this.goalSelector.addGoal(12, new Panda.PandaRollGoal(this));
|
|
this.goalSelector.addGoal(13, new FollowParentGoal(this, 1.25D));
|
|
this.goalSelector.addGoal(14, new WaterAvoidingRandomStrollGoal(this, 1.0D));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, (new Panda.PandaHurtByTargetGoal(this, new Class[0])).setAlertOthers(new Class[0]));
|
|
}
|
|
|
|
@@ -617,7 +667,10 @@ public class Panda extends Animal {
|
|
|
|
public void setAttributes() {
|
|
if (this.isWeak()) {
|
|
- this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(10.0D);
|
|
+ // Purpur start
|
|
+ net.minecraft.world.entity.ai.attributes.AttributeInstance maxHealth = this.getAttribute(Attributes.MAX_HEALTH);
|
|
+ maxHealth.setBaseValue(maxHealth.getValue() / 2);
|
|
+ // Purpur end
|
|
}
|
|
|
|
if (this.isLazy()) {
|
|
@@ -640,7 +693,7 @@ public class Panda extends Animal {
|
|
ItemStack itemstack = player.getItemInHand(hand);
|
|
|
|
if (this.isScared()) {
|
|
- return InteractionResult.PASS;
|
|
+ return tryRide(player, hand); // Purpur
|
|
} else if (this.isOnBack()) {
|
|
this.setOnBack(false);
|
|
return InteractionResult.SUCCESS;
|
|
@@ -679,12 +732,12 @@ public class Panda extends Animal {
|
|
}
|
|
}
|
|
|
|
- return InteractionResult.PASS;
|
|
+ return tryRide(player, hand); // Purpur
|
|
}
|
|
|
|
return InteractionResult.SUCCESS_SERVER;
|
|
} else {
|
|
- return InteractionResult.PASS;
|
|
+ return tryRide(player, hand); // Purpur
|
|
}
|
|
}
|
|
|
|
@@ -729,7 +782,7 @@ public class Panda extends Animal {
|
|
return itemEntity.getItem().is(ItemTags.PANDA_EATS_FROM_GROUND) && itemEntity.isAlive() && !itemEntity.hasPickUpDelay();
|
|
}
|
|
|
|
- private static class PandaMoveControl extends MoveControl {
|
|
+ private static class PandaMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur
|
|
|
|
private final Panda panda;
|
|
|
|
@@ -739,9 +792,9 @@ public class Panda extends Animal {
|
|
}
|
|
|
|
@Override
|
|
- public void tick() {
|
|
+ public void vanillaTick() { // Purpur
|
|
if (this.panda.canPerformAction()) {
|
|
- super.tick();
|
|
+ super.vanillaTick(); // Purpur
|
|
}
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Parrot.java b/src/main/java/net/minecraft/world/entity/animal/Parrot.java
|
|
index 8883894da73c7d5975a8826d23ee7f542db98b0b..28a9d267099f6c24f71dc5a11179d59c27265a88 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Parrot.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Parrot.java
|
|
@@ -126,12 +126,89 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder<Parrot
|
|
|
|
public Parrot(EntityType<? extends Parrot> type, Level world) {
|
|
super(type, world);
|
|
- this.moveControl = new FlyingMoveControl(this, 10, false);
|
|
+ // Purpur start
|
|
+ final org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD flyingController = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F);
|
|
+ class ParrotMoveControl extends FlyingMoveControl {
|
|
+ public ParrotMoveControl(Mob entity, int maxPitchChange, boolean noGravity) {
|
|
+ super(entity, maxPitchChange, noGravity);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ if (mob.getRider() != null && mob.isControllable()) {
|
|
+ flyingController.purpurTick(mob.getRider());
|
|
+ } else {
|
|
+ super.tick();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasWanted() {
|
|
+ return mob.getRider() != null && mob.isControllable() ? getForwardMot() != 0 || getStrafeMot() != 0 : super.hasWanted();
|
|
+ }
|
|
+ }
|
|
+ this.moveControl = new ParrotMoveControl(this, 10, false);
|
|
+ // Purpur end
|
|
this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F);
|
|
this.setPathfindingMalus(PathType.DAMAGE_FIRE, -1.0F);
|
|
this.setPathfindingMalus(PathType.COCOA, -1.0F);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.parrotRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.parrotRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.parrotControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double getMaxY() {
|
|
+ return level().purpurConfig.parrotMaxY;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void travel(Vec3 vec3) {
|
|
+ super.travel(vec3);
|
|
+ if (getRider() != null && this.isControllable() && !onGround) {
|
|
+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2;
|
|
+ setSpeed(speed);
|
|
+ Vec3 mot = getDeltaMovement();
|
|
+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.25, speed));
|
|
+ setDeltaMovement(mot.scale(0.9D));
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.parrotMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.parrotScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return 6000;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.parrotTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.parrotAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Nullable
|
|
@Override
|
|
public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) {
|
|
@@ -150,8 +227,11 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder<Parrot
|
|
|
|
@Override
|
|
protected void registerGoals() {
|
|
- this.goalSelector.addGoal(0, new TamableAnimal.TamableAnimalPanicGoal(1.25D));
|
|
+ //this.goalSelector.addGoal(0, new TamableAnimal.TamableAnimalPanicGoal(1.25D)); // Purpur - move down
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ if (this.level().purpurConfig.parrotBreedable) this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.BreedGoal(this, 1.0D)); // Purpur
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
+ this.goalSelector.addGoal(1, new TamableAnimal.TamableAnimalPanicGoal(1.25D)); // Purpur
|
|
this.goalSelector.addGoal(1, new LookAtPlayerGoal(this, Player.class, 8.0F));
|
|
this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this));
|
|
this.goalSelector.addGoal(2, new FollowOwnerGoal(this, 1.0D, 5.0F, 1.0F));
|
|
@@ -250,7 +330,7 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder<Parrot
|
|
}
|
|
|
|
if (!this.level().isClientSide) {
|
|
- if (this.random.nextInt(10) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit
|
|
+ if ((this.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials()) || (this.random.nextInt(10) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled())) { // CraftBukkit // Purpur
|
|
this.tame(player);
|
|
this.level().broadcastEntityEvent(this, (byte) 7);
|
|
} else {
|
|
@@ -258,6 +338,7 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder<Parrot
|
|
}
|
|
}
|
|
|
|
+ if (this.level().purpurConfig.parrotBreedable) return super.mobInteract(player, hand); // Purpur
|
|
return InteractionResult.SUCCESS;
|
|
} else if (!itemstack.is(ItemTags.PARROT_POISONOUS_FOOD)) {
|
|
if (!this.isFlying() && this.isTame() && this.isOwnedBy(player)) {
|
|
@@ -282,7 +363,7 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder<Parrot
|
|
|
|
@Override
|
|
public boolean isFood(ItemStack stack) {
|
|
- return false;
|
|
+ return this.level().purpurConfig.parrotBreedable && stack.is(ItemTags.PARROT_FOOD); // Purpur
|
|
}
|
|
|
|
public static boolean checkParrotSpawnRules(EntityType<Parrot> type, LevelAccessor world, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random) {
|
|
@@ -294,13 +375,13 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder<Parrot
|
|
|
|
@Override
|
|
public boolean canMate(Animal other) {
|
|
- return false;
|
|
+ return super.canMate(other); // Purpur
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public AgeableMob getBreedOffspring(ServerLevel world, AgeableMob entity) {
|
|
- return null;
|
|
+ return world.purpurConfig.parrotBreedable ? EntityType.PARROT.create(world, EntitySpawnReason.BREEDING) : null; // Purpur
|
|
}
|
|
|
|
@Nullable
|
|
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 c39b2580a67c9b0bf8631f108e0628fa9732ada1..7895fca01c20da24a10ac6a642ebba87f73f2799 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Pig.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Pig.java
|
|
@@ -65,9 +65,48 @@ public class Pig extends Animal implements ItemSteerable, Saddleable {
|
|
this.steering = new ItemBasedSteering(this.entityData, Pig.DATA_BOOST_TIME, Pig.DATA_SADDLE_ID);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.pigRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.pigRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.pigControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.pigMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.pigScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.pigBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.pigTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.pigAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new PanicGoal(this, 1.25D));
|
|
this.goalSelector.addGoal(3, new BreedGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(4, new TemptGoal(this, 1.2D, (itemstack) -> {
|
|
@@ -156,6 +195,17 @@ public class Pig extends Animal implements ItemSteerable, Saddleable {
|
|
public InteractionResult mobInteract(Player player, InteractionHand hand) {
|
|
boolean flag = this.isFood(player.getItemInHand(hand));
|
|
|
|
+ if (level().purpurConfig.pigGiveSaddleBack && player.isSecondaryUseActive() && !flag && isSaddled() && !isVehicle()) {
|
|
+ this.steering.setSaddle(false);
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ ItemStack saddle = new ItemStack(Items.SADDLE);
|
|
+ if (!player.getInventory().add(saddle)) {
|
|
+ player.drop(saddle, false);
|
|
+ }
|
|
+ }
|
|
+ return InteractionResult.SUCCESS;
|
|
+ }
|
|
+
|
|
if (!flag && this.isSaddled() && !this.isVehicle() && !player.isSecondaryUseActive()) {
|
|
if (!this.level().isClientSide) {
|
|
player.startRiding(this);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java
|
|
index cd72d8f766069796ce1fe4a83b8646692005ff8c..86c44912a363401bdd716c22d24dfd7e92cfd0be 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java
|
|
@@ -59,11 +59,82 @@ public class PolarBear extends Animal implements NeutralMob {
|
|
private int remainingPersistentAngerTime;
|
|
@Nullable
|
|
private UUID persistentAngerTarget;
|
|
+ private int standTimer = 0; // Purpur
|
|
|
|
public PolarBear(EntityType<? extends PolarBear> type, Level world) {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.polarBearRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.polarBearRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.polarBearControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean onSpacebar() {
|
|
+ if (!isStanding()) {
|
|
+ if (getRider() != null && getRider().getForwardMot() == 0 && getRider().getStrafeMot() == 0) {
|
|
+ setStanding(true);
|
|
+ playSound(SoundEvents.POLAR_BEAR_WARNING, 1.0F, 1.0F);
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.polarBearMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.polarBearScale);
|
|
+ }
|
|
+
|
|
+ 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();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.polarBearBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.polarBearTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.polarBearAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Nullable
|
|
@Override
|
|
public AgeableMob getBreedOffspring(ServerLevel world, AgeableMob entity) {
|
|
@@ -72,20 +143,28 @@ 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
|
|
protected void registerGoals() {
|
|
super.registerGoals();
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new PolarBear.PolarBearMeleeAttackGoal());
|
|
this.goalSelector
|
|
.addGoal(1, new PanicGoal(this, 2.0, polarBear -> polarBear.isBaby() ? DamageTypeTags.PANIC_CAUSES : DamageTypeTags.PANIC_ENVIRONMENTAL_CAUSES));
|
|
+ // Purpur start
|
|
+ if (level().purpurConfig.polarBearBreedableItem != null) {
|
|
+ this.goalSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.BreedGoal(this, 1.0D));
|
|
+ this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.TemptGoal(this, 1.0D, net.minecraft.world.item.crafting.Ingredient.of(level().purpurConfig.polarBearBreedableItem), false));
|
|
+ }
|
|
+ // Purpur end
|
|
this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25));
|
|
this.goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0));
|
|
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F));
|
|
this.goalSelector.addGoal(7, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new PolarBear.PolarBearHurtByTargetGoal());
|
|
this.targetSelector.addGoal(2, new PolarBear.PolarBearAttackPlayersGoal());
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt));
|
|
@@ -204,6 +283,12 @@ public class PolarBear extends Animal implements NeutralMob {
|
|
if (!this.level().isClientSide) {
|
|
this.updatePersistentAnger((ServerLevel)this.level(), true);
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ if (isStanding() && --standTimer <= 0) {
|
|
+ setStanding(false);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
|
|
@Override
|
|
@@ -223,6 +308,7 @@ public class PolarBear extends Animal implements NeutralMob {
|
|
|
|
public void setStanding(boolean warning) {
|
|
this.entityData.set(DATA_STANDING_ID, warning);
|
|
+ standTimer = warning ? 20 : -1; // Purpur
|
|
}
|
|
|
|
public float getStandingAnimationScale(float tickDelta) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java
|
|
index cdb74f86ee92ee143af29962a85d45ca585cee44..c5a39ea2ad0e5e5ac434d79c1a57e0068b8bc809 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java
|
|
@@ -52,6 +52,33 @@ public class Pufferfish extends AbstractFish {
|
|
this.refreshDimensions();
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.pufferfishRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.pufferfishControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.pufferfishMaxHealth);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.pufferfishTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.pufferfishAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
|
super.defineSynchedData(builder);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java
|
|
index 8cc6022507c97af62fb2b4455198bc35744137c9..d8fa11a297ea2a183cac67c76b378ca912dba1f9 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java
|
|
@@ -88,6 +88,7 @@ public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
|
|
private boolean wasOnGround;
|
|
private int jumpDelayTicks;
|
|
public int moreCarrotTicks;
|
|
+ private boolean actualJump; // Purpur
|
|
|
|
public Rabbit(EntityType<? extends Rabbit> type, Level world) {
|
|
super(type, world);
|
|
@@ -95,9 +96,76 @@ public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
|
|
this.moveControl = new Rabbit.RabbitMoveControl(this);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.rabbitRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.rabbitRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.rabbitControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean onSpacebar() {
|
|
+ if (onGround) {
|
|
+ actualJump = true;
|
|
+ jumpFromGround();
|
|
+ actualJump = false;
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ private void handleJumping() {
|
|
+ if (onGround) {
|
|
+ RabbitJumpControl jumpController = (RabbitJumpControl) jumpControl;
|
|
+ if (!wasOnGround) {
|
|
+ setJumping(false);
|
|
+ jumpController.setCanJump(false);
|
|
+ }
|
|
+ if (!jumpController.wantJump()) {
|
|
+ if (moveControl.hasWanted()) {
|
|
+ startJumping();
|
|
+ }
|
|
+ } else if (!jumpController.canJump()) {
|
|
+ jumpController.setCanJump(true);
|
|
+ }
|
|
+ }
|
|
+ wasOnGround = onGround;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.rabbitMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.rabbitScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.rabbitBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.rabbitTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.rabbitAlwaysDropExp;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public void registerGoals() {
|
|
this.goalSelector.addGoal(1, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new ClimbOnTopOfPowderSnowGoal(this, this.level()));
|
|
this.goalSelector.addGoal(1, new Rabbit.RabbitPanicGoal(this, 2.2D));
|
|
this.goalSelector.addGoal(2, new BreedGoal(this, 0.8D));
|
|
@@ -114,6 +182,14 @@ public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
|
|
|
|
@Override
|
|
protected float getJumpPower() {
|
|
+ // Purpur start
|
|
+ if (getRider() != null && this.isControllable()) {
|
|
+ if (getForwardMot() < 0) {
|
|
+ setSpeed(getForwardMot() * 2F);
|
|
+ }
|
|
+ return actualJump ? 0.5F : 0.3F;
|
|
+ }
|
|
+ // Purpur end
|
|
float f = 0.3F;
|
|
|
|
if (this.horizontalCollision || this.moveControl.hasWanted() && this.moveControl.getWantedY() > this.getY() + 0.5D) {
|
|
@@ -188,6 +264,12 @@ public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
|
|
|
|
@Override
|
|
public void customServerAiStep(ServerLevel world) {
|
|
+ // Purpur start
|
|
+ if (getRider() != null && this.isControllable()) {
|
|
+ handleJumping();
|
|
+ return;
|
|
+ }
|
|
+ // Purpur end
|
|
if (this.jumpDelayTicks > 0) {
|
|
--this.jumpDelayTicks;
|
|
}
|
|
@@ -402,10 +484,23 @@ public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
|
|
}
|
|
|
|
this.setVariant(entityrabbit_variant);
|
|
+
|
|
+ // Purpur start
|
|
+ if (entityrabbit_variant != Variant.EVIL && world.getLevel().purpurConfig.rabbitNaturalToast > 0D && random.nextDouble() <= world.getLevel().purpurConfig.rabbitNaturalToast) {
|
|
+ setCustomName(Component.translatable("Toast"));
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData);
|
|
}
|
|
|
|
private static Rabbit.Variant getRandomRabbitVariant(LevelAccessor world, BlockPos pos) {
|
|
+ // Purpur start
|
|
+ Level level = world.getMinecraftWorld();
|
|
+ if (level.purpurConfig.rabbitNaturalKiller > 0D && world.getRandom().nextDouble() <= level.purpurConfig.rabbitNaturalKiller) {
|
|
+ return Rabbit.Variant.EVIL;
|
|
+ }
|
|
+ // Purpur end
|
|
Holder<Biome> holder = world.getBiome(pos);
|
|
int i = world.getRandom().nextInt(100);
|
|
|
|
@@ -469,7 +564,7 @@ public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
|
|
}
|
|
}
|
|
|
|
- private static class RabbitMoveControl extends MoveControl {
|
|
+ private static class RabbitMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur
|
|
|
|
private final Rabbit rabbit;
|
|
private double nextJumpSpeed;
|
|
@@ -480,14 +575,14 @@ public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
|
|
}
|
|
|
|
@Override
|
|
- public void tick() {
|
|
+ public void vanillaTick() { // Purpur
|
|
if (this.rabbit.onGround() && !this.rabbit.jumping && !((Rabbit.RabbitJumpControl) this.rabbit.jumpControl).wantJump()) {
|
|
this.rabbit.setSpeedModifier(0.0D);
|
|
} else if (this.hasWanted()) {
|
|
this.rabbit.setSpeedModifier(this.nextJumpSpeed);
|
|
}
|
|
|
|
- super.tick();
|
|
+ super.vanillaTick(); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -549,7 +644,7 @@ public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
|
|
@Override
|
|
public boolean canUse() {
|
|
if (this.nextStartTick <= 0) {
|
|
- if (!getServerLevel((Entity) this.rabbit).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
|
+ if (!getServerLevel((Entity) this.rabbit).purpurConfig.rabbitBypassMobGriefing && !getServerLevel((Entity) this.rabbit).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur
|
|
return false;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Salmon.java b/src/main/java/net/minecraft/world/entity/animal/Salmon.java
|
|
index 661997c39df777b6e332f0a5710e7f63a116a499..1a0c71ed6f3bd3d961f9b30ab29a62d683195355 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Salmon.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Salmon.java
|
|
@@ -32,6 +32,33 @@ public class Salmon extends AbstractSchoolingFish implements VariantHolder<Salmo
|
|
this.refreshDimensions();
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.salmonRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.salmonControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.salmonMaxHealth);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.salmonTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.salmonAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
public int getMaxSchoolSize() {
|
|
return 5;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java
|
|
index 432ad1c785e133ef18390108fd342be50ec4dddc..a13ce089bacfb6644eea81fbe7c6d640aedaea96 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java
|
|
@@ -91,10 +91,49 @@ public class Sheep extends Animal implements Shearable {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.sheepRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.sheepRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.sheepControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.sheepMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.sheepScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.sheepBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.sheepTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.sheepAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.eatBlockGoal = new EatBlockGoal(this);
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new PanicGoal(this, 1.25D));
|
|
this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(3, new TemptGoal(this, 1.1D, (itemstack) -> {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java
|
|
index fd9f6c17448a4d87f940eb8f544ecb9669068582..d6dd771a868bdf012b6095e333ebb12fc6050478 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java
|
|
@@ -50,17 +50,57 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
|
|
|
|
private static final EntityDataAccessor<Byte> DATA_PUMPKIN_ID = SynchedEntityData.defineId(SnowGolem.class, EntityDataSerializers.BYTE);
|
|
private static final byte PUMPKIN_FLAG = 16;
|
|
+ @Nullable private java.util.UUID summoner; // Purpur
|
|
|
|
public SnowGolem(EntityType<? extends SnowGolem> type, Level world) {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.snowGolemRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.snowGolemRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.snowGolemControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.snowGolemMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.snowGolemScale);
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
+ public java.util.UUID getSummoner() {
|
|
+ return summoner;
|
|
+ }
|
|
+
|
|
+ public void setSummoner(@Nullable java.util.UUID summoner) {
|
|
+ this.summoner = summoner;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.snowGolemAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
- this.goalSelector.addGoal(1, new RangedAttackGoal(this, 1.25D, 20, 10.0F));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
+ this.goalSelector.addGoal(1, new RangedAttackGoal(this, level().purpurConfig.snowGolemAttackDistance, level().purpurConfig.snowGolemSnowBallMin, level().purpurConfig.snowGolemSnowBallMax, level().purpurConfig.snowGolemSnowBallModifier)); // Purpur
|
|
this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D, 1.0000001E-5F));
|
|
this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F));
|
|
this.goalSelector.addGoal(4, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Mob.class, 10, true, false, (entityliving, worldserver) -> {
|
|
return entityliving instanceof Enemy;
|
|
}));
|
|
@@ -80,6 +120,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
|
|
public void addAdditionalSaveData(CompoundTag nbt) {
|
|
super.addAdditionalSaveData(nbt);
|
|
nbt.putBoolean("Pumpkin", this.hasPumpkin());
|
|
+ if (getSummoner() != null) nbt.putUUID("Purpur.Summoner", getSummoner()); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -88,12 +129,13 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
|
|
if (nbt.contains("Pumpkin")) {
|
|
this.setPumpkin(nbt.getBoolean("Pumpkin"));
|
|
}
|
|
+ if (nbt.contains("Purpur.Summoner")) setSummoner(nbt.getUUID("Purpur.Summoner")); // Purpur
|
|
|
|
}
|
|
|
|
@Override
|
|
public boolean isSensitiveToWater() {
|
|
- return true;
|
|
+ return this.level().purpurConfig.snowGolemTakeDamageFromWater; // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -106,10 +148,11 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
|
|
this.hurtServer(worldserver, this.damageSources().melting(), 1.0F); // CraftBukkit - DamageSources.ON_FIRE -> CraftEventFactory.MELTING
|
|
}
|
|
|
|
- if (!worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
|
+ if (!worldserver.purpurConfig.snowGolemBypassMobGriefing && !worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur
|
|
return;
|
|
}
|
|
|
|
+ if (getRider() != null && this.isControllable() && !level().purpurConfig.snowGolemLeaveTrailWhenRidden) return; // Purpur - don't leave snow trail when being ridden
|
|
BlockState iblockdata = Blocks.SNOW.defaultBlockState();
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
@@ -166,7 +209,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
|
|
org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops);
|
|
if (event != null) {
|
|
if (event.isCancelled()) {
|
|
- return InteractionResult.PASS;
|
|
+ return tryRide(player, hand); // Purpur
|
|
}
|
|
drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops());
|
|
// Paper end - custom shear drops
|
|
@@ -178,8 +221,16 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
|
|
}
|
|
|
|
return InteractionResult.SUCCESS;
|
|
+ // Purpur start
|
|
+ } else if (level().purpurConfig.snowGolemPutPumpkinBack && !hasPumpkin() && itemstack.getItem() == Blocks.CARVED_PUMPKIN.asItem()) {
|
|
+ setPumpkin(true);
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ itemstack.shrink(1);
|
|
+ }
|
|
+ return InteractionResult.SUCCESS;
|
|
+ // Purpur end
|
|
} else {
|
|
- return InteractionResult.PASS;
|
|
+ return tryRide(player, hand); // Purpur
|
|
}
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java
|
|
index f9fdc600dc680c55219fcbf9bc8f151a733a093c..36a56553702fa6e4a2ac92b3639c210c94faee73 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Squid.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java
|
|
@@ -46,13 +46,67 @@ public class Squid extends AgeableWaterCreature {
|
|
|
|
public Squid(EntityType<? extends Squid> type, Level world) {
|
|
super(type, world);
|
|
- //this.random.setSeed((long)this.getId()); // Paper - Share random for entities to make them more random
|
|
+ if (!world.purpurConfig.entitySharedRandom) this.random.setSeed((long)this.getId()); // Paper - Share random for entities to make them more random // Purpur
|
|
this.tentacleSpeed = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.squidRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.squidControllable;
|
|
+ }
|
|
+
|
|
+ protected void rotateVectorAroundY(org.bukkit.util.Vector vector, double degrees) {
|
|
+ double rad = Math.toRadians(degrees);
|
|
+ double cos = Math.cos(rad);
|
|
+ double sine = Math.sin(rad);
|
|
+ double x = vector.getX();
|
|
+ double z = vector.getZ();
|
|
+ vector.setX(cos * x - sine * z);
|
|
+ vector.setZ(sine * x + cos * z);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.squidMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.squidScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public net.minecraft.world.phys.AABB getAxisForFluidCheck() {
|
|
+ // Stops squids from floating just over the water
|
|
+ return super.getAxisForFluidCheck().offsetY(level().purpurConfig.squidOffsetWaterCheck);
|
|
+ }
|
|
+
|
|
+ public boolean canFly() {
|
|
+ return this.level().purpurConfig.squidsCanFly;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isInWater() {
|
|
+ return this.wasTouchingWater || canFly();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.squidTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.squidAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new Squid.SquidFleeGoal());
|
|
}
|
|
|
|
@@ -127,6 +181,7 @@ public class Squid extends AgeableWaterCreature {
|
|
}
|
|
|
|
if (this.isInWaterOrBubble()) {
|
|
+ if (canFly()) setNoGravity(!wasTouchingWater); // Purpur
|
|
if (this.tentacleMovement < (float) Math.PI) {
|
|
float f = this.tentacleMovement / (float) Math.PI;
|
|
this.tentacleAngle = Mth.sin(f * f * (float) Math.PI) * (float) Math.PI * 0.25F;
|
|
@@ -305,10 +360,41 @@ public class Squid extends AgeableWaterCreature {
|
|
|
|
@Override
|
|
public void tick() {
|
|
+ // Purpur start
|
|
+ net.minecraft.world.entity.player.Player rider = squid.getRider();
|
|
+ if (rider != null && squid.isControllable()) {
|
|
+ if (rider.jumping) {
|
|
+ squid.onSpacebar();
|
|
+ }
|
|
+ float forward = rider.getForwardMot();
|
|
+ float strafe = rider.getStrafeMot();
|
|
+ float speed = (float) squid.getAttributeValue(Attributes.MOVEMENT_SPEED) * 10F;
|
|
+ if (forward < 0.0F) {
|
|
+ speed *= -0.5;
|
|
+ }
|
|
+ org.bukkit.util.Vector dir = rider.getBukkitEntity().getEyeLocation().getDirection().normalize().multiply(speed / 20.0F);
|
|
+ if (strafe != 0.0F) {
|
|
+ if (forward == 0.0F) {
|
|
+ dir.setY(0);
|
|
+ rotateVectorAroundY(dir, strafe > 0.0F ? -90 : 90);
|
|
+ } else if (forward < 0.0F) {
|
|
+ rotateVectorAroundY(dir, strafe > 0.0F ? 45 : -45);
|
|
+ } else {
|
|
+ rotateVectorAroundY(dir, strafe > 0.0F ? -45 : 45);
|
|
+ }
|
|
+ }
|
|
+ if (forward != 0.0F || strafe != 0.0F) {
|
|
+ squid.movementVector = new Vec3((float) dir.getX(), (float) dir.getY(), (float) dir.getZ());
|
|
+ } else {
|
|
+ squid.movementVector = Vec3.ZERO;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+ // Purpur end
|
|
int i = this.squid.getNoActionTime();
|
|
if (i > 100) {
|
|
this.squid.movementVector = Vec3.ZERO;
|
|
- } else if (this.squid.getRandom().nextInt(reducedTickDelay(50)) == 0 || !this.squid.wasTouchingWater || !this.squid.hasMovementVector()) {
|
|
+ } else if (this.squid.getRandom().nextInt(reducedTickDelay(50)) == 0 || !this.squid.isInWater() || !this.squid.hasMovementVector()) { // Purpur
|
|
float f = this.squid.getRandom().nextFloat() * (float) (Math.PI * 2);
|
|
this.squid.movementVector = new Vec3(
|
|
(double)(Mth.cos(f) * 0.2F), (double)(-0.1F + this.squid.getRandom().nextFloat() * 0.2F), (double)(Mth.sin(f) * 0.2F)
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java
|
|
index 8d59d606bdaaea7c64389572b2810b65414a1533..7f9d3177285f6496c4313da63f0fd0cc78266586 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java
|
|
@@ -67,6 +67,33 @@ public class TropicalFish extends AbstractSchoolingFish implements VariantHolder
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.tropicalFishRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.tropicalFishControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.tropicalFishMaxHealth);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.tropicalFishTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.tropicalFishAlwaysDropExp;
|
|
+ }
|
|
+
|
|
public static String getPredefinedName(int variant) {
|
|
return "entity.minecraft.tropical_fish.predefined." + variant;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
|
index d6605c15111dbdb6ee61a24822bc0a9aed7198d6..c9e307452a097329c26893673055cfb72a43e4c7 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
|
@@ -86,6 +86,44 @@ public class Turtle extends Animal {
|
|
this.moveControl = new Turtle.TurtleMoveControl(this);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.turtleRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.turtleRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.turtleControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.turtleMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.turtleScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.turtleBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.turtleTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.turtleAlwaysDropExp;
|
|
+ }
|
|
+
|
|
public void setHomePos(BlockPos pos) {
|
|
this.entityData.set(Turtle.HOME_POS, pos);
|
|
}
|
|
@@ -188,6 +226,7 @@ public class Turtle extends Animal {
|
|
|
|
@Override
|
|
protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(0, new Turtle.TurtlePanicGoal(this, 1.2D));
|
|
this.goalSelector.addGoal(1, new Turtle.TurtleBreedGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(1, new Turtle.TurtleLayEggGoal(this, 1.0D));
|
|
@@ -349,13 +388,15 @@ public class Turtle extends Animal {
|
|
return this.isBaby() ? Turtle.BABY_DIMENSIONS : super.getDefaultDimensions(pose);
|
|
}
|
|
|
|
- private static class TurtleMoveControl extends MoveControl {
|
|
+ private static class TurtleMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur
|
|
|
|
private final Turtle turtle;
|
|
+ private final org.purpurmc.purpur.controller.WaterMoveControllerWASD waterController; // Purpur
|
|
|
|
TurtleMoveControl(Turtle turtle) {
|
|
super(turtle);
|
|
this.turtle = turtle;
|
|
+ waterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(turtle, 0.25D); // Purpur
|
|
}
|
|
|
|
private void updateSpeed() {
|
|
@@ -375,7 +416,7 @@ public class Turtle extends Animal {
|
|
}
|
|
|
|
@Override
|
|
- public void tick() {
|
|
+ public void vanillaTick() { // Purpur
|
|
this.updateSpeed();
|
|
if (this.operation == MoveControl.Operation.MOVE_TO && !this.turtle.getNavigation().isDone()) {
|
|
double d0 = this.wantedX - this.turtle.getX();
|
|
@@ -391,7 +432,7 @@ public class Turtle extends Animal {
|
|
|
|
this.turtle.setYRot(this.rotlerp(this.turtle.getYRot(), f, 90.0F));
|
|
this.turtle.yBodyRot = this.turtle.getYRot();
|
|
- float f1 = (float) (this.speedModifier * this.turtle.getAttributeValue(Attributes.MOVEMENT_SPEED));
|
|
+ float f1 = (float) (this.getSpeedModifier() * this.turtle.getAttributeValue(Attributes.MOVEMENT_SPEED));
|
|
|
|
this.turtle.setSpeed(Mth.lerp(0.125F, this.turtle.getSpeed(), f1));
|
|
this.turtle.setDeltaMovement(this.turtle.getDeltaMovement().add(0.0D, (double) this.turtle.getSpeed() * d1 * 0.1D, 0.0D));
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
|
|
index 8c4532a250f8679d729a35c17e9b5bd339264450..2b8336bd88641cfb29e94c8f01abfbdb39938bf3 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
|
|
@@ -74,6 +74,6 @@ public abstract class WaterAnimal extends PathfinderMob {
|
|
i = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(i);
|
|
j = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(j);
|
|
// Paper end - Make water animal spawn height configurable
|
|
- return pos.getY() >= j && pos.getY() <= i && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER);
|
|
+ return ((reason == EntitySpawnReason.SPAWNER && world.getMinecraftWorld().purpurConfig.spawnerFixMC238526) || (pos.getY() >= j && pos.getY() <= i)) && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER); // Purpur
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java
|
|
index fc19bd326f00d1e8bd08ef6cc430c555337a6e3d..499e3294f8dd19fb3802f521cb7d24d0998c8aeb 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java
|
|
@@ -103,6 +103,37 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Hol
|
|
|
|
return entitytypes == EntityType.SHEEP || entitytypes == EntityType.RABBIT || entitytypes == EntityType.FOX;
|
|
};
|
|
+ // Purpur start - rabid wolf spawn chance
|
|
+ private boolean isRabid = false;
|
|
+ private static final TargetingConditions.Selector RABID_PREDICATE = (entity, ignored) -> entity instanceof net.minecraft.server.level.ServerPlayer || entity instanceof net.minecraft.world.entity.Mob;
|
|
+ private final net.minecraft.world.entity.ai.goal.Goal PATHFINDER_VANILLA = new NonTameRandomTargetGoal<>(this, Animal.class, false, PREY_SELECTOR);
|
|
+ private final net.minecraft.world.entity.ai.goal.Goal PATHFINDER_RABID = new NonTameRandomTargetGoal<>(this, LivingEntity.class, false, RABID_PREDICATE);
|
|
+ private static final class AvoidRabidWolfGoal extends AvoidEntityGoal<Wolf> {
|
|
+ private final Wolf wolf;
|
|
+
|
|
+ public AvoidRabidWolfGoal(Wolf wolf, float distance, double minSpeed, double maxSpeed) {
|
|
+ super(wolf, Wolf.class, distance, minSpeed, maxSpeed);
|
|
+ this.wolf = wolf;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canUse() {
|
|
+ return super.canUse() && !this.wolf.isRabid() && this.toAvoid != null && this.toAvoid.isRabid(); // wolves which are not rabid run away from rabid wolves
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void start() {
|
|
+ this.wolf.setTarget(null);
|
|
+ super.start();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ this.wolf.setTarget(null);
|
|
+ super.tick();
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
private static final float START_HEALTH = 8.0F;
|
|
private static final float TAME_HEALTH = 40.0F;
|
|
private static final float ARMOR_REPAIR_UNIT = 0.125F;
|
|
@@ -124,12 +155,87 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Hol
|
|
this.setPathfindingMalus(PathType.DANGER_POWDER_SNOW, -1.0F);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.wolfRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.wolfRidableInWater;
|
|
+ }
|
|
+
|
|
+ public void onMount(Player rider) {
|
|
+ super.onMount(rider);
|
|
+ setInSittingPose(false);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.wolfControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.wolfMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.wolfScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.wolfBreedingTicks;
|
|
+ }
|
|
+
|
|
+ public boolean isRabid() {
|
|
+ return this.isRabid;
|
|
+ }
|
|
+
|
|
+ public void setRabid(boolean isRabid) {
|
|
+ this.isRabid = isRabid;
|
|
+ updatePathfinders(true);
|
|
+ }
|
|
+
|
|
+ public void updatePathfinders(boolean modifyEffects) {
|
|
+ this.targetSelector.removeGoal(PATHFINDER_VANILLA);
|
|
+ this.targetSelector.removeGoal(PATHFINDER_RABID);
|
|
+ if (this.isRabid) {
|
|
+ setOwnerUUID(null);
|
|
+ setTame(false, true);
|
|
+ this.targetSelector.addGoal(5, PATHFINDER_RABID);
|
|
+ if (modifyEffects) this.addEffect(new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.CONFUSION, 1200));
|
|
+ } else {
|
|
+ this.targetSelector.addGoal(5, PATHFINDER_VANILLA);
|
|
+ this.stopBeingAngry();
|
|
+ if (modifyEffects) this.removeEffect(net.minecraft.world.effect.MobEffects.CONFUSION);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void tame(Player player) {
|
|
+ setCollarColor(level().purpurConfig.wolfDefaultCollarColor);
|
|
+ super.tame(player);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.wolfTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.wolfAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(1, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new TamableAnimal.TamableAnimalPanicGoal(1.5D, DamageTypeTags.PANIC_ENVIRONMENTAL_CAUSES));
|
|
this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this));
|
|
this.goalSelector.addGoal(3, new Wolf.WolfAvoidEntityGoal<>(this, Llama.class, 24.0F, 1.5D, 1.5D));
|
|
+ this.goalSelector.addGoal(3, new AvoidRabidWolfGoal(this, 24.0F, 1.5D, 1.5D)); // Purpur
|
|
this.goalSelector.addGoal(4, new LeapAtTargetGoal(this, 0.4F));
|
|
this.goalSelector.addGoal(5, new MeleeAttackGoal(this, 1.0D, true));
|
|
this.goalSelector.addGoal(6, new FollowOwnerGoal(this, 1.0D, 10.0F, 2.0F));
|
|
@@ -138,11 +244,12 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Hol
|
|
this.goalSelector.addGoal(9, new BegGoal(this, 8.0F));
|
|
this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Player.class, 8.0F));
|
|
this.goalSelector.addGoal(10, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new OwnerHurtByTargetGoal(this));
|
|
this.targetSelector.addGoal(2, new OwnerHurtTargetGoal(this));
|
|
this.targetSelector.addGoal(3, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers());
|
|
this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt));
|
|
- this.targetSelector.addGoal(5, new NonTameRandomTargetGoal<>(this, Animal.class, false, Wolf.PREY_SELECTOR));
|
|
+ // this.targetSelector.addGoal(5, new NonTameRandomTargetGoal<>(this, Animal.class, false, Wolf.PREY_SELECTOR)); // Purpur - moved to updatePathfinders()
|
|
this.targetSelector.addGoal(6, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR));
|
|
this.targetSelector.addGoal(7, new NearestAttackableTargetGoal<>(this, AbstractSkeleton.class, false));
|
|
this.targetSelector.addGoal(8, new ResetUniversalAngerTargetGoal<>(this, true));
|
|
@@ -191,6 +298,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Hol
|
|
public void addAdditionalSaveData(CompoundTag nbt) {
|
|
super.addAdditionalSaveData(nbt);
|
|
nbt.putByte("CollarColor", (byte) this.getCollarColor().getId());
|
|
+ nbt.putBoolean("Purpur.IsRabid", this.isRabid); // Purpur
|
|
this.getVariant().unwrapKey().ifPresent((resourcekey) -> {
|
|
nbt.putString("variant", resourcekey.location().toString());
|
|
});
|
|
@@ -208,6 +316,10 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Hol
|
|
if (nbt.contains("CollarColor", 99)) {
|
|
this.setCollarColor(DyeColor.byId(nbt.getInt("CollarColor")));
|
|
}
|
|
+ // Purpur start
|
|
+ this.isRabid = nbt.getBoolean("Purpur.IsRabid");
|
|
+ this.updatePathfinders(false);
|
|
+ // Purpur end
|
|
|
|
this.readPersistentAngerSaveData(this.level(), nbt);
|
|
}
|
|
@@ -226,6 +338,12 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Hol
|
|
}
|
|
|
|
this.setVariant(holder1);
|
|
+
|
|
+ // Purpur start
|
|
+ this.isRabid = world.getLevel().purpurConfig.wolfNaturalRabid > 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.wolfNaturalRabid;
|
|
+ this.updatePathfinders(false);
|
|
+ // Purpur end
|
|
+
|
|
return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData);
|
|
}
|
|
|
|
@@ -269,6 +387,11 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Hol
|
|
public void tick() {
|
|
super.tick();
|
|
if (this.isAlive()) {
|
|
+ // Purpur start
|
|
+ if (this.age % 300 == 0 && this.isRabid()) {
|
|
+ this.addEffect(new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.CONFUSION, 400));
|
|
+ }
|
|
+ // Purpur end
|
|
this.interestedAngleO = this.interestedAngle;
|
|
if (this.isInterested()) {
|
|
this.interestedAngle += (1.0F - this.interestedAngle) * 0.4F;
|
|
@@ -499,6 +622,19 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Hol
|
|
itemstack.consume(1, player);
|
|
this.tryToTame(player);
|
|
return InteractionResult.SUCCESS_SERVER;
|
|
+ // Purpur start
|
|
+ } else if (this.level().purpurConfig.wolfMilkCuresRabies && itemstack.getItem() == Items.MILK_BUCKET && this.isRabid()) {
|
|
+ if (!player.isCreative()) {
|
|
+ player.setItemInHand(hand, new ItemStack(Items.BUCKET));
|
|
+ }
|
|
+ this.setRabid(false);
|
|
+ for (int i = 0; i < 10; ++i) {
|
|
+ ((ServerLevel) level()).sendParticles(((ServerLevel) level()).players(), null, ParticleTypes.HAPPY_VILLAGER,
|
|
+ getX() + random.nextFloat(), getY() + (random.nextFloat() * 1.5), getZ() + random.nextFloat(), 1,
|
|
+ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0, true);
|
|
+ }
|
|
+ return InteractionResult.SUCCESS_SERVER;
|
|
+ // Purpur end
|
|
} else {
|
|
return super.mobInteract(player, hand);
|
|
}
|
|
@@ -506,7 +642,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Hol
|
|
|
|
private void tryToTame(Player player) {
|
|
// CraftBukkit - added event call and isCancelled check.
|
|
- if (this.random.nextInt(3) == 0 && !CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) {
|
|
+ if ((this.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials()) || this.random.nextInt(3) == 0 && !CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) {
|
|
this.tame(player);
|
|
this.navigation.stop();
|
|
this.setTarget((LivingEntity) null);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java b/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java
|
|
index 05c3d43fafc781e2c2d762dd5f509753df8da3b3..f60961bd5fdf6d1417e458b92e311c1a0a62463d 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java
|
|
@@ -104,10 +104,23 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS
|
|
private float spinningAnimationTicks;
|
|
private float spinningAnimationTicks0;
|
|
public boolean forceDancing = false; // CraftBukkit
|
|
+ private org.purpurmc.purpur.controller.FlyingMoveControllerWASD purpurController; // Purpur
|
|
|
|
public Allay(EntityType<? extends Allay> type, Level world) {
|
|
super(type, world);
|
|
- this.moveControl = new FlyingMoveControl(this, 20, true);
|
|
+ // Purpur start
|
|
+ this.purpurController = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this, 0.1F, 0.5F);
|
|
+ this.moveControl = new FlyingMoveControl(this, 20, true) {
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ if (mob.getRider() != null && mob.isControllable()) {
|
|
+ purpurController.purpurTick(mob.getRider());
|
|
+ } else {
|
|
+ super.tick();
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+ // Purpur end
|
|
this.setCanPickUpLoot(this.canPickUpLoot());
|
|
this.vibrationUser = new Allay.VibrationUser();
|
|
this.vibrationData = new VibrationSystem.Data();
|
|
@@ -121,6 +134,34 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS
|
|
}
|
|
// CraftBukkit end
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.allayRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.allayRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.allayControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.allayMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.allayScale);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected Brain.Provider<Allay> brainProvider() {
|
|
return Brain.provider(Allay.MEMORY_TYPES, Allay.SENSOR_TYPES);
|
|
@@ -221,14 +262,15 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("allayBrain");
|
|
+ //gameprofilerfiller.push("allayBrain"); // Purpur
|
|
+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish
|
|
this.getBrain().tick(world, this);
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("allayActivityUpdate");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("allayActivityUpdate"); // Purpur
|
|
AllayAi.updateActivity(this);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
super.customServerAiStep(world);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java
|
|
index c1ef714096159608752d744b98f615cd45fe459a..84516dcfc6cd0fe16c26538ccb86fb5c85b44ffa 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java
|
|
@@ -82,6 +82,34 @@ public class Armadillo extends Animal {
|
|
return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 12.0D).add(Attributes.MOVEMENT_SPEED, 0.14D);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.armadilloRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.armadilloRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.armadilloControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.armadilloMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.armadilloScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.armadilloBreedingTicks;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
|
super.defineSynchedData(builder);
|
|
@@ -135,14 +163,14 @@ public class Armadillo extends Animal {
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("armadilloBrain");
|
|
+ //gameprofilerfiller.push("armadilloBrain"); // Purpur
|
|
((Brain<Armadillo>) this.brain).tick(world, this); // CraftBukkit - decompile error
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("armadilloActivityUpdate");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("armadilloActivityUpdate"); // Purpur
|
|
ArmadilloAi.updateActivity(this);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
if (this.isAlive() && !this.isBaby() && --this.scuteTime <= 0) {
|
|
this.forceDrops = true; // CraftBukkit
|
|
if (this.dropFromGiftLootTable(world, BuiltInLootTables.ARMADILLO_SHED, this::spawnAtLocation)) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java
|
|
index 31b10cd404b672d7ce21c2107d8f83e32de26ef4..c80d74caa393a31e09f2776cdb3cb950ef99e2ef 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java
|
|
@@ -100,6 +100,44 @@ public class Axolotl extends Animal implements VariantHolder<Axolotl.Variant>, B
|
|
this.lookControl = new Axolotl.AxolotlLookControl(this, 20);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.axolotlRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.axolotlControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.axolotlMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.axolotlScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.axolotlBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.axolotlTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.axolotlAlwaysDropExp;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public float getWalkTargetValue(BlockPos pos, LevelReader world) {
|
|
return 0.0F;
|
|
@@ -294,14 +332,15 @@ public class Axolotl extends Animal implements VariantHolder<Axolotl.Variant>, B
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("axolotlBrain");
|
|
+ //gameprofilerfiller.push("axolotlBrain"); // Purpur
|
|
+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish
|
|
this.getBrain().tick(world, this);
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("axolotlActivityUpdate");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("axolotlActivityUpdate"); // Purpur
|
|
AxolotlAi.updateActivity(this);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
if (!this.isNoAi()) {
|
|
Optional<Integer> optional = this.getBrain().getMemory(MemoryModuleType.PLAY_DEAD_TICKS);
|
|
|
|
@@ -520,14 +559,22 @@ public class Axolotl extends Animal implements VariantHolder<Axolotl.Variant>, B
|
|
private static class AxolotlMoveControl extends SmoothSwimmingMoveControl {
|
|
|
|
private final Axolotl axolotl;
|
|
+ private final org.purpurmc.purpur.controller.WaterMoveControllerWASD waterController; // Purpur
|
|
|
|
public AxolotlMoveControl(Axolotl axolotl) {
|
|
super(axolotl, 85, 10, 0.1F, 0.5F, false);
|
|
this.axolotl = axolotl;
|
|
+ waterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(axolotl, 0.5D); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
+ // Purpur start
|
|
+ if (axolotl.getRider() != null && axolotl.isControllable()) {
|
|
+ waterController.purpurTick(axolotl.getRider());
|
|
+ return;
|
|
+ }
|
|
+ // Purpur end
|
|
if (!this.axolotl.isPlayingDead()) {
|
|
super.tick();
|
|
}
|
|
@@ -542,9 +589,9 @@ public class Axolotl extends Animal implements VariantHolder<Axolotl.Variant>, B
|
|
}
|
|
|
|
@Override
|
|
- public void tick() {
|
|
+ public void vanillaTick() { // Purpur
|
|
if (!Axolotl.this.isPlayingDead()) {
|
|
- super.tick();
|
|
+ super.vanillaTick(); // Purpur
|
|
}
|
|
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java
|
|
index f3c884ab9c09f04dd01cabf2ee9de3b5b620563d..56d97225a909fd55f0d8aec992d5b6d42687c948 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java
|
|
@@ -87,6 +87,17 @@ public class Camel extends AbstractHorse {
|
|
navigation.setCanWalkOverFences(true);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.camelRidableInWater;
|
|
+ }
|
|
+
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.camelBreedingTicks;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public void addAdditionalSaveData(CompoundTag nbt) {
|
|
super.addAdditionalSaveData(nbt);
|
|
@@ -143,16 +154,16 @@ public class Camel extends AbstractHorse {
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("camelBrain");
|
|
+ //gameprofilerfiller.push("camelBrain"); // Purpur
|
|
Brain<Camel> behaviorcontroller = (Brain<Camel>) this.getBrain(); // CraftBukkit - decompile error
|
|
|
|
behaviorcontroller.tick(world, this);
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("camelActivityUpdate");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("camelActivityUpdate"); // Purpur
|
|
CamelAi.updateActivity(this);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
super.customServerAiStep(world);
|
|
}
|
|
|
|
@@ -314,6 +325,23 @@ public class Camel extends AbstractHorse {
|
|
return this.dashCooldown;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public float generateMaxHealth(net.minecraft.util.RandomSource random) {
|
|
+ return (float) generateMaxHealth(this.level().purpurConfig.camelMaxHealthMin, this.level().purpurConfig.camelMaxHealthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateJumpStrength(net.minecraft.util.RandomSource random) {
|
|
+ return generateJumpStrength(this.level().purpurConfig.camelJumpStrengthMin, this.level().purpurConfig.camelJumpStrengthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateSpeed(net.minecraft.util.RandomSource random) {
|
|
+ return generateSpeed(this.level().purpurConfig.camelMovementSpeedMin, this.level().purpurConfig.camelMovementSpeedMax);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected SoundEvent getAmbientSound() {
|
|
return SoundEvents.CAMEL_AMBIENT;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java
|
|
index 36846ba6b6c7494c745ebd8b221479a9d02ff318..501a12398c56fe0df4e76a3bbce0f98c6c5aa6cb 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java
|
|
@@ -106,6 +106,8 @@ public class Frog extends Animal implements VariantHolder<Holder<FrogVariant>> {
|
|
public final AnimationState croakAnimationState = new AnimationState();
|
|
public final AnimationState tongueAnimationState = new AnimationState();
|
|
public final AnimationState swimIdleAnimationState = new AnimationState();
|
|
+ private org.purpurmc.purpur.controller.MoveControllerWASD purpurLandController; // Purpur
|
|
+ private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurWaterController; // Purpur
|
|
|
|
public Frog(EntityType<? extends Animal> type, Level world) {
|
|
super(type, world);
|
|
@@ -113,6 +115,58 @@ public class Frog extends Animal implements VariantHolder<Holder<FrogVariant>> {
|
|
this.setPathfindingMalus(PathType.WATER, 4.0F);
|
|
this.setPathfindingMalus(PathType.TRAPDOOR, -1.0F);
|
|
this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true);
|
|
+ // Purpur start
|
|
+ this.purpurLandController = new org.purpurmc.purpur.controller.MoveControllerWASD(this, 0.2F);
|
|
+ this.purpurWaterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F);
|
|
+ this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true) {
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ net.minecraft.world.entity.player.Player rider = mob.getRider();
|
|
+ if (rider != null && mob.isControllable()) {
|
|
+ if (mob.isInWater()) {
|
|
+ purpurWaterController.purpurTick(rider);
|
|
+ mob.setDeltaMovement(mob.getDeltaMovement().add(0.0D, -0.005D, 0.0D));
|
|
+ } else {
|
|
+ purpurLandController.purpurTick(rider);
|
|
+ }
|
|
+ } else {
|
|
+ super.tick();
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+ // Purpur end
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.frogRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.frogRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.frogControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public float getJumpPower() {
|
|
+ return (getRider() != null && isControllable()) ? level().purpurConfig.frogRidableJumpHeight * this.getBlockJumpFactor() : super.getJumpPower();
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.frogBreedingTicks;
|
|
}
|
|
|
|
@Override
|
|
@@ -186,13 +240,14 @@ public class Frog extends Animal implements VariantHolder<Holder<FrogVariant>> {
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller profilerFiller = Profiler.get();
|
|
- profilerFiller.push("frogBrain");
|
|
+ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur
|
|
+ //profilerFiller.push("frogBrain"); // Purpur
|
|
+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish
|
|
this.getBrain().tick(world, this);
|
|
- profilerFiller.pop();
|
|
- profilerFiller.push("frogActivityUpdate");
|
|
+ //profilerFiller.pop(); // Purpur
|
|
+ //profilerFiller.push("frogActivityUpdate"); // Purpur
|
|
FrogAi.updateActivity(this);
|
|
- profilerFiller.pop();
|
|
+ //profilerFiller.pop(); // Purpur
|
|
super.customServerAiStep(world);
|
|
}
|
|
|
|
@@ -384,7 +439,7 @@ public class Frog extends Animal implements VariantHolder<Holder<FrogVariant>> {
|
|
return world.getBlockState(pos.below()).is(BlockTags.FROGS_SPAWNABLE_ON) && isBrightEnoughToSpawn(world, pos);
|
|
}
|
|
|
|
- class FrogLookControl extends LookControl {
|
|
+ class FrogLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur
|
|
FrogLookControl(final Mob entity) {
|
|
super(entity);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java
|
|
index 48ac8c3f6e00c3c2dc67b6c994be7c0ac6dfcf81..071d14cc6697587ec14f02c69c78df364e7d8a8f 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java
|
|
@@ -51,13 +51,50 @@ public class Tadpole extends AbstractFish {
|
|
protected static final ImmutableList<SensorType<? extends Sensor<? super Tadpole>>> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS, SensorType.HURT_BY, SensorType.FROG_TEMPTATIONS);
|
|
protected static final ImmutableList<MemoryModuleType<?>> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.LOOK_TARGET, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.NEAREST_VISIBLE_ADULT, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryModuleType.IS_TEMPTED, MemoryModuleType.TEMPTING_PLAYER, MemoryModuleType.BREED_TARGET, MemoryModuleType.IS_PANICKING);
|
|
public boolean ageLocked; // Paper
|
|
+ private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurController; // Purpur
|
|
|
|
public Tadpole(EntityType<? extends AbstractFish> type, Level world) {
|
|
super(type, world);
|
|
- this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true);
|
|
+ // Purpur start
|
|
+ this.purpurController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F);
|
|
+ this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true) {
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ Player rider = mob.getRider();
|
|
+ if (rider != null && mob.isControllable()) {
|
|
+ purpurController.purpurTick(rider);
|
|
+ mob.setDeltaMovement(mob.getDeltaMovement().add(0.0D, 0.002D, 0.0D));
|
|
+ } else {
|
|
+ super.tick();
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+ // Purpur end
|
|
this.lookControl = new SmoothSwimmingLookControl(this, 10);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.tadpoleRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.tadpoleRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.tadpoleControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected PathNavigation createNavigation(Level world) {
|
|
return new WaterBoundPathNavigation(this, world);
|
|
@@ -85,14 +122,15 @@ public class Tadpole extends AbstractFish {
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
|
|
- gameprofilerfiller.push("tadpoleBrain");
|
|
+ //gameprofilerfiller.push("tadpoleBrain"); // Purpur
|
|
+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // // Purpur - TODO: Pufferfish
|
|
this.getBrain().tick(world, this);
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("tadpoleActivityUpdate");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("tadpoleActivityUpdate"); // Purpur
|
|
TadpoleAi.updateActivity(this);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
super.customServerAiStep(world);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java
|
|
index 76aca47d8638d5c37c57d3a59fa7f8ceaa5a53b4..ebf53d48b09918c7453f982a5e4f9a1584dfc544 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java
|
|
@@ -93,6 +93,38 @@ public class Goat extends Animal {
|
|
});
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.goatRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.goatRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.goatControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.goatBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.goatTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.goatAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected Brain.Provider<Goat> brainProvider() {
|
|
return Brain.provider(Goat.MEMORY_TYPES, Goat.SENSOR_TYPES);
|
|
@@ -194,14 +226,15 @@ public class Goat extends Animal {
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("goatBrain");
|
|
+ //gameprofilerfiller.push("goatBrain"); // Purpur
|
|
+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish
|
|
this.getBrain().tick(world, this);
|
|
- gameprofilerfiller.pop();
|
|
- gameprofilerfiller.push("goatActivityUpdate");
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
+ //gameprofilerfiller.push("goatActivityUpdate"); // Purpur
|
|
GoatAi.updateActivity(this);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
super.customServerAiStep(world);
|
|
}
|
|
|
|
@@ -399,6 +432,7 @@ public class Goat extends Animal {
|
|
|
|
// Paper start - Goat ram API
|
|
public void ram(net.minecraft.world.entity.LivingEntity entity) {
|
|
+ if(!new org.purpurmc.purpur.event.entity.GoatRamEntityEvent((org.bukkit.entity.Goat) getBukkitEntity(), (org.bukkit.entity.LivingEntity) entity.getBukkitLivingEntity()).callEvent()) return; // Purpur
|
|
Brain<Goat> brain = this.getBrain();
|
|
brain.setMemory(MemoryModuleType.RAM_TARGET, entity.position());
|
|
brain.eraseMemory(MemoryModuleType.RAM_COOLDOWN_TICKS);
|
|
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 8aed30cdbbfdd42c20dcd4c8773c8a0ee21a980d..b258be16f32ffd58ac8406deac9423cb01ca9a5c 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
|
|
@@ -228,11 +228,59 @@ public abstract class AbstractHorse extends Animal implements ContainerListener,
|
|
|
|
protected AbstractHorse(EntityType<? extends AbstractHorse> type, Level world) {
|
|
super(type, world);
|
|
+ this.moveControl = new net.minecraft.world.entity.ai.control.MoveControl(this); // Purpur - use vanilla controller
|
|
+ this.lookControl = new net.minecraft.world.entity.ai.control.LookControl(this); // Purpur - use vanilla controller
|
|
this.createInventory();
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return false; // vanilla handles
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.generateMaxHealth(random));
|
|
+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.generateSpeed(random));
|
|
+ this.getAttribute(Attributes.JUMP_STRENGTH).setBaseValue(this.generateJumpStrength(random));
|
|
+ }
|
|
+
|
|
+ protected double generateMaxHealth(double min, double max) {
|
|
+ if (min == max) return min;
|
|
+ int diff = Mth.floor(max - min);
|
|
+ double base = max - diff;
|
|
+ int first = Mth.floor((double) diff / 2);
|
|
+ int rest = diff - first;
|
|
+ return base + random.nextInt(first + 1) + random.nextInt(rest + 1);
|
|
+ }
|
|
+
|
|
+ protected double generateJumpStrength(double min, double max) {
|
|
+ if (min == max) return min;
|
|
+ return min + (max - min) * this.random.nextDouble();
|
|
+ }
|
|
+
|
|
+ protected double generateSpeed(double min, double max) {
|
|
+ if (min == max) return min;
|
|
+ return min + (max - min) * this.random.nextDouble();
|
|
+ }
|
|
+
|
|
+ protected float generateMaxHealth(RandomSource random) {
|
|
+ return 15.0F + (float) random.nextInt(8) + (float) random.nextInt(9);
|
|
+ }
|
|
+
|
|
+ protected double generateJumpStrength(RandomSource random) {
|
|
+ return 0.4000000059604645D + random.nextDouble() * 0.2D + random.nextDouble() * 0.2D + random.nextDouble() * 0.2D;
|
|
+ }
|
|
+
|
|
+ protected double generateSpeed(RandomSource random) {
|
|
+ return (0.44999998807907104D + random.nextDouble() * 0.3D + random.nextDouble() * 0.3D + random.nextDouble() * 0.3D) * 0.25D;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new PanicGoal(this, 1.2D));
|
|
this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2D));
|
|
this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D, AbstractHorse.class));
|
|
@@ -243,6 +291,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener,
|
|
if (this.canPerformRearing()) {
|
|
this.goalSelector.addGoal(9, new RandomStandGoal(this));
|
|
}
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur
|
|
|
|
this.addBehaviourGoals();
|
|
}
|
|
@@ -1269,7 +1318,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener,
|
|
entityData = new AgeableMob.AgeableMobGroupData(0.2F);
|
|
}
|
|
|
|
- this.randomizeAttributes(world.getRandom());
|
|
+ // this.randomizeAttributes(world.getRandom()); // Purpur - replaced by initAttributes()
|
|
return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java
|
|
index 5cafdde956d7a5b00cd5aec5c44849639307363d..dbf9fa551023cc9bf634fd5f5d504c4d689264cd 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java
|
|
@@ -16,6 +16,43 @@ public class Donkey extends AbstractChestedHorse {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.donkeyRidableInWater;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public float generateMaxHealth(net.minecraft.util.RandomSource random) {
|
|
+ return (float) generateMaxHealth(this.level().purpurConfig.donkeyMaxHealthMin, this.level().purpurConfig.donkeyMaxHealthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateJumpStrength(net.minecraft.util.RandomSource random) {
|
|
+ return generateJumpStrength(this.level().purpurConfig.donkeyJumpStrengthMin, this.level().purpurConfig.donkeyJumpStrengthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateSpeed(net.minecraft.util.RandomSource random) {
|
|
+ return generateSpeed(this.level().purpurConfig.donkeyMovementSpeedMin, this.level().purpurConfig.donkeyMovementSpeedMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.donkeyBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.donkeyTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.donkeyAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected SoundEvent getAmbientSound() {
|
|
return SoundEvents.DONKEY_AMBIENT;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java
|
|
index b5ec7c8ad0e482930d1a54b590b26093f4e477ea..780cad91fff78bda6264cfd78ff7a408a79e8a2f 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java
|
|
@@ -43,6 +43,43 @@ public class Horse extends AbstractHorse implements VariantHolder<Variant> {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.horseRidableInWater;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public float generateMaxHealth(RandomSource random) {
|
|
+ return (float) generateMaxHealth(this.level().purpurConfig.horseMaxHealthMin, this.level().purpurConfig.horseMaxHealthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateJumpStrength(RandomSource random) {
|
|
+ return generateJumpStrength(this.level().purpurConfig.horseJumpStrengthMin, this.level().purpurConfig.horseJumpStrengthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateSpeed(RandomSource random) {
|
|
+ return generateSpeed(this.level().purpurConfig.horseMovementSpeedMin, this.level().purpurConfig.horseMovementSpeedMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.horseBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.horseTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.horseAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void randomizeAttributes(RandomSource random) {
|
|
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue((double)generateMaxHealth(random::nextInt));
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java
|
|
index 18bd483fe46de3d9dc129bffbccfba9d4cab9550..8401c7ae749f6300281cbd6b2bfc77f03d5eb9ea 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
|
|
@@ -72,11 +72,86 @@ public class Llama extends AbstractChestedHorse implements VariantHolder<Llama.V
|
|
private Llama caravanHead;
|
|
@Nullable
|
|
public Llama caravanTail; // Paper
|
|
+ public boolean shouldJoinCaravan = true; // Purpur
|
|
|
|
public Llama(EntityType<? extends Llama> type, Level world) {
|
|
super(type, world);
|
|
this.getNavigation().setRequiredPathLength(40.0F);
|
|
this.maxDomestication = 30; // Paper - Missing entity API; configure max temper instead of a hardcoded value
|
|
+ // Purpur start
|
|
+ this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this) {
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ if (entity.getRider() != null && entity.isControllable() && isSaddled()) {
|
|
+ purpurTick(entity.getRider());
|
|
+ } else {
|
|
+ vanillaTick();
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+ this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this) {
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ if (entity.getRider() != null && entity.isControllable() && isSaddled()) {
|
|
+ purpurTick(entity.getRider());
|
|
+ } else {
|
|
+ vanillaTick();
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+ // Purpur end
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.llamaRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.llamaRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.llamaControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSaddled() {
|
|
+ return super.isSaddled() || (isTamed());
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public float generateMaxHealth(RandomSource random) {
|
|
+ return (float) generateMaxHealth(this.level().purpurConfig.llamaMaxHealthMin, this.level().purpurConfig.llamaMaxHealthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateJumpStrength(RandomSource random) {
|
|
+ return generateJumpStrength(this.level().purpurConfig.llamaJumpStrengthMin, this.level().purpurConfig.llamaJumpStrengthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateSpeed(RandomSource random) {
|
|
+ return generateSpeed(this.level().purpurConfig.llamaMovementSpeedMin, this.level().purpurConfig.llamaMovementSpeedMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.llamaBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.llamaTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.llamaAlwaysDropExp;
|
|
}
|
|
|
|
public boolean isTraderLlama() {
|
|
@@ -107,6 +182,7 @@ public class Llama extends AbstractChestedHorse implements VariantHolder<Llama.V
|
|
super.addAdditionalSaveData(nbt);
|
|
nbt.putInt("Variant", this.getVariant().id);
|
|
nbt.putInt("Strength", this.getStrength());
|
|
+ nbt.putBoolean("Purpur.ShouldJoinCaravan", shouldJoinCaravan); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -114,11 +190,13 @@ public class Llama extends AbstractChestedHorse implements VariantHolder<Llama.V
|
|
this.setStrength(nbt.getInt("Strength"));
|
|
super.readAdditionalSaveData(nbt);
|
|
this.setVariant(Llama.Variant.byId(nbt.getInt("Variant")));
|
|
+ if (nbt.contains("Purpur.ShouldJoinCaravan")) this.shouldJoinCaravan = nbt.getBoolean("Purpur.ShouldJoinCaravan"); // Purpur
|
|
}
|
|
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.LlamaHasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2D));
|
|
this.goalSelector.addGoal(2, new LlamaFollowCaravanGoal(this, 2.0999999046325684D));
|
|
this.goalSelector.addGoal(3, new RangedAttackGoal(this, 1.25D, 40, 20.0F));
|
|
@@ -131,6 +209,7 @@ public class Llama extends AbstractChestedHorse implements VariantHolder<Llama.V
|
|
this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.7D));
|
|
this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 6.0F));
|
|
this.goalSelector.addGoal(9, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.LlamaHasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new Llama.LlamaHurtByTargetGoal(this));
|
|
this.targetSelector.addGoal(2, new Llama.LlamaAttackWolfGoal(this));
|
|
}
|
|
@@ -379,6 +458,7 @@ public class Llama extends AbstractChestedHorse implements VariantHolder<Llama.V
|
|
|
|
public void leaveCaravan() {
|
|
if (this.caravanHead != null) {
|
|
+ new org.purpurmc.purpur.event.entity.LlamaLeaveCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity()).callEvent(); // Purpur
|
|
this.caravanHead.caravanTail = null;
|
|
}
|
|
|
|
@@ -386,6 +466,7 @@ public class Llama extends AbstractChestedHorse implements VariantHolder<Llama.V
|
|
}
|
|
|
|
public void joinCaravan(Llama llama) {
|
|
+ if (!this.level().purpurConfig.llamaJoinCaravans || !shouldJoinCaravan || !new org.purpurmc.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;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Mule.java b/src/main/java/net/minecraft/world/entity/animal/horse/Mule.java
|
|
index b108f34393230c090c3e5797f52aa076135915e4..626a7d6391882bed7778be8c74b39e4de5c7c3c2 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/horse/Mule.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Mule.java
|
|
@@ -15,6 +15,43 @@ public class Mule extends AbstractChestedHorse {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.muleRidableInWater;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public float generateMaxHealth(net.minecraft.util.RandomSource random) {
|
|
+ return (float) generateMaxHealth(this.level().purpurConfig.muleMaxHealthMin, this.level().purpurConfig.muleMaxHealthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateJumpStrength(net.minecraft.util.RandomSource random) {
|
|
+ return generateJumpStrength(this.level().purpurConfig.muleJumpStrengthMin, this.level().purpurConfig.muleJumpStrengthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateSpeed(net.minecraft.util.RandomSource random) {
|
|
+ return generateSpeed(this.level().purpurConfig.muleMovementSpeedMin, this.level().purpurConfig.muleMovementSpeedMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.muleBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.muleTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.muleAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected SoundEvent getAmbientSound() {
|
|
return SoundEvents.MULE_AMBIENT;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonHorse.java
|
|
index 7d0197447990bb79b85a4f1529c3ac3eefb03c84..9307c07b8f75caacbde6839893f54700bf85275a 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonHorse.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonHorse.java
|
|
@@ -42,6 +42,43 @@ public class SkeletonHorse extends AbstractHorse {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isTamed() {
|
|
+ return super.isTamed() || this.level().purpurConfig.skeletonHorseRidable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public float generateMaxHealth(RandomSource random) {
|
|
+ return (float) generateMaxHealth(this.level().purpurConfig.skeletonHorseMaxHealthMin, this.level().purpurConfig.skeletonHorseMaxHealthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateJumpStrength(RandomSource random) {
|
|
+ return generateJumpStrength(this.level().purpurConfig.skeletonHorseJumpStrengthMin, this.level().purpurConfig.skeletonHorseJumpStrengthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateSpeed(RandomSource random) {
|
|
+ return generateSpeed(this.level().purpurConfig.skeletonHorseMovementSpeedMin, this.level().purpurConfig.skeletonHorseMovementSpeedMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return 6000;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.skeletonHorseTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.skeletonHorseAlwaysDropExp;
|
|
+ }
|
|
+
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 15.0D).add(Attributes.MOVEMENT_SPEED, 0.20000000298023224D);
|
|
}
|
|
@@ -59,7 +96,9 @@ public class SkeletonHorse extends AbstractHorse {
|
|
}
|
|
|
|
@Override
|
|
- protected void addBehaviourGoals() {}
|
|
+ protected void addBehaviourGoals() {
|
|
+ if (level().purpurConfig.skeletonHorseCanSwim) goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this));
|
|
+ }
|
|
|
|
@Override
|
|
protected SoundEvent getAmbientSound() {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java b/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java
|
|
index 7b43fcf86984cc200f34c189e7a547996416f379..1d765ad53a9d8dd388106bc0cb02f4919a1f8173 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java
|
|
@@ -33,6 +33,58 @@ public class TraderLlama extends Llama {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.traderLlamaRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.traderLlamaRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.traderLlamaControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSaddled() {
|
|
+ return super.isSaddled() || isTamed();
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public float generateMaxHealth(net.minecraft.util.RandomSource random) {
|
|
+ return (float) generateMaxHealth(this.level().purpurConfig.traderLlamaMaxHealthMin, this.level().purpurConfig.traderLlamaMaxHealthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateJumpStrength(net.minecraft.util.RandomSource random) {
|
|
+ return generateJumpStrength(this.level().purpurConfig.traderLlamaJumpStrengthMin, this.level().purpurConfig.traderLlamaJumpStrengthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateSpeed(net.minecraft.util.RandomSource random) {
|
|
+ return generateSpeed(this.level().purpurConfig.traderLlamaMovementSpeedMin, this.level().purpurConfig.traderLlamaMovementSpeedMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.traderLlamaBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.traderLlamaTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.traderLlamaAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
public boolean isTraderLlama() {
|
|
return true;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/ZombieHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/ZombieHorse.java
|
|
index e89638fc9c87b555651813f615b0ccba10d2a9d0..2b7b0d766ceba4b2261be2d8308170ae795f9cb3 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/horse/ZombieHorse.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/ZombieHorse.java
|
|
@@ -33,6 +33,48 @@ public class ZombieHorse extends AbstractHorse {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieHorseRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isTamed() {
|
|
+ return super.isTamed() || this.level().purpurConfig.zombieHorseRidable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public float generateMaxHealth(RandomSource random) {
|
|
+ return (float) generateMaxHealth(this.level().purpurConfig.zombieHorseMaxHealthMin, this.level().purpurConfig.zombieHorseMaxHealthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateJumpStrength(RandomSource random) {
|
|
+ return generateJumpStrength(this.level().purpurConfig.zombieHorseJumpStrengthMin, this.level().purpurConfig.zombieHorseJumpStrengthMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double generateSpeed(RandomSource random) {
|
|
+ return generateSpeed(this.level().purpurConfig.zombieHorseMovementSpeedMin, this.level().purpurConfig.zombieHorseMovementSpeedMax);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return 6000;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.zombieHorseTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.zombieHorseAlwaysDropExp;
|
|
+ }
|
|
+
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 15.0).add(Attributes.MOVEMENT_SPEED, 0.2F);
|
|
}
|
|
@@ -78,6 +120,7 @@ public class ZombieHorse extends AbstractHorse {
|
|
|
|
@Override
|
|
protected void addBehaviourGoals() {
|
|
+ if (level().purpurConfig.zombieHorseCanSwim) goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java
|
|
index af2f6e690fc51d319b77d081466c2dc7a1d8fe19..3fb4f12095883ea4ec6e0d60e0600b9de6ed7be2 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java
|
|
@@ -90,6 +90,34 @@ public class Sniffer extends Animal {
|
|
this.setPathfindingMalus(PathType.DAMAGE_CAUTIOUS, -1.0F);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.snifferRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.snifferRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.snifferControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.snifferMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.snifferScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.snifferBreedingTicks;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
|
super.defineSynchedData(builder);
|
|
@@ -467,13 +495,13 @@ public class Sniffer extends Animal {
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("snifferBrain");
|
|
+ //gameprofilerfiller.push("snifferBrain"); // Purpur
|
|
this.getBrain().tick(world, this);
|
|
- gameprofilerfiller.popPush("snifferActivityUpdate");
|
|
+ //gameprofilerfiller.popPush("snifferActivityUpdate"); // Purpur
|
|
SnifferAi.updateActivity(this);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
super.customServerAiStep(world);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java b/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java
|
|
index 58f303ce22cba0840a577b09ec5c32b13717fa15..a8830f8434d7c9d1a15ddd403d1ea1dbe530ce54 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java
|
|
@@ -27,6 +27,13 @@ public class EnderDragonPart extends Entity {
|
|
this.name = name;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public net.minecraft.world.InteractionResult interact(net.minecraft.world.entity.player.Player player, net.minecraft.world.InteractionHand hand) {
|
|
+ return parentMob.isAlive() ? parentMob.tryRide(player, hand) : net.minecraft.world.InteractionResult.PASS;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
|
|
index 7cb3d69a69e0e3ef4b7f9f9c8b1eb67edb5d116d..b1db1e92de3a88a0f0e0fdb42b0bf9732095c8a9 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
|
|
@@ -31,6 +31,12 @@ public class EndCrystal extends Entity {
|
|
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);
|
|
@@ -43,6 +49,22 @@ public class EndCrystal extends Entity {
|
|
this.setPos(x, y, z);
|
|
}
|
|
|
|
+ public boolean shouldExplode() {
|
|
+ return showsBottom() ? level().purpurConfig.basedEndCrystalExplode : level().purpurConfig.baselessEndCrystalExplode;
|
|
+ }
|
|
+
|
|
+ public float getExplosionPower() {
|
|
+ return (float) (showsBottom() ? level().purpurConfig.basedEndCrystalExplosionPower : level().purpurConfig.baselessEndCrystalExplosionPower);
|
|
+ }
|
|
+
|
|
+ public boolean hasExplosionFire() {
|
|
+ return showsBottom() ? level().purpurConfig.basedEndCrystalExplosionFire : level().purpurConfig.baselessEndCrystalExplosionFire;
|
|
+ }
|
|
+
|
|
+ public Level.ExplosionInteraction getExplosionEffect() {
|
|
+ return showsBottom() ? level().purpurConfig.basedEndCrystalExplosionEffect : level().purpurConfig.baselessEndCrystalExplosionEffect;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected Entity.MovementEmission getMovementEmission() {
|
|
return Entity.MovementEmission.NONE;
|
|
@@ -80,8 +102,52 @@ public class EndCrystal extends Entity {
|
|
}
|
|
}
|
|
// Paper end - Fix invulnerable end crystals
|
|
+ if (this.level().purpurConfig.endCrystalCramming > 0 && this.level().getEntitiesOfClass(EndCrystal.class, getBoundingBox()).size() > this.level().purpurConfig.endCrystalCramming) this.hurt(this.damageSources().cramming(), 6.0F); // Purpur
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ 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(targetPhantom.damageSources().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
|
|
@@ -128,16 +194,18 @@ public class EndCrystal extends Entity {
|
|
}
|
|
// CraftBukkit end
|
|
if (!source.is(DamageTypeTags.IS_EXPLOSION)) {
|
|
+ if (shouldExplode()) {// Purpur
|
|
DamageSource damagesource1 = source.getEntity() != null ? this.damageSources().explosion(this, source.getEntity()) : null;
|
|
|
|
// CraftBukkit start
|
|
- ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, 6.0F, false);
|
|
+ ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, getExplosionPower(), hasExplosionFire()); // Purpur
|
|
if (event.isCancelled()) {
|
|
return false;
|
|
}
|
|
|
|
this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause
|
|
- world.explode(this, damagesource1, (ExplosionDamageCalculator) null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK);
|
|
+ world.explode(this, damagesource1, (ExplosionDamageCalculator) null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), getExplosionEffect()); // Purpur
|
|
+ } else this.unsetRemoved(); // Purpur
|
|
} else {
|
|
this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
|
index 2df8bf818345246cc1f88b93e4a3b62e61772efb..e0e76b5abdb9650c3c50a3c8b49336977982fe67 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
|
|
@@ -108,6 +108,7 @@ public class EnderDragon extends Mob implements Enemy {
|
|
@Nullable
|
|
private BlockPos podium;
|
|
// Paper end - Allow changing the EnderDragon podium
|
|
+ private boolean hadRider; // Purpur
|
|
|
|
public EnderDragon(EntityType<? extends EnderDragon> entitytypes, Level world) {
|
|
super(EntityType.ENDER_DRAGON, world);
|
|
@@ -129,6 +130,37 @@ public class EnderDragon extends Mob implements Enemy {
|
|
this.noPhysics = true;
|
|
this.phaseManager = new EnderDragonPhaseManager(this);
|
|
this.explosionSource = new ServerExplosion(world.getMinecraftWorld(), this, null, null, new Vec3(Double.NaN, Double.NaN, Double.NaN), Float.NaN, true, Explosion.BlockInteraction.DESTROY); // CraftBukkit
|
|
+
|
|
+ // Purpur start
|
|
+ this.moveControl = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this) {
|
|
+ @Override
|
|
+ public void vanillaTick() {
|
|
+ // dragon doesn't use the controller. do nothing
|
|
+ }
|
|
+ };
|
|
+ this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this) {
|
|
+ @Override
|
|
+ public void vanillaTick() {
|
|
+ // dragon doesn't use the controller. do nothing
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void purpurTick(Player rider) {
|
|
+ setYawPitch(rider.getYRot() - 180F, rider.xRotO * 0.5F);
|
|
+ }
|
|
+ };
|
|
+ // Purpur end
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.enderDragonRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.enderDragonRidableInWater;
|
|
}
|
|
|
|
public void setDragonFight(EndDragonFight fight) {
|
|
@@ -143,6 +175,27 @@ public class EnderDragon extends Mob implements Enemy {
|
|
return this.fightOrigin;
|
|
}
|
|
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.enderDragonControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double getMaxY() {
|
|
+ return level().purpurConfig.enderDragonMaxY;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.enderDragonMaxHealth);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.enderDragonTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0D);
|
|
}
|
|
@@ -184,6 +237,37 @@ public class EnderDragon extends Mob implements Enemy {
|
|
|
|
@Override
|
|
public void aiStep() {
|
|
+ // Purpur start
|
|
+ boolean hasRider = getRider() != null && this.isControllable();
|
|
+ if (hasRider) {
|
|
+ if (!hadRider) {
|
|
+ hadRider = true;
|
|
+ noPhysics = false;
|
|
+ this.dimensions = net.minecraft.world.entity.EntityDimensions.scalable(4.0F, 2.0F);
|
|
+ }
|
|
+
|
|
+ // dragon doesn't use controllers, so must tick manually
|
|
+ moveControl.tick();
|
|
+ lookControl.tick();
|
|
+
|
|
+ moveRelative((float) getAttributeValue(Attributes.MOVEMENT_SPEED) * 0.1F, new Vec3(-getStrafeMot(), getVerticalMot(), -getForwardMot()));
|
|
+ Vec3 mot = getDeltaMovement();
|
|
+ setDeltaMovement(mot);
|
|
+ move(MoverType.PLAYER, mot);
|
|
+
|
|
+ mot = mot.multiply(0.9F, 0.9F, 0.9F);
|
|
+ setDeltaMovement(mot);
|
|
+
|
|
+ // control wing flap speed on client
|
|
+ phaseManager.setPhase(mot.x() * mot.x() + mot.z() * mot.z() < 0.005F ? EnderDragonPhase.HOVERING : EnderDragonPhase.HOLDING_PATTERN);
|
|
+ } else if (hadRider) {
|
|
+ hadRider = false;
|
|
+ noPhysics = true;
|
|
+ this.dimensions = net.minecraft.world.entity.EntityDimensions.scalable(16.0F, 8.0F);
|
|
+ phaseManager.setPhase(EnderDragonPhase.HOLDING_PATTERN); // HoldingPattern
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
this.processFlappingMovement();
|
|
if (this.level().isClientSide) {
|
|
this.setHealth(this.getHealth());
|
|
@@ -210,6 +294,8 @@ public class EnderDragon extends Mob implements Enemy {
|
|
float f;
|
|
|
|
if (this.isDeadOrDying()) {
|
|
+ if (hasRider) ejectPassengers(); // Purpur
|
|
+
|
|
float f1 = (this.random.nextFloat() - 0.5F) * 8.0F;
|
|
|
|
f = (this.random.nextFloat() - 0.5F) * 4.0F;
|
|
@@ -222,9 +308,9 @@ public class EnderDragon extends Mob implements Enemy {
|
|
|
|
f = 0.2F / ((float) vec3d.horizontalDistance() * 10.0F + 1.0F);
|
|
f *= (float) Math.pow(2.0D, vec3d.y);
|
|
- if (this.phaseManager.getCurrentPhase().isSitting()) {
|
|
+ if (!hasRider && this.phaseManager.getCurrentPhase().isSitting()) { // Purpur
|
|
this.flapTime += 0.1F;
|
|
- } else if (this.inWall) {
|
|
+ } else if (!hasRider && this.inWall) { // Purpur
|
|
this.flapTime += f * 0.5F;
|
|
} else {
|
|
this.flapTime += f;
|
|
@@ -240,7 +326,7 @@ public class EnderDragon extends Mob implements Enemy {
|
|
float f4;
|
|
float f5;
|
|
|
|
- if (world1 instanceof ServerLevel) {
|
|
+ if (world1 instanceof ServerLevel && !hasRider) { // Purpur
|
|
ServerLevel worldserver1 = (ServerLevel) world1;
|
|
DragonPhaseInstance idragoncontroller = this.phaseManager.getCurrentPhase();
|
|
|
|
@@ -326,7 +412,7 @@ public class EnderDragon extends Mob implements Enemy {
|
|
if (world2 instanceof ServerLevel) {
|
|
ServerLevel worldserver2 = (ServerLevel) world2;
|
|
|
|
- if (this.hurtTime == 0) {
|
|
+ if (!hasRider && this.hurtTime == 0) { // Purpur
|
|
this.knockBack(worldserver2, worldserver2.getEntities((Entity) this, this.wing1.getBoundingBox().inflate(4.0D, 2.0D, 4.0D).move(0.0D, -2.0D, 0.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR));
|
|
this.knockBack(worldserver2, worldserver2.getEntities((Entity) this, this.wing2.getBoundingBox().inflate(4.0D, 2.0D, 4.0D).move(0.0D, -2.0D, 0.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR));
|
|
this.hurt(worldserver2, worldserver2.getEntities((Entity) this, this.head.getBoundingBox().inflate(1.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR));
|
|
@@ -374,7 +460,7 @@ public class EnderDragon extends Mob implements Enemy {
|
|
if (world3 instanceof ServerLevel) {
|
|
ServerLevel worldserver3 = (ServerLevel) world3;
|
|
|
|
- this.inWall = this.checkWalls(worldserver3, this.head.getBoundingBox()) | this.checkWalls(worldserver3, this.neck.getBoundingBox()) | this.checkWalls(worldserver3, this.body.getBoundingBox());
|
|
+ this.inWall = !hasRider && this.checkWalls(worldserver3, this.head.getBoundingBox()) | this.checkWalls(worldserver3, this.neck.getBoundingBox()) | this.checkWalls(worldserver3, this.body.getBoundingBox()); // Purpur
|
|
if (this.dragonFight != null) {
|
|
this.dragonFight.updateDragon(this);
|
|
}
|
|
@@ -510,7 +596,7 @@ public class EnderDragon extends Mob implements Enemy {
|
|
BlockState iblockdata = world.getBlockState(blockposition);
|
|
|
|
if (!iblockdata.isAir() && !iblockdata.is(BlockTags.DRAGON_TRANSPARENT)) {
|
|
- if (world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !iblockdata.is(BlockTags.DRAGON_IMMUNE)) {
|
|
+ if ((world.purpurConfig.enderDragonBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && !iblockdata.is(BlockTags.DRAGON_IMMUNE)) { // Purpur
|
|
// CraftBukkit start - Add blocks to list rather than destroying them
|
|
// flag1 = worldserver.removeBlock(blockposition, false) || flag1;
|
|
flag1 = true;
|
|
@@ -651,7 +737,7 @@ public class EnderDragon extends Mob implements Enemy {
|
|
boolean flag = worldserver.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;
|
|
}
|
|
|
|
@@ -1069,6 +1155,7 @@ public class EnderDragon extends Mob implements Enemy {
|
|
|
|
@Override
|
|
protected boolean canRide(Entity entity) {
|
|
+ if (this.level().purpurConfig.enderDragonCanRideVehicles) return this.boardingCooldown <= 0; // Purpur
|
|
return false;
|
|
}
|
|
|
|
@@ -1095,6 +1182,6 @@ public class EnderDragon extends Mob implements Enemy {
|
|
|
|
@Override
|
|
protected float sanitizeScale(float scale) {
|
|
- return 1.0F;
|
|
+ return 1.0F; // Purpur - diff on change
|
|
}
|
|
}
|
|
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 244e38db508efa3eebebb6392c4ebb0805367baf..026e730f67c58caf385070d57a2e199fca966a46 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
|
|
@@ -86,20 +86,60 @@ public class WitherBoss extends Monster implements RangedAttackMob {
|
|
return !entityliving.getType().is(EntityTypeTags.WITHER_FRIENDS) && entityliving.attackable();
|
|
};
|
|
private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0D).selector(WitherBoss.LIVING_ENTITY_SELECTOR);
|
|
+ @Nullable private java.util.UUID summoner; // Purpur
|
|
+ private int shootCooldown = 0; // Purpur
|
|
// Paper start
|
|
private boolean canPortal = false;
|
|
|
|
public void setCanTravelThroughPortals(boolean canPortal) { this.canPortal = canPortal; }
|
|
// Paper end
|
|
+ private org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD purpurController; // Purpur
|
|
|
|
public WitherBoss(EntityType<? extends WitherBoss> type, Level world) {
|
|
super(type, world);
|
|
this.bossEvent = (ServerBossEvent) (new ServerBossEvent(this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS)).setDarkenScreen(true);
|
|
- this.moveControl = new FlyingMoveControl(this, 10, false);
|
|
+ // Purpur start
|
|
+ this.purpurController = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.1F);
|
|
+ this.moveControl = new FlyingMoveControl(this, 10, false) {
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ if (mob.getRider() != null && mob.isControllable()) {
|
|
+ purpurController.purpurTick(mob.getRider());
|
|
+ } else {
|
|
+ super.tick();
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+ // Purpur end
|
|
this.setHealth(this.getMaxHealth());
|
|
this.xpReward = 50;
|
|
}
|
|
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.witherMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.witherScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.witherTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
+ public java.util.UUID getSummoner() {
|
|
+ return summoner;
|
|
+ }
|
|
+
|
|
+ public void setSummoner(@Nullable java.util.UUID summoner) {
|
|
+ this.summoner = summoner;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.witherAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected PathNavigation createNavigation(Level world) {
|
|
FlyingPathNavigation navigationflying = new FlyingPathNavigation(this, world);
|
|
@@ -110,13 +150,114 @@ public class WitherBoss extends Monster implements RangedAttackMob {
|
|
return navigationflying;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.witherRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witherRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.witherControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double getMaxY() {
|
|
+ return level().purpurConfig.witherMaxY;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void travel(Vec3 vec3) {
|
|
+ super.travel(vec3);
|
|
+ if (getRider() != null && this.isControllable() && !onGround) {
|
|
+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 5F;
|
|
+ setSpeed(speed);
|
|
+ Vec3 mot = getDeltaMovement();
|
|
+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.5, speed));
|
|
+ setDeltaMovement(mot.scale(0.9D));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onMount(Player rider) {
|
|
+ super.onMount(rider);
|
|
+ this.entityData.set(DATA_TARGETS.get(0), 0);
|
|
+ this.entityData.set(DATA_TARGETS.get(1), 0);
|
|
+ this.entityData.set(DATA_TARGETS.get(2), 0);
|
|
+ getNavigation().stop();
|
|
+ shootCooldown = 20;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean onClick(net.minecraft.world.InteractionHand hand) {
|
|
+ return shoot(getRider(), hand == net.minecraft.world.InteractionHand.MAIN_HAND ? new int[]{1} : new int[]{2});
|
|
+ }
|
|
+
|
|
+ public boolean shoot(@Nullable Player rider, int[] heads) {
|
|
+ if (shootCooldown > 0) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ shootCooldown = 20;
|
|
+ if (rider == null) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ org.bukkit.craftbukkit.entity.CraftHumanEntity player = rider.getBukkitEntity();
|
|
+ if (!player.hasPermission("allow.special.wither")) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ net.minecraft.world.phys.HitResult rayTrace = getRayTrace(120, net.minecraft.world.level.ClipContext.Fluid.NONE);
|
|
+ if (rayTrace == null) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ Vec3 loc;
|
|
+ if (rayTrace.getType() == net.minecraft.world.phys.HitResult.Type.BLOCK) {
|
|
+ BlockPos pos = ((net.minecraft.world.phys.BlockHitResult) rayTrace).getBlockPos();
|
|
+ loc = new Vec3(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D);
|
|
+ } else if (rayTrace.getType() == net.minecraft.world.phys.HitResult.Type.ENTITY) {
|
|
+ Entity target = ((net.minecraft.world.phys.EntityHitResult) rayTrace).getEntity();
|
|
+ loc = new Vec3(target.getX(), target.getY() + (target.getEyeHeight() / 2), target.getZ());
|
|
+ } else {
|
|
+ org.bukkit.block.Block block = player.getTargetBlock(null, 120);
|
|
+ loc = new Vec3(block.getX() + 0.5D, block.getY() + 0.5D, block.getZ() + 0.5D);
|
|
+ }
|
|
+
|
|
+ for (int head : heads) {
|
|
+ shoot(head, loc.x(), loc.y(), loc.z(), rider);
|
|
+ }
|
|
+
|
|
+ return true; // handled
|
|
+ }
|
|
+
|
|
+ public void shoot(int head, double x, double y, double z, Player rider) {
|
|
+ level().levelEvent(null, 1024, blockPosition(), 0);
|
|
+ double headX = getHeadX(head);
|
|
+ double headY = getHeadY(head);
|
|
+ double headZ = getHeadZ(head);
|
|
+ Vec3 vec3d = new Vec3(x - headX, y - headY, z - headZ);
|
|
+ WitherSkull skull = new WitherSkull(level(), this, vec3d.normalize());
|
|
+ skull.setPosRaw(headX, headY, headZ);
|
|
+ level().addFreshEntity(skull);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(0, new WitherBoss.WitherDoNothingGoal());
|
|
this.goalSelector.addGoal(2, new RangedAttackGoal(this, 1.0D, 40, 20.0F));
|
|
this.goalSelector.addGoal(5, new WaterAvoidingRandomFlyingGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F));
|
|
this.goalSelector.addGoal(7, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0]));
|
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 0, false, false, WitherBoss.LIVING_ENTITY_SELECTOR));
|
|
}
|
|
@@ -134,6 +275,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
|
|
public void addAdditionalSaveData(CompoundTag nbt) {
|
|
super.addAdditionalSaveData(nbt);
|
|
nbt.putInt("Invul", this.getInvulnerableTicks());
|
|
+ if (getSummoner() != null) nbt.putUUID("Purpur.Summoner", getSummoner()); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -143,6 +285,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
|
|
if (this.hasCustomName()) {
|
|
this.bossEvent.setName(this.getDisplayName());
|
|
}
|
|
+ if (nbt.contains("Purpur.Summoner")) setSummoner(nbt.getUUID("Purpur.Summoner")); // Purpur
|
|
|
|
}
|
|
|
|
@@ -261,6 +404,15 @@ public class WitherBoss extends Monster implements RangedAttackMob {
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
+ // Purpur start
|
|
+ if (getRider() != null && this.isControllable()) {
|
|
+ Vec3 mot = getDeltaMovement();
|
|
+ setDeltaMovement(mot.x(), mot.y() + (getVerticalMot() > 0 ? 0.07D : 0.0D), mot.z());
|
|
+ }
|
|
+ if (shootCooldown > 0) {
|
|
+ shootCooldown--;
|
|
+ }
|
|
+ // Purpur end
|
|
int i;
|
|
|
|
if (this.getInvulnerableTicks() > 0) {
|
|
@@ -277,7 +429,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
|
|
}
|
|
// CraftBukkit end
|
|
|
|
- if (!this.isSilent()) {
|
|
+ if (!this.isSilent() && level().purpurConfig.witherPlaySpawnSound) {
|
|
// CraftBukkit start - Use relative location for far away sounds
|
|
// worldserver.globalLevelEvent(1023, new BlockPosition(this), 0);
|
|
int viewDistance = world.getCraftServer().getViewDistance() * 16;
|
|
@@ -302,7 +454,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
|
|
|
|
this.setInvulnerableTicks(i);
|
|
if (this.tickCount % 10 == 0) {
|
|
- this.heal(10.0F, EntityRegainHealthEvent.RegainReason.WITHER_SPAWN); // CraftBukkit
|
|
+ this.heal(this.getMaxHealth() / 33, EntityRegainHealthEvent.RegainReason.WITHER_SPAWN); // CraftBukkit // Purpur
|
|
}
|
|
|
|
} else {
|
|
@@ -362,7 +514,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
|
|
|
|
if (this.destroyBlocksTick > 0) {
|
|
--this.destroyBlocksTick;
|
|
- if (this.destroyBlocksTick == 0 && world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
|
+ if (this.destroyBlocksTick == 0 && (world.purpurConfig.witherBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // Purpur
|
|
boolean flag = false;
|
|
|
|
j = Mth.floor(this.getBbWidth() / 2.0F + 1.0F);
|
|
@@ -389,8 +541,10 @@ public class WitherBoss extends Monster implements 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());
|
|
@@ -579,11 +733,11 @@ public class WitherBoss extends Monster implements RangedAttackMob {
|
|
}
|
|
|
|
public int getAlternativeTarget(int headIndex) {
|
|
- return (Integer) this.entityData.get((EntityDataAccessor) WitherBoss.DATA_TARGETS.get(headIndex));
|
|
+ return getRider() != null && this.isControllable() ? 0 : this.entityData.get(WitherBoss.DATA_TARGETS.get(headIndex)); // Purpur
|
|
}
|
|
|
|
public void setAlternativeTarget(int headIndex, int id) {
|
|
- this.entityData.set((EntityDataAccessor) WitherBoss.DATA_TARGETS.get(headIndex), id);
|
|
+ if (getRider() == null || !this.isControllable()) this.entityData.set(WitherBoss.DATA_TARGETS.get(headIndex), id); // Purpur
|
|
}
|
|
|
|
public boolean isPowered() {
|
|
@@ -592,6 +746,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
|
|
|
|
@Override
|
|
protected boolean canRide(Entity entity) {
|
|
+ if (this.level().purpurConfig.witherCanRideVehicles) return this.boardingCooldown <= 0; // Purpur
|
|
return false;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
|
index 70b8023c3badc745f342d5b0ab54699e3923826a..037586c0fdb42a02660aba89dd741a647c67e52b 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
|
@@ -114,10 +114,12 @@ public class ArmorStand extends LivingEntity {
|
|
private boolean noTickPoseDirty = false;
|
|
private boolean noTickEquipmentDirty = false;
|
|
// Paper end - Allow ArmorStands not to tick
|
|
+ public boolean canMovementTick = true; // Purpur
|
|
|
|
public ArmorStand(EntityType<? extends ArmorStand> type, Level world) {
|
|
super(type, world);
|
|
if (world != null) this.canTick = world.paperConfig().entities.armorStands.tick; // Paper - Allow ArmorStands not to tick
|
|
+ if (world != null) this.canMovementTick = world.purpurConfig.armorstandMovement; // Purpur
|
|
this.handItems = NonNullList.withSize(2, ItemStack.EMPTY);
|
|
this.armorItems = NonNullList.withSize(4, ItemStack.EMPTY);
|
|
this.headPose = ArmorStand.DEFAULT_HEAD_POSE;
|
|
@@ -126,6 +128,7 @@ public class ArmorStand extends LivingEntity {
|
|
this.rightArmPose = ArmorStand.DEFAULT_RIGHT_ARM_POSE;
|
|
this.leftLegPose = ArmorStand.DEFAULT_LEFT_LEG_POSE;
|
|
this.rightLegPose = ArmorStand.DEFAULT_RIGHT_LEG_POSE;
|
|
+ this.setShowArms(world != null && world.purpurConfig.armorstandPlaceWithArms); // Purpur
|
|
}
|
|
|
|
public ArmorStand(Level world, double x, double y, double z) {
|
|
@@ -618,6 +621,7 @@ public class ArmorStand extends LivingEntity {
|
|
private org.bukkit.event.entity.EntityDeathEvent brokenByPlayer(ServerLevel world, DamageSource damageSource) { // Paper
|
|
ItemStack itemstack = new ItemStack(Items.ARMOR_STAND);
|
|
|
|
+ if (this.level().purpurConfig.persistentDroppableEntityDisplayNames)
|
|
itemstack.set(DataComponents.CUSTOM_NAME, this.getCustomName());
|
|
this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior
|
|
return this.brokenByAnything(world, damageSource); // Paper
|
|
@@ -681,6 +685,7 @@ public class ArmorStand extends LivingEntity {
|
|
|
|
@Override
|
|
public void tick() {
|
|
+ maxUpStep = level().purpurConfig.armorstandStepHeight;
|
|
// Paper start - Allow ArmorStands not to tick
|
|
if (!this.canTick) {
|
|
if (this.noTickPoseDirty) {
|
|
@@ -1013,4 +1018,18 @@ public class ArmorStand extends LivingEntity {
|
|
}
|
|
}
|
|
// Paper end
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public void updateInWaterStateAndDoWaterCurrentPushing() {
|
|
+ if (this.level().purpurConfig.armorstandWaterMovement &&
|
|
+ (this.level().purpurConfig.armorstandWaterFence || !(level().getBlockState(blockPosition().below()).getBlock() instanceof net.minecraft.world.level.block.FenceBlock)))
|
|
+ super.updateInWaterStateAndDoWaterCurrentPushing();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void aiStep() {
|
|
+ if (this.canMovementTick && this.canMove) super.aiStep();
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
|
index bbdaaa1cc0b4aed28bc39385508d221055b99d4d..bd5e034ce58ebe53d2121209d76ae60134ce72fe 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
|
@@ -240,7 +240,13 @@ public class ItemFrame extends HangingEntity {
|
|
}
|
|
|
|
if (dropSelf) {
|
|
- this.spawnAtLocation(world, this.getFrameItemStack());
|
|
+ // Purpur start
|
|
+ final ItemStack itemFrame = this.getFrameItemStack();
|
|
+ if (!this.level().purpurConfig.persistentDroppableEntityDisplayNames) {
|
|
+ itemFrame.set(DataComponents.CUSTOM_NAME, null);
|
|
+ }
|
|
+ this.spawnAtLocation(world, itemFrame);
|
|
+ // Purpur end
|
|
}
|
|
|
|
if (!itemstack.isEmpty()) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/decoration/Painting.java b/src/main/java/net/minecraft/world/entity/decoration/Painting.java
|
|
index fd0e78a2318e3950d011c17358245e107b38154a..0fcab828e81176323cbdf16c0ec714d9a2846ae5 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/decoration/Painting.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/decoration/Painting.java
|
|
@@ -179,7 +179,13 @@ public class Painting extends HangingEntity implements VariantHolder<Holder<Pain
|
|
}
|
|
}
|
|
|
|
- this.spawnAtLocation(world, (ItemLike) Items.PAINTING);
|
|
+ // Purpur start
|
|
+ final ItemStack painting = new ItemStack((ItemLike) Items.PAINTING);
|
|
+ if (!this.level().purpurConfig.persistentDroppableEntityDisplayNames) {
|
|
+ painting.set(net.minecraft.core.component.DataComponents.CUSTOM_NAME, null);
|
|
+ }
|
|
+ this.spawnAtLocation(world, painting);
|
|
+ // Purpur end
|
|
}
|
|
}
|
|
|
|
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 0f086af57a5ff08c264dcbf89a8c3931ec73a609..c63cf322e0d00b5ec9929db8c22d4a392049160f 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
|
@@ -64,6 +64,12 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
|
public boolean canMobPickup = true; // Paper - Item#canEntityPickup
|
|
private int despawnRate = -1; // Paper - Alternative item-despawn-rate
|
|
public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API
|
|
+ // Purpur start
|
|
+ public boolean immuneToCactus = false;
|
|
+ public boolean immuneToExplosion = false;
|
|
+ public boolean immuneToFire = false;
|
|
+ public boolean immuneToLightning = false;
|
|
+ // Purpur end
|
|
|
|
public ItemEntity(EntityType<? extends ItemEntity> type, Level world) {
|
|
super(type, world);
|
|
@@ -384,7 +390,16 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
|
|
|
@Override
|
|
public final boolean hurtServer(ServerLevel world, DamageSource source, float amount) {
|
|
- if (this.isInvulnerableToBase(source)) {
|
|
+ // Purpur start
|
|
+ if (
|
|
+ (immuneToCactus && source.is(net.minecraft.world.damagesource.DamageTypes.CACTUS)) ||
|
|
+ (immuneToFire && (source.is(net.minecraft.tags.DamageTypeTags.IS_FIRE) || source.is(net.minecraft.world.damagesource.DamageTypes.ON_FIRE) || source.is(net.minecraft.world.damagesource.DamageTypes.IN_FIRE))) ||
|
|
+ (immuneToLightning && source.is(net.minecraft.world.damagesource.DamageTypes.LIGHTNING_BOLT)) ||
|
|
+ (immuneToExplosion && source.is(net.minecraft.tags.DamageTypeTags.IS_EXPLOSION))
|
|
+ ) {
|
|
+ return false;
|
|
+ } else if (this.isInvulnerableToBase(source)) {
|
|
+ // Purpur end
|
|
return false;
|
|
} else if (!world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && source.getEntity() instanceof Mob) {
|
|
return false;
|
|
@@ -595,6 +610,12 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
|
public void setItem(ItemStack stack) {
|
|
this.getEntityData().set(ItemEntity.DATA_ITEM, stack);
|
|
this.despawnRate = this.level().paperConfig().entities.spawning.altItemDespawnRate.enabled ? this.level().paperConfig().entities.spawning.altItemDespawnRate.items.getOrDefault(stack.getItem(), this.level().spigotConfig.itemDespawnRate) : this.level().spigotConfig.itemDespawnRate; // Paper - Alternative item-despawn-rate
|
|
+ // Purpur start
|
|
+ if (level().purpurConfig.itemImmuneToCactus.contains(stack.getItem())) immuneToCactus = true;
|
|
+ if (level().purpurConfig.itemImmuneToExplosion.contains(stack.getItem())) immuneToExplosion = true;
|
|
+ if (level().purpurConfig.itemImmuneToFire.contains(stack.getItem())) immuneToFire = true;
|
|
+ if (level().purpurConfig.itemImmuneToLightning.contains(stack.getItem())) immuneToLightning = true;
|
|
+ // level end
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
|
index de87483600e55d88176fe25db621bbd3e464729f..287ba483614e79e78022e703ef891f59f41ac455 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
|
@@ -249,4 +249,31 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
|
return !level().paperConfig().fixes.preventTntFromMovingInWater && super.isPushedByFluid();
|
|
}
|
|
// Paper end - Option to prevent TNT from moving in water
|
|
+ // Purpur start - Shears can defuse TNT
|
|
+ @Override
|
|
+ public net.minecraft.world.InteractionResult interact(net.minecraft.world.entity.player.Player player, net.minecraft.world.InteractionHand hand) {
|
|
+ Level world = this.level();
|
|
+
|
|
+ if (world instanceof ServerLevel serverWorld && level().purpurConfig.shearsCanDefuseTnt) {
|
|
+ final net.minecraft.world.item.ItemStack inHand = player.getItemInHand(hand);
|
|
+
|
|
+ if (!inHand.is(net.minecraft.world.item.Items.SHEARS) || !player.getBukkitEntity().hasPermission("purpur.tnt.defuse") ||
|
|
+ serverWorld.random.nextFloat() > serverWorld.purpurConfig.shearsCanDefuseTntChance) return net.minecraft.world.InteractionResult.PASS;
|
|
+
|
|
+ net.minecraft.world.entity.item.ItemEntity tntItem = new net.minecraft.world.entity.item.ItemEntity(serverWorld, getX(), getY(), getZ(),
|
|
+ new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.TNT));
|
|
+ tntItem.setPickUpDelay(10);
|
|
+
|
|
+ inHand.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand));
|
|
+ serverWorld.addFreshEntity(tntItem, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CUSTOM);
|
|
+
|
|
+ this.playSound(net.minecraft.sounds.SoundEvents.SHEEP_SHEAR);
|
|
+
|
|
+ this.kill(serverWorld);
|
|
+ return net.minecraft.world.InteractionResult.SUCCESS;
|
|
+ }
|
|
+
|
|
+ return super.interact(player, hand);
|
|
+ }
|
|
+ // Purpur end - Shears can defuse TNT
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
|
|
index 32670a3cb4b54b66d655197e3fde834d2b2b6d34..39d02cf0e31832e30c4f034b0b5385e3e0057e60 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
|
|
@@ -68,16 +68,19 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
|
|
protected AbstractSkeleton(EntityType<? extends AbstractSkeleton> type, Level world) {
|
|
super(type, world);
|
|
this.reassessWeaponGoal();
|
|
+ this.setShouldBurnInDay(true); // Purpur - API for any mob to burn daylight
|
|
}
|
|
|
|
@Override
|
|
protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(2, new RestrictSunGoal(this));
|
|
this.goalSelector.addGoal(3, new FleeSunGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Wolf.class, 6.0F, 1.0D, 1.2D));
|
|
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F));
|
|
this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0]));
|
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
|
|
@@ -96,37 +99,14 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
|
|
abstract SoundEvent getStepSound();
|
|
|
|
// Paper start - shouldBurnInDay API
|
|
- private boolean shouldBurnInDay = true;
|
|
+ //private boolean shouldBurnInDay = true; // Purpur - moved to LivingEntity; keep methods for ABI compatibility - API for any mob to burn daylight
|
|
public boolean shouldBurnInDay() { return shouldBurnInDay; }
|
|
public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; }
|
|
// Paper end - shouldBurnInDay API
|
|
|
|
@Override
|
|
public void aiStep() {
|
|
- boolean flag = shouldBurnInDay && this.isSunBurnTick(); // Paper - shouldBurnInDay API
|
|
-
|
|
- if (flag) {
|
|
- ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD);
|
|
-
|
|
- if (!itemstack.isEmpty()) {
|
|
- if (itemstack.isDamageableItem()) {
|
|
- Item item = itemstack.getItem();
|
|
-
|
|
- itemstack.setDamageValue(itemstack.getDamageValue() + this.random.nextInt(2));
|
|
- if (itemstack.getDamageValue() >= itemstack.getMaxDamage()) {
|
|
- this.onEquippedItemBroken(item, EquipmentSlot.HEAD);
|
|
- this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY);
|
|
- }
|
|
- }
|
|
-
|
|
- flag = false;
|
|
- }
|
|
-
|
|
- if (flag) {
|
|
- this.igniteForSeconds(8.0F);
|
|
- }
|
|
- }
|
|
-
|
|
+ // Purpur - implemented in LivingEntity - API for any mob to burn daylight
|
|
super.aiStep();
|
|
}
|
|
|
|
@@ -158,11 +138,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
|
|
this.reassessWeaponGoal();
|
|
this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || randomsource.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot
|
|
if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
|
|
- LocalDate localdate = LocalDate.now();
|
|
- int i = localdate.get(ChronoField.DAY_OF_MONTH);
|
|
- int j = localdate.get(ChronoField.MONTH_OF_YEAR);
|
|
-
|
|
- if (j == 10 && i == 31 && randomsource.nextFloat() < 0.25F) {
|
|
+ if (net.minecraft.world.entity.ambient.Bat.isHalloweenSeason(world.getMinecraftWorld()) && this.random.nextFloat() < this.level().purpurConfig.chanceHeadHalloweenOnEntity) { // Purpur
|
|
this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
|
|
this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F;
|
|
}
|
|
@@ -221,7 +197,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
|
|
}
|
|
|
|
if (event.getProjectile() == entityarrow.getBukkitEntity()) {
|
|
- Projectile.spawnProjectileUsingShoot(entityarrow, worldserver, itemstack1, d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, (float) (14 - worldserver.getDifficulty().getId() * 4));
|
|
+ Projectile.spawnProjectileUsingShoot(entityarrow, worldserver, itemstack1, d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, this.level().purpurConfig.skeletonBowAccuracyMap.getOrDefault(this.level().getDifficulty().getId(), (float) (14 - this.level().getDifficulty().getId() * 4))); // Purpur
|
|
}
|
|
// CraftBukkit end
|
|
}
|
|
@@ -243,7 +219,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
|
|
super.readAdditionalSaveData(nbt);
|
|
this.reassessWeaponGoal();
|
|
// Paper start - shouldBurnInDay API
|
|
- if (nbt.contains("Paper.ShouldBurnInDay")) {
|
|
+ if (false && nbt.contains("Paper.ShouldBurnInDay")) { // Purpur - implemented in LivingEntity - API for any mob to burn daylight
|
|
this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay");
|
|
}
|
|
// Paper end - shouldBurnInDay API
|
|
@@ -253,7 +229,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
|
|
@Override
|
|
public void addAdditionalSaveData(CompoundTag nbt) {
|
|
super.addAdditionalSaveData(nbt);
|
|
- nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay);
|
|
+ //nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - implemented in LivingEntity - API for any mob to burn daylight
|
|
}
|
|
// Paper end - shouldBurnInDay API
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Blaze.java b/src/main/java/net/minecraft/world/entity/monster/Blaze.java
|
|
index e33fa82ca1332b95bb067fd621212d3026eee1b7..07db4557ab0d7a4a0f5432257bd18195d2de7255 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Blaze.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Blaze.java
|
|
@@ -33,26 +33,74 @@ public class Blaze extends Monster {
|
|
|
|
public Blaze(EntityType<? extends Blaze> type, Level world) {
|
|
super(type, world);
|
|
- this.setPathfindingMalus(PathType.WATER, -1.0F);
|
|
+ this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); // Purpur
|
|
+ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur
|
|
this.setPathfindingMalus(PathType.LAVA, 8.0F);
|
|
this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F);
|
|
this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F);
|
|
this.xpReward = 10;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.blazeRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.blazeRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.blazeControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double getMaxY() {
|
|
+ return level().purpurConfig.blazeMaxY;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void travel(Vec3 vec3) {
|
|
+ super.travel(vec3);
|
|
+ if (getRider() != null && this.isControllable() && !onGround) {
|
|
+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED);
|
|
+ setSpeed(speed);
|
|
+ Vec3 mot = getDeltaMovement();
|
|
+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed));
|
|
+ setDeltaMovement(mot.scale(0.9D));
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.blazeMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.blazeScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.blazeAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(4, new Blaze.BlazeAttackGoal(this));
|
|
this.goalSelector.addGoal(5, new MoveTowardsRestrictionGoal(this, 1.0));
|
|
this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0, 0.0F));
|
|
this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F));
|
|
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers());
|
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
|
}
|
|
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
- return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 6.0).add(Attributes.MOVEMENT_SPEED, 0.23F).add(Attributes.FOLLOW_RANGE, 48.0);
|
|
+ return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 6.0).add(Attributes.MOVEMENT_SPEED, 0.23F).add(Attributes.FOLLOW_RANGE, 48.0).add(Attributes.FLYING_SPEED, 0.6D); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -112,11 +160,18 @@ public class Blaze extends Monster {
|
|
|
|
@Override
|
|
public boolean isSensitiveToWater() {
|
|
- return true;
|
|
+ return this.level().purpurConfig.blazeTakeDamageFromWater; // Purpur
|
|
}
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
+ // Purpur start
|
|
+ if (getRider() != null && this.isControllable()) {
|
|
+ Vec3 mot = getDeltaMovement();
|
|
+ setDeltaMovement(mot.x(), getVerticalMot() > 0 ? 0.07D : -0.07D, mot.z());
|
|
+ return;
|
|
+ }
|
|
+ // Purpur end
|
|
this.nextHeightOffsetChangeTick--;
|
|
if (this.nextHeightOffsetChangeTick <= 0) {
|
|
this.nextHeightOffsetChangeTick = 100;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Bogged.java b/src/main/java/net/minecraft/world/entity/monster/Bogged.java
|
|
index 18dae37d65552077aa3825c76f433bbd31152db9..52993da6868161105450491a81f5c32356fa17aa 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Bogged.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Bogged.java
|
|
@@ -44,6 +44,29 @@ public class Bogged extends AbstractSkeleton implements Shearable {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.boggedRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.boggedRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.boggedControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.boggedMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.boggedScale);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
|
super.defineSynchedData(builder);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java b/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java
|
|
index 4e621a7f36b3d718695434a2a4e3060283667bb2..9a274b83a3a7726cac421856dbc7be01de45d29b 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java
|
|
@@ -27,6 +27,39 @@ public class CaveSpider extends Spider {
|
|
return Spider.createAttributes().add(Attributes.MAX_HEALTH, 12.0D);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.caveSpiderRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.caveSpiderRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.caveSpiderControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.caveSpiderMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.caveSpiderScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.caveSpiderTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.caveSpiderAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
public boolean doHurtTarget(ServerLevel world, Entity target) {
|
|
if (super.doHurtTarget(world, target)) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java
|
|
index 1906dfc22af208d6e801ad4a8f2f9e9702432691..38cbe2fce9c36195aa9bea2af26d14364b216825 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java
|
|
@@ -60,21 +60,99 @@ public class Creeper extends Monster {
|
|
public int explosionRadius = 3;
|
|
private int droppedSkulls;
|
|
public Entity entityIgniter; // CraftBukkit
|
|
+ // Purpur start
|
|
+ private int spacebarCharge = 0;
|
|
+ private int prevSpacebarCharge = 0;
|
|
+ private int powerToggleDelay = 0;
|
|
+ // Purpur end
|
|
+ private boolean exploding = false; // Purpur - Config to make Creepers explode on death
|
|
|
|
public Creeper(EntityType<? extends Creeper> type, Level world) {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.creeperRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.creeperRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.creeperControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void customServerAiStep(ServerLevel world) {
|
|
+ if (powerToggleDelay > 0) {
|
|
+ powerToggleDelay--;
|
|
+ }
|
|
+ if (getRider() != null && this.isControllable()) {
|
|
+ if (getRider().getForwardMot() != 0 || getRider().getStrafeMot() != 0) {
|
|
+ spacebarCharge = 0;
|
|
+ setIgnited(false);
|
|
+ setSwellDir(-1);
|
|
+ }
|
|
+ if (spacebarCharge == prevSpacebarCharge) {
|
|
+ spacebarCharge = 0;
|
|
+ }
|
|
+ prevSpacebarCharge = spacebarCharge;
|
|
+ }
|
|
+ super.customServerAiStep(world);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onMount(Player rider) {
|
|
+ super.onMount(rider);
|
|
+ setIgnited(false);
|
|
+ setSwellDir(-1);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean onSpacebar() {
|
|
+ if (powerToggleDelay > 0) {
|
|
+ return true; // just toggled power, do not jump or ignite
|
|
+ }
|
|
+ spacebarCharge++;
|
|
+ if (spacebarCharge > maxSwell - 2) {
|
|
+ spacebarCharge = 0;
|
|
+ if (getRider() != null && getRider().getBukkitEntity().hasPermission("allow.powered.creeper")) {
|
|
+ powerToggleDelay = 20;
|
|
+ setPowered(!isPowered());
|
|
+ setIgnited(false);
|
|
+ setSwellDir(-1);
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ if (!isIgnited()) {
|
|
+ if (getRider() != null && getRider().getForwardMot() == 0 && getRider().getStrafeMot() == 0 &&
|
|
+ getRider().getBukkitEntity().hasPermission("allow.special.creeper")) {
|
|
+ setIgnited(true);
|
|
+ setSwellDir(1);
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return getForwardMot() == 0 && getStrafeMot() == 0; // do not jump if standing still
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(1, new FloatGoal(this));
|
|
this.goalSelector.addGoal(2, new SwellGoal(this));
|
|
+ this.goalSelector.addGoal(3, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Ocelot.class, 6.0F, 1.0D, 1.2D));
|
|
this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Cat.class, 6.0F, 1.0D, 1.2D));
|
|
this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0D, false));
|
|
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8D));
|
|
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F));
|
|
this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
|
this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0]));
|
|
}
|
|
@@ -174,6 +252,40 @@ public class Creeper extends Monster {
|
|
}
|
|
}
|
|
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.creeperMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.creeperScale);
|
|
+ }
|
|
+
|
|
+ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.EntitySpawnReason spawnReason, @Nullable net.minecraft.world.entity.SpawnGroupData entityData) {
|
|
+ double chance = world.getLevel().purpurConfig.creeperChargedChance;
|
|
+ if (chance > 0D && random.nextDouble() <= chance) {
|
|
+ setPowered(true);
|
|
+ }
|
|
+ return super.finalizeSpawn(world, difficulty, spawnReason, entityData);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.creeperTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ // Purpur start - Config to make Creepers explode on death
|
|
+ @Override
|
|
+ protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(ServerLevel world, DamageSource damageSource) {
|
|
+ if (!this.exploding && this.level().purpurConfig.creeperExplodeWhenKilled && damageSource.getEntity() instanceof net.minecraft.server.level.ServerPlayer) {
|
|
+ this.explodeCreeper();
|
|
+ }
|
|
+ return super.dropAllDeathLoot(world, damageSource);
|
|
+ }
|
|
+ // Purpur end - Config to make Creepers explode on death
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.creeperAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected SoundEvent getHurtSound(DamageSource source) {
|
|
return SoundEvents.CREEPER_HURT;
|
|
@@ -262,16 +374,18 @@ public class Creeper extends Monster {
|
|
|
|
public void explodeCreeper() {
|
|
Level world = this.level();
|
|
+ this.exploding = true; // Purpur - Config to make Creepers explode on death
|
|
|
|
if (world instanceof ServerLevel worldserver) {
|
|
float f = this.isPowered() ? 2.0F : 1.0F;
|
|
+ float multiplier = worldserver.purpurConfig.creeperHealthRadius ? this.getHealth() / this.getMaxHealth() : 1; // Purpur
|
|
|
|
// CraftBukkit start
|
|
- ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, this.explosionRadius * f, false);
|
|
+ ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, (this.explosionRadius * f) * multiplier, false); // Purpur
|
|
if (!event.isCancelled()) {
|
|
// CraftBukkit end
|
|
this.dead = true;
|
|
- worldserver.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this)
|
|
+ worldserver.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), worldserver.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) && level().purpurConfig.creeperAllowGriefing ? Level.ExplosionInteraction.MOB : Level.ExplosionInteraction.NONE); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this) // Purpur
|
|
this.spawnLingeringCloud();
|
|
this.triggerOnDeathMobEffects(worldserver, Entity.RemovalReason.KILLED);
|
|
this.discard(EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause
|
|
@@ -283,6 +397,7 @@ public class Creeper extends Monster {
|
|
// CraftBukkit end
|
|
}
|
|
|
|
+ this.exploding = false; // Purpur - Config to make Creepers explode on death
|
|
}
|
|
|
|
private void spawnLingeringCloud() {
|
|
@@ -324,6 +439,7 @@ public class Creeper extends Monster {
|
|
com.destroystokyo.paper.event.entity.CreeperIgniteEvent event = new com.destroystokyo.paper.event.entity.CreeperIgniteEvent((org.bukkit.entity.Creeper) getBukkitEntity(), ignited);
|
|
if (event.callEvent()) {
|
|
this.entityData.set(Creeper.DATA_IS_IGNITED, event.isIgnited());
|
|
+ if (!event.isIgnited()) setSwellDir(-1); // Purpur
|
|
}
|
|
}
|
|
// Paper end - CreeperIgniteEvent
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Drowned.java b/src/main/java/net/minecraft/world/entity/monster/Drowned.java
|
|
index 2e73917ce9270de7483bb1d4e9bf312a31ec9b1e..949207eda199c874f2f14074b5a4fff5462b86b9 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Drowned.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Drowned.java
|
|
@@ -72,6 +72,59 @@ public class Drowned extends Zombie implements RangedAttackMob {
|
|
return Zombie.createAttributes().add(Attributes.STEP_HEIGHT, 1.0);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.drownedRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.drownedRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.drownedControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.drownedMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.drownedScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void randomizeReinforcementsChance() {
|
|
+ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.drownedSpawnReinforcements);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.drownedTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean jockeyOnlyBaby() {
|
|
+ return level().purpurConfig.drownedJockeyOnlyBaby;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double jockeyChance() {
|
|
+ return level().purpurConfig.drownedJockeyChance;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean jockeyTryExistingChickens() {
|
|
+ return level().purpurConfig.drownedJockeyTryExistingChickens;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.drownedAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void addBehaviourGoals() {
|
|
this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0));
|
|
@@ -79,10 +132,23 @@ public class Drowned extends Zombie implements RangedAttackMob {
|
|
this.goalSelector.addGoal(2, new Drowned.DrownedAttackGoal(this, 1.0, false));
|
|
this.goalSelector.addGoal(5, new Drowned.DrownedGoToBeachGoal(this, 1.0));
|
|
this.goalSelector.addGoal(6, new Drowned.DrownedSwimUpGoal(this, 1.0, this.level().getSeaLevel()));
|
|
+ if (level().purpurConfig.drownedBreakDoors) this.goalSelector.addGoal(6, new net.minecraft.world.entity.ai.goal.MoveThroughVillageGoal(this, 1.0D, true, 4, this::canBreakDoors));
|
|
this.goalSelector.addGoal(7, new RandomStrollGoal(this, 1.0));
|
|
this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Drowned.class).setAlertOthers(ZombifiedPiglin.class));
|
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (target, world) -> this.okTarget(target)));
|
|
- if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Paper - Check drowned for villager aggression config
|
|
+ // Purpur start
|
|
+ if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false) { // Paper - Check drowned for villager aggression config
|
|
+ @Override
|
|
+ public boolean canUse() {
|
|
+ return (level().purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !level().getServer().server.isLagging()) && super.canUse();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canContinueToUse() {
|
|
+ return (level().purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !level().getServer().server.isLagging()) && super.canContinueToUse();
|
|
+ }
|
|
+ });
|
|
+ // Purpur end
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Axolotl.class, true, false));
|
|
this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR));
|
|
@@ -396,7 +462,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
|
|
}
|
|
}
|
|
|
|
- static class DrownedMoveControl extends MoveControl {
|
|
+ static class DrownedMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur
|
|
private final Drowned drowned;
|
|
|
|
public DrownedMoveControl(Drowned drowned) {
|
|
@@ -405,7 +471,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
|
|
}
|
|
|
|
@Override
|
|
- public void tick() {
|
|
+ public void vanillaTick() { // Purpur
|
|
LivingEntity livingEntity = this.drowned.getTarget();
|
|
if (this.drowned.wantsToSwim() && this.drowned.isInWater()) {
|
|
if (livingEntity != null && livingEntity.getY() > this.drowned.getY() || this.drowned.searchingForLand) {
|
|
@@ -425,7 +491,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
|
|
float h = (float)(Mth.atan2(f, d) * 180.0F / (float)Math.PI) - 90.0F;
|
|
this.drowned.setYRot(this.rotlerp(this.drowned.getYRot(), h, 90.0F));
|
|
this.drowned.yBodyRot = this.drowned.getYRot();
|
|
- float i = (float)(this.speedModifier * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED));
|
|
+ float i = (float)(this.getSpeedModifier() * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur
|
|
float j = Mth.lerp(0.125F, this.drowned.getSpeed(), i);
|
|
this.drowned.setSpeed(j);
|
|
this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add((double)j * d * 0.005, (double)j * e * 0.1, (double)j * f * 0.005));
|
|
@@ -434,7 +500,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
|
|
this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add(0.0, -0.008, 0.0));
|
|
}
|
|
|
|
- super.tick();
|
|
+ super.vanillaTick(); // Purpur
|
|
}
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java
|
|
index 378694a38115c012978e1fea59d049d1ebd04110..a000304e3ac4c34b020f7457aa2589c87f140d8c 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java
|
|
@@ -33,6 +33,34 @@ public class ElderGuardian extends Guardian {
|
|
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.elderGuardianRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.elderGuardianControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.elderGuardianMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.elderGuardianScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.elderGuardianTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.elderGuardianAlwaysDropExp;
|
|
+ }
|
|
+
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
return Guardian.createAttributes().add(Attributes.MOVEMENT_SPEED, 0.30000001192092896D).add(Attributes.ATTACK_DAMAGE, 8.0D).add(Attributes.MAX_HEALTH, 80.0D);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
|
index 48dcd2bc12ce1d08cc5195bff5460dc0dd9902d3..39ec4b00c6254824632b37ea9824ae9ff84cdb20 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
|
@@ -92,12 +92,41 @@ public class EnderMan extends Monster implements NeutralMob {
|
|
|
|
public EnderMan(EntityType<? extends EnderMan> type, Level world) {
|
|
super(type, world);
|
|
- this.setPathfindingMalus(PathType.WATER, -1.0F);
|
|
+ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.endermanRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.endermanRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.endermanControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.endermanMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.endermanScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.endermanAlwaysDropExp;
|
|
}
|
|
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new EnderMan.EndermanFreezeWhenLookedAt(this));
|
|
this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0D, false));
|
|
this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D, 0.0F));
|
|
@@ -105,9 +134,10 @@ public class EnderMan extends Monster implements NeutralMob {
|
|
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
|
|
this.goalSelector.addGoal(10, new EnderMan.EndermanLeaveBlockGoal(this));
|
|
this.goalSelector.addGoal(11, new EnderMan.EndermanTakeBlockGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new EnderMan.EndermanLookForPlayerGoal(this, this::isAngryAt));
|
|
this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0]));
|
|
- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Endermite.class, true, false));
|
|
+ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Endermite.class, 10, true, false, (entityliving, ignored) -> entityliving.level().purpurConfig.endermanAggroEndermites && entityliving instanceof Endermite endermite && (!entityliving.level().purpurConfig.endermanAggroEndermitesOnlyIfPlayerSpawned || endermite.isPlayerSpawned()))); // Purpur
|
|
this.targetSelector.addGoal(4, new ResetUniversalAngerTargetGoal<>(this, false));
|
|
}
|
|
|
|
@@ -235,7 +265,7 @@ public class EnderMan extends Monster implements NeutralMob {
|
|
|
|
boolean isBeingStaredBy(Player player) {
|
|
// Paper start - EndermanAttackPlayerEvent
|
|
- boolean shouldAttack = isBeingStaredBy0(player);
|
|
+ boolean shouldAttack = !this.level().purpurConfig.endermanDisableStareAggro && isBeingStaredBy0(player); // Purpur
|
|
com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent event = new com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent((org.bukkit.entity.Enderman) getBukkitEntity(), (org.bukkit.entity.Player) player.getBukkitEntity());
|
|
event.setCancelled(!shouldAttack);
|
|
return event.callEvent();
|
|
@@ -263,12 +293,12 @@ public class EnderMan extends Monster implements NeutralMob {
|
|
|
|
@Override
|
|
public boolean isSensitiveToWater() {
|
|
- return true;
|
|
+ return this.level().purpurConfig.endermanTakeDamageFromWater; // Purpur
|
|
}
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- if (world.isDay() && this.tickCount >= this.targetChangeTime + 600) {
|
|
+ if ((getRider() == null || !this.isControllable()) && world.isDay() && this.tickCount >= this.targetChangeTime + 600) { // Purpur - no random teleporting
|
|
float f = this.getLightLevelDependentMagicValue();
|
|
|
|
if (f > 0.5F && world.canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper - EndermanEscapeEvent
|
|
@@ -383,6 +413,8 @@ public class EnderMan extends Monster implements NeutralMob {
|
|
public boolean hurtServer(ServerLevel world, DamageSource source, float amount) {
|
|
if (this.isInvulnerableTo(world, source)) {
|
|
return false;
|
|
+ } else if (getRider() != null && this.isControllable()) { return super.hurtServer(world, source, amount); // Purpur - no teleporting on damage
|
|
+ } else if (org.purpurmc.purpur.PurpurConfig.endermanShortHeight && source.is(net.minecraft.world.damagesource.DamageTypes.IN_WALL)) { return false; // Purpur - no suffocation damage if short height
|
|
} else {
|
|
boolean flag = source.getDirectEntity() instanceof ThrownPotion;
|
|
boolean flag1;
|
|
@@ -397,6 +429,7 @@ public class EnderMan extends Monster implements NeutralMob {
|
|
} else {
|
|
flag1 = flag && this.hurtWithCleanWater(world, source, (ThrownPotion) source.getDirectEntity(), amount);
|
|
|
|
+ if (!flag1 && world.purpurConfig.endermanIgnoreProjectiles) return super.hurtServer(world, source, amount); // Purpur
|
|
if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper - EndermanEscapeEvent
|
|
for (int i = 0; i < 64; ++i) {
|
|
if (this.teleport()) {
|
|
@@ -441,7 +474,7 @@ public class EnderMan extends Monster implements NeutralMob {
|
|
|
|
@Override
|
|
public boolean requiresCustomPersistence() {
|
|
- return super.requiresCustomPersistence() || this.getCarriedBlock() != null;
|
|
+ return super.requiresCustomPersistence() || (!this.level().purpurConfig.endermanDespawnEvenWithBlock && this.getCarriedBlock() != null); // Purpur
|
|
}
|
|
|
|
private static class EndermanFreezeWhenLookedAt extends Goal {
|
|
@@ -488,7 +521,16 @@ public class EnderMan extends Monster implements NeutralMob {
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
- return this.enderman.getCarriedBlock() == null ? false : (!getServerLevel((Entity) this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? false : this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0);
|
|
+ if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur
|
|
+ // Purpur start
|
|
+ if (this.enderman.getCarriedBlock() == null) {
|
|
+ return false;
|
|
+ }
|
|
+ if (!getServerLevel((Entity) this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !this.enderman.level().purpurConfig.endermanBypassMobGriefing) {
|
|
+ return false;
|
|
+ }
|
|
+ return this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0;
|
|
+ // Purpur end
|
|
}
|
|
|
|
@Override
|
|
@@ -533,7 +575,16 @@ public class EnderMan extends Monster implements NeutralMob {
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
- return this.enderman.getCarriedBlock() != null ? false : (!getServerLevel((Entity) this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? false : this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0);
|
|
+ if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur
|
|
+ // Purpur start
|
|
+ if (this.enderman.getCarriedBlock() != null) {
|
|
+ return false;
|
|
+ }
|
|
+ if (!getServerLevel((Entity) this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !this.enderman.level().purpurConfig.endermanBypassMobGriefing) {
|
|
+ return false;
|
|
+ }
|
|
+ return this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0;
|
|
+ // Purpur end
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Endermite.java b/src/main/java/net/minecraft/world/entity/monster/Endermite.java
|
|
index 534e98dd7291e09dee1d0f77cbf221b15708590f..f8373fc9839fccb31e3dd090de70e2cd7c9e6cfc 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Endermite.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Endermite.java
|
|
@@ -32,20 +32,64 @@ public class Endermite extends Monster {
|
|
|
|
private static final int MAX_LIFE = 2400;
|
|
public int life;
|
|
+ private boolean isPlayerSpawned; // Purpur
|
|
|
|
public Endermite(EntityType<? extends Endermite> type, Level world) {
|
|
super(type, world);
|
|
this.xpReward = 3;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.endermiteRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.endermiteRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.endermiteControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.endermiteMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.endermiteScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.endermiteTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ public boolean isPlayerSpawned() {
|
|
+ return this.isPlayerSpawned;
|
|
+ }
|
|
+
|
|
+ public void setPlayerSpawned(boolean playerSpawned) {
|
|
+ this.isPlayerSpawned = playerSpawned;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.endermiteAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(1, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new ClimbOnTopOfPowderSnowGoal(this, this.level()));
|
|
this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0D, false));
|
|
this.goalSelector.addGoal(3, new WaterAvoidingRandomStrollGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 8.0F));
|
|
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers());
|
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
|
}
|
|
@@ -83,12 +127,14 @@ public class Endermite extends Monster {
|
|
public void readAdditionalSaveData(CompoundTag nbt) {
|
|
super.readAdditionalSaveData(nbt);
|
|
this.life = nbt.getInt("Lifetime");
|
|
+ this.isPlayerSpawned = nbt.getBoolean("PlayerSpawned"); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void addAdditionalSaveData(CompoundTag nbt) {
|
|
super.addAdditionalSaveData(nbt);
|
|
nbt.putInt("Lifetime", this.life);
|
|
+ nbt.putBoolean("PlayerSpawned", this.isPlayerSpawned); // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Evoker.java b/src/main/java/net/minecraft/world/entity/monster/Evoker.java
|
|
index 6592baa53ecb4e364d1c1b6f64178fc86c59a982..732fa9c2bf22e488ba531c0f9fd2a7e08468ff63 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Evoker.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Evoker.java
|
|
@@ -53,10 +53,44 @@ public class Evoker extends SpellcasterIllager {
|
|
this.xpReward = 10;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.evokerRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.evokerRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.evokerControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.evokerMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.evokerScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.evokerTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.evokerAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
super.registerGoals();
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new Evoker.EvokerCastingSpellGoal());
|
|
this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 0.6D, 1.0D));
|
|
this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0D, 1.2D));
|
|
@@ -66,6 +100,7 @@ public class Evoker extends SpellcasterIllager {
|
|
this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D));
|
|
this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F));
|
|
this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers());
|
|
this.targetSelector.addGoal(2, (new NearestAttackableTargetGoal<>(this, Player.class, true)).setUnseenMemoryTicks(300));
|
|
this.targetSelector.addGoal(3, (new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)).setUnseenMemoryTicks(300));
|
|
@@ -342,7 +377,7 @@ public class Evoker extends SpellcasterIllager {
|
|
} else {
|
|
ServerLevel worldserver = getServerLevel(Evoker.this.level());
|
|
|
|
- if (!worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
|
+ if (!worldserver.purpurConfig.evokerBypassMobGriefing && !worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur
|
|
return false;
|
|
} else {
|
|
List<Sheep> list = worldserver.getNearbyEntities(Sheep.class, this.wololoTargeting, Evoker.this, Evoker.this.getBoundingBox().inflate(16.0D, 4.0D, 16.0D));
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Ghast.java b/src/main/java/net/minecraft/world/entity/monster/Ghast.java
|
|
index a8c8c03e972aa6352843cf4c3e4aebfb8f493125..173b10fa553db30c321bfd9eabe13915b63cf920 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Ghast.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Ghast.java
|
|
@@ -44,11 +44,47 @@ public class Ghast extends FlyingMob implements Enemy {
|
|
this.moveControl = new Ghast.GhastMoveControl(this);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.ghastRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ghastRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.ghastControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double getMaxY() {
|
|
+ return level().purpurConfig.ghastMaxY;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void travel(Vec3 vec3) {
|
|
+ super.travel(vec3);
|
|
+ if (getRider() != null && this.isControllable() && !onGround) {
|
|
+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED);
|
|
+ setSpeed(speed);
|
|
+ Vec3 mot = getDeltaMovement();
|
|
+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed));
|
|
+ setDeltaMovement(mot.scale(0.9D));
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(5, new Ghast.RandomFloatAroundGoal(this));
|
|
this.goalSelector.addGoal(7, new Ghast.GhastLookGoal(this));
|
|
this.goalSelector.addGoal(7, new Ghast.GhastShootFireballGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entityliving, worldserver) -> {
|
|
return Math.abs(entityliving.getY() - this.getY()) <= 4.0D;
|
|
}));
|
|
@@ -96,6 +132,22 @@ public class Ghast extends FlyingMob implements Enemy {
|
|
}
|
|
}
|
|
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ghastMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.ghastScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.ghastTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.ghastAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
|
super.defineSynchedData(builder);
|
|
@@ -103,7 +155,7 @@ public class Ghast extends FlyingMob implements Enemy {
|
|
}
|
|
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.FOLLOW_RANGE, 100.0D);
|
|
+ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.FOLLOW_RANGE, 100.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -155,7 +207,7 @@ public class Ghast extends FlyingMob implements Enemy {
|
|
|
|
}
|
|
|
|
- private static class GhastMoveControl extends MoveControl {
|
|
+ private static class GhastMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur
|
|
|
|
private final Ghast ghast;
|
|
private int floatDuration;
|
|
@@ -166,7 +218,7 @@ public class Ghast extends FlyingMob implements Enemy {
|
|
}
|
|
|
|
@Override
|
|
- public void tick() {
|
|
+ public void vanillaTick() { // Purpur
|
|
if (this.operation == MoveControl.Operation.MOVE_TO) {
|
|
if (this.floatDuration-- <= 0) {
|
|
this.floatDuration += this.ghast.getRandom().nextInt(5) + 2;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Giant.java b/src/main/java/net/minecraft/world/entity/monster/Giant.java
|
|
index 118521ae54254b0a73bb7cba7b2871c9c26f89fc..859d316825658c11f58dd92912edbee75eaeabb9 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Giant.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Giant.java
|
|
@@ -12,12 +12,95 @@ public class Giant extends Monster {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.giantRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.giantRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.giantControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void registerGoals() {
|
|
+ if (level().purpurConfig.giantHaveAI) {
|
|
+ this.goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this));
|
|
+ this.goalSelector.addGoal(7, new net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal(this, 1.0D));
|
|
+ this.goalSelector.addGoal(8, new net.minecraft.world.entity.ai.goal.LookAtPlayerGoal(this, net.minecraft.world.entity.player.Player.class, 16.0F));
|
|
+ this.goalSelector.addGoal(8, new net.minecraft.world.entity.ai.goal.RandomLookAroundGoal(this));
|
|
+ this.goalSelector.addGoal(5, new net.minecraft.world.entity.ai.goal.MoveTowardsRestrictionGoal(this, 1.0D));
|
|
+ if (level().purpurConfig.giantHaveHostileAI) {
|
|
+ this.goalSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.0D, false));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this));
|
|
+ this.targetSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal(this).setAlertOthers(ZombifiedPiglin.class));
|
|
+ this.targetSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.player.Player.class, true));
|
|
+ this.targetSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.npc.Villager.class, false));
|
|
+ this.targetSelector.addGoal(4, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.animal.IronGolem.class, true));
|
|
+ this.targetSelector.addGoal(5, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.animal.Turtle.class, true));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.giantTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.giantAlwaysDropExp;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.giantMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.giantScale);
|
|
+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.giantMovementSpeed);
|
|
+ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(this.level().purpurConfig.giantAttackDamage);
|
|
+ }
|
|
+
|
|
+ // Purpur end
|
|
+
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 100.0).add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.ATTACK_DAMAGE, 50.0);
|
|
}
|
|
|
|
+ @Override
|
|
+ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.EntitySpawnReason spawnReason, @org.jetbrains.annotations.Nullable net.minecraft.world.entity.SpawnGroupData entityData) {
|
|
+ net.minecraft.world.entity.SpawnGroupData groupData = super.finalizeSpawn(world, difficulty, spawnReason, entityData);
|
|
+ if (groupData == null) {
|
|
+ populateDefaultEquipmentSlots(this.random, difficulty);
|
|
+ populateDefaultEquipmentEnchantments(world, this.random, difficulty);
|
|
+ }
|
|
+ return groupData;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void populateDefaultEquipmentSlots(net.minecraft.util.RandomSource random, net.minecraft.world.DifficultyInstance difficulty) {
|
|
+ super.populateDefaultEquipmentSlots(this.random, difficulty);
|
|
+ // TODO make configurable
|
|
+ if (random.nextFloat() < (level().getDifficulty() == net.minecraft.world.Difficulty.HARD ? 0.1F : 0.05F)) {
|
|
+ this.setItemSlot(net.minecraft.world.entity.EquipmentSlot.MAINHAND, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.IRON_SWORD));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public float getJumpPower() {
|
|
+ // make giants jump as high as everything else relative to their size
|
|
+ // 1.0 makes bottom of feet about as high as their waist when they jump
|
|
+ return level().purpurConfig.giantJumpHeight;
|
|
+ }
|
|
+
|
|
@Override
|
|
public float getWalkTargetValue(BlockPos pos, LevelReader world) {
|
|
- return world.getPathfindingCostFromLightLevels(pos);
|
|
+ return super.getWalkTargetValue(pos, world); // Purpur - fix light requirements for natural spawns
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Guardian.java b/src/main/java/net/minecraft/world/entity/monster/Guardian.java
|
|
index 951f46684623582980901c1ebc1870aa5bcf25a1..da833bf35342f771ecccd5dcac4fe87f72d047b0 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Guardian.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Guardian.java
|
|
@@ -67,15 +67,52 @@ public class Guardian extends Monster {
|
|
this.xpReward = 10;
|
|
this.setPathfindingMalus(PathType.WATER, 0.0F);
|
|
this.moveControl = new Guardian.GuardianMoveControl(this);
|
|
+ // Purpur start
|
|
+ this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this) {
|
|
+ @Override
|
|
+ public void setYawPitch(float yaw, float pitch) {
|
|
+ super.setYawPitch(yaw, pitch * 0.35F);
|
|
+ }
|
|
+ };
|
|
+ // Purpur end
|
|
this.clientSideTailAnimation = this.random.nextFloat();
|
|
this.clientSideTailAnimationO = this.clientSideTailAnimation;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.guardianRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.guardianControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.guardianMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.guardianScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.guardianTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.guardianAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
MoveTowardsRestrictionGoal pathfindergoalmovetowardsrestriction = new MoveTowardsRestrictionGoal(this, 1.0D);
|
|
|
|
this.randomStrollGoal = new RandomStrollGoal(this, 1.0D, 80);
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(4, this.guardianAttackGoal = new Guardian.GuardianAttackGoal(this)); // CraftBukkit - assign field
|
|
this.goalSelector.addGoal(5, pathfindergoalmovetowardsrestriction);
|
|
this.goalSelector.addGoal(7, this.randomStrollGoal);
|
|
@@ -84,6 +121,7 @@ public class Guardian extends Monster {
|
|
this.goalSelector.addGoal(9, new RandomLookAroundGoal(this));
|
|
this.randomStrollGoal.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
|
|
pathfindergoalmovetowardsrestriction.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 10, true, false, new Guardian.GuardianAttackSelector(this)));
|
|
}
|
|
|
|
@@ -330,7 +368,7 @@ public class Guardian extends Monster {
|
|
@Override
|
|
public void travel(Vec3 movementInput) {
|
|
if (this.isControlledByLocalInstance() && this.isInWater()) {
|
|
- this.moveRelative(0.1F, movementInput);
|
|
+ this.moveRelative(getRider() != null && this.isControllable() ? getSpeed() : 0.1F, movementInput); // Purpur
|
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
|
this.setDeltaMovement(this.getDeltaMovement().scale(0.9D));
|
|
if (!this.isMoving() && this.getTarget() == null) {
|
|
@@ -342,7 +380,7 @@ public class Guardian extends Monster {
|
|
|
|
}
|
|
|
|
- private static class GuardianMoveControl extends MoveControl {
|
|
+ private static class GuardianMoveControl extends org.purpurmc.purpur.controller.WaterMoveControllerWASD { // Purpur
|
|
|
|
private final Guardian guardian;
|
|
|
|
@@ -351,8 +389,17 @@ public class Guardian extends Monster {
|
|
this.guardian = guardian;
|
|
}
|
|
|
|
+ // Purpur start
|
|
@Override
|
|
- public void tick() {
|
|
+ public void purpurTick(Player rider) {
|
|
+ super.purpurTick(rider);
|
|
+ guardian.setDeltaMovement(guardian.getDeltaMovement().add(0.0D, 0.005D, 0.0D));
|
|
+ guardian.setMoving(guardian.getForwardMot() > 0.0F); // control tail speed
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void vanillaTick() { // Purpur
|
|
if (this.operation == MoveControl.Operation.MOVE_TO && !this.guardian.getNavigation().isDone()) {
|
|
Vec3 vec3d = new Vec3(this.wantedX - this.guardian.getX(), this.wantedY - this.guardian.getY(), this.wantedZ - this.guardian.getZ());
|
|
double d0 = vec3d.length();
|
|
@@ -363,7 +410,7 @@ public class Guardian extends Monster {
|
|
|
|
this.guardian.setYRot(this.rotlerp(this.guardian.getYRot(), f, 90.0F));
|
|
this.guardian.yBodyRot = this.guardian.getYRot();
|
|
- float f1 = (float) (this.speedModifier * this.guardian.getAttributeValue(Attributes.MOVEMENT_SPEED));
|
|
+ float f1 = (float) (this.getSpeedModifier() * this.guardian.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur
|
|
float f2 = Mth.lerp(0.125F, this.guardian.getSpeed(), f1);
|
|
|
|
this.guardian.setSpeed(f2);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Husk.java b/src/main/java/net/minecraft/world/entity/monster/Husk.java
|
|
index 184fa759db065fb345f3623752229430816d8ad3..7c8ec5cd88fb2083f458a945e716b6f118555db8 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Husk.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Husk.java
|
|
@@ -21,6 +21,59 @@ public class Husk extends Zombie {
|
|
|
|
public Husk(EntityType<? extends Husk> type, Level world) {
|
|
super(type, world);
|
|
+ this.setShouldBurnInDay(false); // Purpur - API for any mob to burn daylight
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.huskRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.huskRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.huskControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.huskMaxHealth);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ 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;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.huskTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.huskAlwaysDropExp;
|
|
}
|
|
|
|
public static boolean checkHuskSpawnRules(EntityType<Husk> type, ServerLevelAccessor world, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random) {
|
|
@@ -29,7 +82,7 @@ public class Husk extends Zombie {
|
|
|
|
@Override
|
|
public boolean isSunSensitive() {
|
|
- return false;
|
|
+ return this.shouldBurnInDay; // Purpur - moved to LivingEntity; keep methods for ABI compatibility - API for any mob to burn daylight
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java
|
|
index db3aac9ba711dcd18ffc35c4a745ecaec89d0166..2ca241344efc6320d2018bdc772f74470080eeed 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java
|
|
@@ -59,10 +59,46 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
|
|
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.illusionerRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.illusionerRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.illusionerControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ protected void initAttributes() {
|
|
+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.illusionerMovementSpeed);
|
|
+ this.getAttribute(Attributes.FOLLOW_RANGE).setBaseValue(this.level().purpurConfig.illusionerFollowRange);
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.illusionerMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.illusionerScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.illusionerTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.illusionerAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
super.registerGoals();
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new SpellcasterIllager.SpellcasterCastingSpellGoal());
|
|
this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0D, 1.2D));
|
|
this.goalSelector.addGoal(4, new Illusioner.IllusionerMirrorSpellGoal());
|
|
@@ -71,6 +107,7 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
|
|
this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D));
|
|
this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F));
|
|
this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers());
|
|
this.targetSelector.addGoal(2, (new NearestAttackableTargetGoal<>(this, Player.class, true)).setUnseenMemoryTicks(300));
|
|
this.targetSelector.addGoal(3, (new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)).setUnseenMemoryTicks(300));
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java
|
|
index ae710c3fffc7840a9ff2cbc5cdacef8a2e248253..63caf20256a3deae98b9cd9f54650def172f0e57 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java
|
|
@@ -24,6 +24,58 @@ public class MagmaCube extends Slime {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.magmaCubeRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.magmaCubeRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.magmaCubeControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public float getJumpPower() {
|
|
+ return 0.42F * this.getBlockJumpFactor(); // from EntityLiving
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ protected String getMaxHealthEquation() {
|
|
+ return level().purpurConfig.magmaCubeMaxHealth;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected String getAttackDamageEquation() {
|
|
+ return level().purpurConfig.magmaCubeAttackDamage;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected java.util.Map<Integer, Double> getMaxHealthCache() {
|
|
+ return level().purpurConfig.magmaCubeMaxHealthCache;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected java.util.Map<Integer, Double> getAttackDamageCache() {
|
|
+ return level().purpurConfig.magmaCubeAttackDamageCache;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.magmaCubeTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.magmaCubeAlwaysDropExp;
|
|
+ }
|
|
+
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F);
|
|
}
|
|
@@ -71,6 +123,7 @@ public class MagmaCube extends Slime {
|
|
float f = (float)this.getSize() * 0.1F;
|
|
this.setDeltaMovement(vec3.x, (double)(this.getJumpPower() + f), vec3.z);
|
|
this.hasImpulse = true;
|
|
+ this.actualJump = false; // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Monster.java b/src/main/java/net/minecraft/world/entity/monster/Monster.java
|
|
index e2de074bbe7bab0e5a7aecc1fae4c5914a203dd4..c2061f575c731ecc6071384b007517c08e0cf983 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Monster.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Monster.java
|
|
@@ -88,6 +88,14 @@ public abstract class Monster extends PathfinderMob implements Enemy {
|
|
}
|
|
|
|
public static boolean isDarkEnoughToSpawn(ServerLevelAccessor world, BlockPos pos, RandomSource random) {
|
|
+ // Purpur start
|
|
+ if (!world.getMinecraftWorld().purpurConfig.mobsSpawnOnPackedIce || !world.getMinecraftWorld().purpurConfig.mobsSpawnOnBlueIce) {
|
|
+ net.minecraft.world.level.block.state.BlockState spawnBlock = world.getBlockState(pos.below());
|
|
+ if ((!world.getMinecraftWorld().purpurConfig.mobsSpawnOnPackedIce && spawnBlock.is(net.minecraft.world.level.block.Blocks.PACKED_ICE)) || (!world.getMinecraftWorld().purpurConfig.mobsSpawnOnBlueIce && spawnBlock.is(net.minecraft.world.level.block.Blocks.BLUE_ICE))) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
if (world.getBrightness(LightLayer.SKY, pos) > random.nextInt(32)) {
|
|
return false;
|
|
} else {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
|
index 150fd890ac65097b5434fd88e8d2b24a89dca79a..cda6cb5b10b895bab48d2212f259ba4ca40e1ed6 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
|
@@ -49,6 +49,8 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
Vec3 moveTargetPoint;
|
|
public BlockPos anchorPoint;
|
|
Phantom.AttackPhase attackPhase;
|
|
+ private static final net.minecraft.world.item.crafting.Ingredient TORCH = net.minecraft.world.item.crafting.Ingredient.of(net.minecraft.world.item.Items.TORCH, net.minecraft.world.item.Items.SOUL_TORCH); // Purpur
|
|
+ Vec3 crystalPosition; // Purpur
|
|
|
|
public Phantom(EntityType<? extends Phantom> type, Level world) {
|
|
super(type, world);
|
|
@@ -58,6 +60,92 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
this.xpReward = 5;
|
|
this.moveControl = new Phantom.PhantomMoveControl(this);
|
|
this.lookControl = new Phantom.PhantomLookControl(this, this);
|
|
+ this.setShouldBurnInDay(true); // Purpur - API for any mob to burn daylight
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.phantomRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.phantomRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.phantomControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double getMaxY() {
|
|
+ return level().purpurConfig.phantomMaxY;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void travel(Vec3 vec3) {
|
|
+ super.travel(vec3);
|
|
+ if (getRider() != null && this.isControllable() && !onGround) {
|
|
+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED);
|
|
+ setSpeed(speed);
|
|
+ Vec3 mot = getDeltaMovement();
|
|
+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, speed, speed));
|
|
+ setDeltaMovement(mot.scale(0.9D));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static net.minecraft.world.entity.ai.attributes.AttributeSupplier.Builder createAttributes() {
|
|
+ return Monster.createMonsterAttributes().add(Attributes.FLYING_SPEED, 3.0D);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean onSpacebar() {
|
|
+ if (getRider() != null && getRider().getBukkitEntity().hasPermission("allow.special.phantom")) {
|
|
+ shoot();
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ public boolean shoot() {
|
|
+ org.bukkit.Location loc = ((org.bukkit.entity.LivingEntity) getBukkitEntity()).getEyeLocation();
|
|
+ loc.setPitch(-loc.getPitch());
|
|
+ org.bukkit.util.Vector target = loc.getDirection().normalize().multiply(100).add(loc.toVector());
|
|
+
|
|
+ org.purpurmc.purpur.entity.PhantomFlames flames = new org.purpurmc.purpur.entity.PhantomFlames(level(), this);
|
|
+ flames.canGrief = level().purpurConfig.phantomAllowGriefing;
|
|
+ flames.shoot(target.getX() - getX(), target.getY() - getY(), target.getZ() - getZ(), 1.0F, 5.0F);
|
|
+ level().addFreshEntity(flames);
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void dropFromLootTable(ServerLevel world, DamageSource damageSource, boolean causedByPlayer) {
|
|
+ boolean dropped = false;
|
|
+ if (lastHurtByPlayer == null && damageSource.getEntity() instanceof net.minecraft.world.entity.boss.enderdragon.EndCrystal) {
|
|
+ if (random.nextInt(5) < 1) {
|
|
+ dropped = spawnAtLocation(world, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.PHANTOM_MEMBRANE)) != null;
|
|
+ }
|
|
+ }
|
|
+ if (!dropped) {
|
|
+ super.dropFromLootTable(world, damageSource, causedByPlayer);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public boolean isCirclingCrystal() {
|
|
+ return crystalPosition != null;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.phantomTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.phantomAlwaysDropExp;
|
|
}
|
|
|
|
@Override
|
|
@@ -72,9 +160,17 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
|
|
@Override
|
|
protected void registerGoals() {
|
|
- this.goalSelector.addGoal(1, new Phantom.PhantomAttackStrategyGoal());
|
|
- this.goalSelector.addGoal(2, new Phantom.PhantomSweepAttackGoal());
|
|
- this.goalSelector.addGoal(3, new Phantom.PhantomCircleAroundAnchorGoal());
|
|
+ // Purpur start
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.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 org.purpurmc.purpur.entity.ai.HasRider(this));
|
|
+ // Purpur end
|
|
this.targetSelector.addGoal(1, new Phantom.PhantomAttackPlayerTargetGoal());
|
|
}
|
|
|
|
@@ -90,7 +186,10 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
|
|
private void updatePhantomSizeInfo() {
|
|
this.refreshDimensions();
|
|
- this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue((double) (6 + this.getPhantomSize()));
|
|
+ // Purpur start
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(getFromCache(() -> this.level().purpurConfig.phantomMaxHealth, () -> this.level().purpurConfig.phantomMaxHealthCache, () -> 20.0D));
|
|
+ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(getFromCache(() -> this.level().purpurConfig.phantomAttackDamage, () -> this.level().purpurConfig.phantomAttackDamageCache, () -> (double) 6 + this.getPhantomSize()));
|
|
+ // Purpur end
|
|
}
|
|
|
|
public int getPhantomSize() {
|
|
@@ -115,6 +214,21 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
return true;
|
|
}
|
|
|
|
+ private double getFromCache(java.util.function.Supplier<String> equation, java.util.function.Supplier<java.util.Map<Integer, Double>> cache, java.util.function.Supplier<Double> defaultValue) {
|
|
+ int size = getPhantomSize();
|
|
+ Double value = cache.get().get(size);
|
|
+ if (value == null) {
|
|
+ try {
|
|
+ value = ((Number) scriptEngine.eval("let size = " + size + "; " + equation.get())).doubleValue();
|
|
+ } catch (javax.script.ScriptException e) {
|
|
+ e.printStackTrace();
|
|
+ value = defaultValue.get();
|
|
+ }
|
|
+ cache.get().put(size, value);
|
|
+ }
|
|
+ return value;
|
|
+ }
|
|
+
|
|
@Override
|
|
public void tick() {
|
|
super.tick();
|
|
@@ -135,21 +249,23 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
this.level().addParticle(ParticleTypes.MYCELIUM, this.getX() - (double) f3, this.getY() + (double) f5, this.getZ() - (double) f4, 0.0D, 0.0D, 0.0D);
|
|
}
|
|
|
|
+ if (level().purpurConfig.phantomFlamesOnSwoop && attackPhase == AttackPhase.SWOOP) shoot(); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void aiStep() {
|
|
- if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API
|
|
- this.igniteForSeconds(8.0F);
|
|
- }
|
|
-
|
|
+ // Purpur - implemented in LivingEntity; moved down to shouldBurnInDay() - API for any mob to burn daylight
|
|
super.aiStep();
|
|
}
|
|
|
|
@Override
|
|
public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) {
|
|
this.anchorPoint = this.blockPosition().above(5);
|
|
- this.setPhantomSize(0);
|
|
+ // Purpur start
|
|
+ int min = world.getLevel().purpurConfig.phantomMinSize;
|
|
+ int max = world.getLevel().purpurConfig.phantomMaxSize;
|
|
+ this.setPhantomSize(min == max ? min : world.getRandom().nextInt(max + 1 - min) + min);
|
|
+ // Purpur end
|
|
return super.finalizeSpawn(world, difficulty, spawnReason, entityData);
|
|
}
|
|
|
|
@@ -165,7 +281,7 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
if (nbt.hasUUID("Paper.SpawningEntity")) {
|
|
this.spawningEntity = nbt.getUUID("Paper.SpawningEntity");
|
|
}
|
|
- if (nbt.contains("Paper.ShouldBurnInDay")) {
|
|
+ if (false && nbt.contains("Paper.ShouldBurnInDay")) { // Purpur - implemented in LivingEntity - API for any mob to burn daylight
|
|
this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay");
|
|
}
|
|
// Paper end
|
|
@@ -182,7 +298,7 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
if (this.spawningEntity != null) {
|
|
nbt.putUUID("Paper.SpawningEntity", this.spawningEntity);
|
|
}
|
|
- nbt.putBoolean("Paper.ShouldBurnInDay", shouldBurnInDay);
|
|
+ //nbt.putBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); // Purpur - implemented in LivingEntity - API for any mob to burn daylight
|
|
// Paper end
|
|
}
|
|
|
|
@@ -242,8 +358,14 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
return this.spawningEntity;
|
|
}
|
|
public void setSpawningEntity(java.util.UUID entity) { this.spawningEntity = entity; }
|
|
- private boolean shouldBurnInDay = true;
|
|
- public boolean shouldBurnInDay() { return shouldBurnInDay; }
|
|
+ //private boolean shouldBurnInDay = true; // Purpur - moved to LivingEntity; keep methods for ABI compatibility - API for any mob to burn daylight
|
|
+ // Purpur start - API for any mob to burn daylight
|
|
+ public boolean shouldBurnInDay() {
|
|
+ boolean burnFromDaylight = this.shouldBurnInDay && this.level().purpurConfig.phantomBurnInDaylight;
|
|
+ boolean burnFromLightSource = this.level().purpurConfig.phantomBurnInLight > 0 && this.level().getMaxLocalRawBrightness(blockPosition()) >= this.level().purpurConfig.phantomBurnInLight;
|
|
+ return burnFromDaylight || burnFromLightSource;
|
|
+ }
|
|
+ // Purpur end - API for any mob to burn daylight
|
|
public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; }
|
|
// Paper end
|
|
|
|
@@ -254,7 +376,125 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
private AttackPhase() {}
|
|
}
|
|
|
|
- private class PhantomMoveControl extends MoveControl {
|
|
+ // 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 org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur
|
|
|
|
private float speed = 0.1F;
|
|
|
|
@@ -262,8 +502,19 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
super(entity);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public void purpurTick(Player rider) {
|
|
+ if (!Phantom.this.onGround) {
|
|
+ // phantom is always in motion when flying
|
|
+ // TODO - FIX THIS
|
|
+ // rider.setForward(1.0F);
|
|
+ }
|
|
+ super.purpurTick(rider);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
- public void tick() {
|
|
+ public void vanillaTick() { // Purpur
|
|
if (Phantom.this.horizontalCollision) {
|
|
Phantom.this.setYRot(Phantom.this.getYRot() + 180.0F);
|
|
this.speed = 0.1F;
|
|
@@ -309,14 +560,20 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
}
|
|
}
|
|
|
|
- private class PhantomLookControl extends LookControl {
|
|
+ private class PhantomLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur
|
|
|
|
public PhantomLookControl(final Phantom entity, final Mob phantom) {
|
|
super(phantom);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public void purpurTick(Player rider) {
|
|
+ setYawPitch(rider.getYRot(), -rider.xRotO * 0.75F);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
- public void tick() {}
|
|
+ public void vanillaTick() {} // Purpur
|
|
}
|
|
|
|
private class PhantomBodyRotationControl extends BodyRotationControl {
|
|
@@ -403,6 +660,12 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
return false;
|
|
} else if (!entityliving.isAlive()) {
|
|
return false;
|
|
+ // Purpur start
|
|
+ } else if (level().purpurConfig.phantomBurnInLight > 0 && level().getLightEmission(new BlockPos(Phantom.this)) >= level().purpurConfig.phantomBurnInLight) {
|
|
+ return false;
|
|
+ } else if (level().purpurConfig.phantomIgnorePlayersWithTorch && (TORCH.test(entityliving.getItemInHand(net.minecraft.world.InteractionHand.MAIN_HAND)) || TORCH.test(entityliving.getItemInHand(net.minecraft.world.InteractionHand.OFF_HAND)))) {
|
|
+ return false;
|
|
+ // Purpur end
|
|
} else {
|
|
if (entityliving instanceof Player) {
|
|
Player entityhuman = (Player) entityliving;
|
|
@@ -549,6 +812,7 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
ServerLevel worldserver = getServerLevel(Phantom.this.level());
|
|
List<Player> list = worldserver.getNearbyPlayers(this.attackTargeting, Phantom.this, Phantom.this.getBoundingBox().inflate(16.0D, 64.0D, 16.0D));
|
|
|
|
+ if (level().purpurConfig.phantomIgnorePlayersWithTorch) list.removeIf(human -> TORCH.test(human.getItemInHand(net.minecraft.world.InteractionHand.MAIN_HAND)) || TORCH.test(human.getItemInHand(net.minecraft.world.InteractionHand.OFF_HAND)));// Purpur
|
|
if (!list.isEmpty()) {
|
|
list.sort(Comparator.comparing((Entity e) -> { return e.getY(); }).reversed()); // CraftBukkit - decompile error
|
|
Iterator iterator = list.iterator();
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Pillager.java b/src/main/java/net/minecraft/world/entity/monster/Pillager.java
|
|
index 3e8631c7bd1e7591051ca21c6ae7acd87d3c7529..85d5c84a8861905e4546901aa6707078571eb402 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Pillager.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Pillager.java
|
|
@@ -64,16 +64,51 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.pillagerRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.pillagerRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.pillagerControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.pillagerMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.pillagerScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.pillagerTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.pillagerAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
super.registerGoals();
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0D, 1.2D));
|
|
this.goalSelector.addGoal(2, new Raider.HoldGroundAttackGoal(this, 10.0F)); // Paper - decomp fix
|
|
this.goalSelector.addGoal(3, new RangedCrossbowAttackGoal<>(this, 1.0D, 8.0F));
|
|
this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D));
|
|
this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 15.0F, 1.0F));
|
|
this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 15.0F));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers());
|
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false));
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java
|
|
index c96fbfe448b3e7b722a8db0e1688276776abd94e..487f21c6e6ffc0dc9c0733241a8ded8c73a5ec8f 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java
|
|
@@ -77,15 +77,57 @@ public class Ravager extends Raider {
|
|
this.setPathfindingMalus(PathType.LEAVES, 0.0F);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.ravagerRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ravagerRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.ravagerControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onMount(Player rider) {
|
|
+ super.onMount(rider);
|
|
+ getNavigation().stop();
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ravagerMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.ravagerScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.ravagerTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.ravagerAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
super.registerGoals();
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0D, 1.2D));
|
|
+ if (level().purpurConfig.ravagerAvoidRabbits) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.AvoidEntityGoal<>(this, net.minecraft.world.entity.animal.Rabbit.class, 6.0F, 1.0D, 1.2D)); // Purpur
|
|
this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0D, true));
|
|
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.4D));
|
|
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F));
|
|
this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(2, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers());
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
|
this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true, (entityliving, worldserver) -> {
|
|
@@ -138,7 +180,7 @@ public class Ravager extends Raider {
|
|
@Override
|
|
public void aiStep() {
|
|
super.aiStep();
|
|
- if (this.isAlive()) {
|
|
+ if (this.isAlive() && (getRider() == null || !this.isControllable())) { // Purpur
|
|
if (this.isImmobile()) {
|
|
this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.0D);
|
|
} else {
|
|
@@ -153,7 +195,7 @@ public class Ravager extends Raider {
|
|
if (world instanceof ServerLevel) {
|
|
ServerLevel worldserver = (ServerLevel) world;
|
|
|
|
- if (this.horizontalCollision && worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
|
+ if (this.horizontalCollision && (worldserver.purpurConfig.ravagerBypassMobGriefing || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // Purpur
|
|
boolean flag = false;
|
|
AABB axisalignedbb = this.getBoundingBox().inflate(0.2D);
|
|
Iterator iterator = BlockPos.betweenClosed(Mth.floor(axisalignedbb.minX), Mth.floor(axisalignedbb.minY), Mth.floor(axisalignedbb.minZ), Mth.floor(axisalignedbb.maxX), Mth.floor(axisalignedbb.maxY), Mth.floor(axisalignedbb.maxZ)).iterator();
|
|
@@ -163,7 +205,7 @@ public class Ravager extends Raider {
|
|
BlockState iblockdata = worldserver.getBlockState(blockposition);
|
|
Block block = iblockdata.getBlock();
|
|
|
|
- if (block instanceof LeavesBlock) {
|
|
+ if (this.level().purpurConfig.ravagerGriefableBlocks.contains(block)) { // Purpur
|
|
// CraftBukkit start
|
|
if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state
|
|
continue;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java
|
|
index 6e0f2f6573ed6be9b91de960d55c269417ad8907..e3fefd52c83079fe3eab1a96dd81a183f718192b 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java
|
|
@@ -84,7 +84,7 @@ public class Shulker extends AbstractGolem implements VariantHolder<Optional<Dye
|
|
|
|
return new Vector3f((float) baseblockposition.getX(), (float) baseblockposition.getY(), (float) baseblockposition.getZ());
|
|
});
|
|
- private static final float MAX_SCALE = 3.0F;
|
|
+ public static final float MAX_SCALE = 3.0F; // Purpur
|
|
private float currentPeekAmountO;
|
|
private float currentPeekAmount;
|
|
@Nullable
|
|
@@ -98,12 +98,60 @@ public class Shulker extends AbstractGolem implements VariantHolder<Optional<Dye
|
|
this.lookControl = new Shulker.ShulkerLookControl(this);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.shulkerRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.shulkerRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.shulkerControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.shulkerMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.shulkerScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.shulkerTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected net.minecraft.world.InteractionResult mobInteract(Player player, net.minecraft.world.InteractionHand hand) {
|
|
+ net.minecraft.world.item.ItemStack itemstack = player.getItemInHand(hand);
|
|
+ if (player.level().purpurConfig.shulkerChangeColorWithDye && itemstack.getItem() instanceof net.minecraft.world.item.DyeItem dye && dye.getDyeColor() != this.getColor()) {
|
|
+ this.setVariant(Optional.of(dye.getDyeColor()));
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ itemstack.shrink(1);
|
|
+ }
|
|
+ return net.minecraft.world.InteractionResult.SUCCESS;
|
|
+ }
|
|
+ return super.mobInteract(player, hand);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.shulkerAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new LookAtPlayerGoal(this, Player.class, 8.0F, 0.02F, true));
|
|
this.goalSelector.addGoal(4, new Shulker.ShulkerAttackGoal());
|
|
this.goalSelector.addGoal(7, new Shulker.ShulkerPeekGoal());
|
|
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{this.getClass()})).setAlertOthers());
|
|
this.targetSelector.addGoal(2, new Shulker.ShulkerNearestAttackGoal(this));
|
|
this.targetSelector.addGoal(3, new Shulker.ShulkerDefenseAttackGoal(this));
|
|
@@ -482,12 +530,21 @@ public class Shulker extends AbstractGolem implements VariantHolder<Optional<Dye
|
|
Vec3 vec3d = this.position();
|
|
AABB axisalignedbb = this.getBoundingBox();
|
|
|
|
- if (!this.isClosed() && this.teleportSomewhere()) {
|
|
- int i = this.level().getEntities((EntityTypeTest) EntityType.SHULKER, axisalignedbb.inflate(8.0D), Entity::isAlive).size();
|
|
- float f = (float) (i - 1) / 5.0F;
|
|
-
|
|
- if (this.level().random.nextFloat() >= f) {
|
|
+ if ((!this.level().purpurConfig.shulkerSpawnFromBulletRequireOpenLid || !this.isClosed()) && this.teleportSomewhere()) {
|
|
+ // Purpur start
|
|
+ float chance = this.level().purpurConfig.shulkerSpawnFromBulletBaseChance;
|
|
+ if (!this.level().purpurConfig.shulkerSpawnFromBulletNearbyEquation.isBlank()) {
|
|
+ int nearby = this.level().getEntities((EntityTypeTest) EntityType.SHULKER, axisalignedbb.inflate(this.level().purpurConfig.shulkerSpawnFromBulletNearbyRange), Entity::isAlive).size();
|
|
+ try {
|
|
+ chance -= ((Number) scriptEngine.eval("let nearby = " + nearby + "; " + this.level().purpurConfig.shulkerSpawnFromBulletNearbyEquation)).floatValue();
|
|
+ } catch (javax.script.ScriptException e) {
|
|
+ e.printStackTrace();
|
|
+ chance -= (nearby - 1) / 5.0F;
|
|
+ }
|
|
+ }
|
|
+ if (this.level().random.nextFloat() <= chance) {
|
|
Shulker entityshulker = (Shulker) EntityType.SHULKER.create(this.level(), EntitySpawnReason.BREEDING);
|
|
+ // Purpur end
|
|
|
|
if (entityshulker != null) {
|
|
entityshulker.setVariant(this.getVariant());
|
|
@@ -590,7 +647,7 @@ public class Shulker extends AbstractGolem implements VariantHolder<Optional<Dye
|
|
|
|
@Override
|
|
protected float sanitizeScale(float scale) {
|
|
- return Math.min(scale, 3.0F);
|
|
+ return Math.min(scale, 3.0F); // Purpur - diff on change
|
|
}
|
|
|
|
public void setVariant(Optional<DyeColor> variant) {
|
|
@@ -601,7 +658,7 @@ public class Shulker extends AbstractGolem implements VariantHolder<Optional<Dye
|
|
|
|
@Override
|
|
public Optional<DyeColor> getVariant() {
|
|
- return Optional.ofNullable(this.getColor());
|
|
+ return Optional.ofNullable(this.level().purpurConfig.shulkerSpawnFromBulletRandomColor ? DyeColor.random(this.level().random) : this.getColor()); // Purpur
|
|
}
|
|
|
|
@Nullable
|
|
@@ -611,7 +668,7 @@ public class Shulker extends AbstractGolem implements VariantHolder<Optional<Dye
|
|
return b0 != 16 && b0 <= 15 ? DyeColor.byId(b0) : null;
|
|
}
|
|
|
|
- private class ShulkerLookControl extends LookControl {
|
|
+ private class ShulkerLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur
|
|
|
|
public ShulkerLookControl(final Mob entity) {
|
|
super(entity);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
|
|
index ff65cb8ea5233f2dd159f42ad53bc9d300cd604f..ece70d8303e563df416fc6703e6d7d2e23ee220a 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
|
|
@@ -44,14 +44,51 @@ public class Silverfish extends Monster {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.silverfishRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.silverfishRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.silverfishControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.silverfishMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.silverfishScale);
|
|
+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.silverfishMovementSpeed);
|
|
+ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(this.level().purpurConfig.silverfishAttackDamage);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.silverfishTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.silverfishAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.friendsGoal = new Silverfish.SilverfishWakeUpFriendsGoal(this);
|
|
this.goalSelector.addGoal(1, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new ClimbOnTopOfPowderSnowGoal(this, this.level()));
|
|
this.goalSelector.addGoal(3, this.friendsGoal);
|
|
this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0D, false));
|
|
this.goalSelector.addGoal(5, new Silverfish.SilverfishMergeWithStoneGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers());
|
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
|
}
|
|
@@ -170,7 +207,7 @@ public class Silverfish extends Monster {
|
|
continue;
|
|
}
|
|
// CraftBukkit end
|
|
- if (getServerLevel(world).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
|
+ if (getServerLevel(world).purpurConfig.silverfishBypassMobGriefing || getServerLevel(world).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur
|
|
world.destroyBlock(blockposition1, true, this.silverfish);
|
|
} else {
|
|
world.setBlock(blockposition1, ((InfestedBlock) block).hostStateByInfested(world.getBlockState(blockposition1)), 3);
|
|
@@ -208,7 +245,7 @@ public class Silverfish extends Monster {
|
|
} else {
|
|
RandomSource randomsource = this.mob.getRandom();
|
|
|
|
- if (getServerLevel((Entity) this.mob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && randomsource.nextInt(reducedTickDelay(10)) == 0) {
|
|
+ if (getServerLevel((Entity) this.mob).purpurConfig.silverfishBypassMobGriefing || getServerLevel((Entity) this.mob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && randomsource.nextInt(reducedTickDelay(10)) == 0) { // Purpur
|
|
this.selectedDirection = Direction.getRandom(randomsource);
|
|
BlockPos blockposition = BlockPos.containing(this.mob.getX(), this.mob.getY() + 0.5D, this.mob.getZ()).relative(this.selectedDirection);
|
|
BlockState iblockdata = this.mob.level().getBlockState(blockposition);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java
|
|
index 3972e2ed0554e2550519e994888e068df0a151e5..3cbe4c1ed514936a00e0181cb1e647fbb58032bb 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java
|
|
@@ -17,6 +17,16 @@ import net.minecraft.world.item.Items;
|
|
import net.minecraft.world.level.ItemLike;
|
|
import net.minecraft.world.level.Level;
|
|
|
|
+// Purpur start
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.level.block.Blocks;
|
|
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
|
+import net.minecraft.world.InteractionHand;
|
|
+import net.minecraft.world.InteractionResult;
|
|
+import net.minecraft.server.level.ServerLevel;
|
|
+import net.minecraft.core.particles.ParticleTypes;
|
|
+// Purpur end
|
|
+
|
|
public class Skeleton extends AbstractSkeleton {
|
|
|
|
private static final int TOTAL_CONVERSION_TIME = 300;
|
|
@@ -29,6 +39,40 @@ public class Skeleton extends AbstractSkeleton {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.skeletonRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.skeletonRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.skeletonControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.skeletonMaxHealth);
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.skeletonTakeDamageFromWater;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.skeletonAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
|
super.defineSynchedData(builder);
|
|
@@ -147,4 +191,63 @@ public class Skeleton extends AbstractSkeleton {
|
|
}
|
|
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ private int witherRosesFed = 0;
|
|
+
|
|
+ @Override
|
|
+ public InteractionResult mobInteract(Player player, InteractionHand hand) {
|
|
+ ItemStack stack = player.getItemInHand(hand);
|
|
+
|
|
+ if (level().purpurConfig.skeletonFeedWitherRoses > 0 && this.getType() != EntityType.WITHER_SKELETON && stack.getItem() == Blocks.WITHER_ROSE.asItem()) {
|
|
+ return this.feedWitherRose(player, stack);
|
|
+ }
|
|
+
|
|
+ return super.mobInteract(player, hand);
|
|
+ }
|
|
+
|
|
+ private InteractionResult feedWitherRose(Player player, ItemStack stack) {
|
|
+ if (++witherRosesFed < level().purpurConfig.skeletonFeedWitherRoses) {
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ stack.shrink(1);
|
|
+ }
|
|
+ return InteractionResult.CONSUME;
|
|
+ }
|
|
+
|
|
+ WitherSkeleton skeleton = EntityType.WITHER_SKELETON.create(level(), net.minecraft.world.entity.EntitySpawnReason.CONVERSION);
|
|
+ if (skeleton == null) {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+
|
|
+ skeleton.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
|
|
+ skeleton.setHealth(this.getHealth());
|
|
+ skeleton.setAggressive(this.isAggressive());
|
|
+ skeleton.copyPosition(this);
|
|
+ skeleton.setYBodyRot(this.yBodyRot);
|
|
+ skeleton.setYHeadRot(this.getYHeadRot());
|
|
+ skeleton.yRotO = this.yRotO;
|
|
+ skeleton.xRotO = this.xRotO;
|
|
+
|
|
+ if (this.hasCustomName()) {
|
|
+ skeleton.setCustomName(this.getCustomName());
|
|
+ }
|
|
+
|
|
+ if (CraftEventFactory.callEntityTransformEvent(this, skeleton, org.bukkit.event.entity.EntityTransformEvent.TransformReason.INFECTION).isCancelled()) {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+
|
|
+ this.level().addFreshEntity(skeleton);
|
|
+ this.remove(RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ stack.shrink(1);
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < 15; ++i) {
|
|
+ ((ServerLevel) level()).sendParticles(((ServerLevel) level()).players(), null, ParticleTypes.HAPPY_VILLAGER,
|
|
+ getX() + random.nextFloat(), getY() + (random.nextFloat() * 2), getZ() + random.nextFloat(), 1,
|
|
+ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0, true);
|
|
+ }
|
|
+ return InteractionResult.SUCCESS;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java
|
|
index 72346a7e5269c91e3143933ac37e65ad9639b791..dad4ef9c672eb4247142de5d045678795951164c 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Slime.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java
|
|
@@ -65,6 +65,7 @@ public class Slime extends Mob implements Enemy {
|
|
public float squish;
|
|
public float oSquish;
|
|
private boolean wasOnGround;
|
|
+ protected boolean actualJump; // Purpur
|
|
|
|
public Slime(EntityType<? extends Slime> type, Level world) {
|
|
super(type, world);
|
|
@@ -72,12 +73,89 @@ public class Slime extends Mob implements Enemy {
|
|
this.moveControl = new Slime.SlimeMoveControl(this);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.slimeRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.slimeTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.slimeAlwaysDropExp;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.slimeRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.slimeControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public float getJumpPower() {
|
|
+ float height = super.getJumpPower();
|
|
+ return getRider() != null && this.isControllable() && actualJump ? height * 1.5F : height;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean onSpacebar() {
|
|
+ if (onGround && getRider() != null && this.isControllable()) {
|
|
+ actualJump = true;
|
|
+ if (getRider().getForwardMot() == 0 || getRider().getStrafeMot() == 0) {
|
|
+ jumpFromGround(); // jump() here if not moving
|
|
+ }
|
|
+ }
|
|
+ return true; // do not jump() in wasd controller, let vanilla controller handle
|
|
+ }
|
|
+
|
|
+ protected String getMaxHealthEquation() {
|
|
+ return level().purpurConfig.slimeMaxHealth;
|
|
+ }
|
|
+
|
|
+ protected String getAttackDamageEquation() {
|
|
+ return level().purpurConfig.slimeAttackDamage;
|
|
+ }
|
|
+
|
|
+ protected java.util.Map<Integer, Double> getMaxHealthCache() {
|
|
+ return level().purpurConfig.slimeMaxHealthCache;
|
|
+ }
|
|
+
|
|
+ protected java.util.Map<Integer, Double> getAttackDamageCache() {
|
|
+ return level().purpurConfig.slimeAttackDamageCache;
|
|
+ }
|
|
+
|
|
+ protected double getFromCache(java.util.function.Supplier<String> equation, java.util.function.Supplier<java.util.Map<Integer, Double>> cache, java.util.function.Supplier<Double> defaultValue) {
|
|
+ int size = getSize();
|
|
+ Double value = cache.get().get(size);
|
|
+ if (value == null) {
|
|
+ try {
|
|
+ value = ((Number) scriptEngine.eval("let size = " + size + "; " + equation.get())).doubleValue();
|
|
+ } catch (javax.script.ScriptException e) {
|
|
+ e.printStackTrace();
|
|
+ value = defaultValue.get();
|
|
+ }
|
|
+ cache.get().put(size, value);
|
|
+ }
|
|
+ return value;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new Slime.SlimeFloatGoal(this));
|
|
this.goalSelector.addGoal(2, new Slime.SlimeAttackGoal(this));
|
|
this.goalSelector.addGoal(3, new Slime.SlimeRandomDirectionGoal(this));
|
|
this.goalSelector.addGoal(5, new Slime.SlimeKeepOnJumpingGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entityliving, worldserver) -> {
|
|
return Math.abs(entityliving.getY() - this.getY()) <= 4.0D;
|
|
}));
|
|
@@ -102,9 +180,9 @@ public class Slime extends Mob implements Enemy {
|
|
this.entityData.set(Slime.ID_SIZE, j);
|
|
this.reapplyPosition();
|
|
this.refreshDimensions();
|
|
- this.getAttribute(Attributes.MAX_HEALTH).setBaseValue((double) (j * j));
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(getFromCache(this::getMaxHealthEquation, this::getMaxHealthCache, () -> (double) size * size)); // Purpur
|
|
this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue((double) (0.2F + 0.1F * (float) j));
|
|
- this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue((double) j);
|
|
+ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(getFromCache(this::getAttackDamageEquation, this::getAttackDamageCache, () -> (double) j)); // Purpur
|
|
if (heal) {
|
|
this.setHealth(this.getMaxHealth());
|
|
}
|
|
@@ -386,6 +464,7 @@ public class Slime extends Mob implements Enemy {
|
|
|
|
this.setDeltaMovement(vec3d.x, (double) this.getJumpPower(), vec3d.z);
|
|
this.hasImpulse = true;
|
|
+ this.actualJump = false; // Purpur
|
|
}
|
|
|
|
@Nullable
|
|
@@ -419,7 +498,7 @@ public class Slime extends Mob implements Enemy {
|
|
return super.getDefaultDimensions(pose).scale((float) this.getSize());
|
|
}
|
|
|
|
- private static class SlimeMoveControl extends MoveControl {
|
|
+ private static class SlimeMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur
|
|
|
|
private float yRot;
|
|
private int jumpDelay;
|
|
@@ -438,21 +517,33 @@ public class Slime extends Mob implements Enemy {
|
|
}
|
|
|
|
public void setWantedMovement(double speed) {
|
|
- this.speedModifier = speed;
|
|
+ this.setSpeedModifier(speed); // Purpur
|
|
this.operation = MoveControl.Operation.MOVE_TO;
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
+ // Purpur start
|
|
+ if (slime.getRider() != null && slime.isControllable()) {
|
|
+ purpurTick(slime.getRider());
|
|
+ if (slime.getForwardMot() != 0 || slime.getStrafeMot() != 0) {
|
|
+ if (jumpDelay > 10) {
|
|
+ jumpDelay = 6;
|
|
+ }
|
|
+ } else {
|
|
+ jumpDelay = 20;
|
|
+ }
|
|
+ } else {
|
|
+ // Purpur end
|
|
this.mob.setYRot(this.rotlerp(this.mob.getYRot(), this.yRot, 90.0F));
|
|
this.mob.yHeadRot = this.mob.getYRot();
|
|
this.mob.yBodyRot = this.mob.getYRot();
|
|
- if (this.operation != MoveControl.Operation.MOVE_TO) {
|
|
+ } if ((slime.getRider() == null || !slime.isControllable()) && this.operation != MoveControl.Operation.MOVE_TO) { // Purpur
|
|
this.mob.setZza(0.0F);
|
|
} else {
|
|
this.operation = MoveControl.Operation.WAIT;
|
|
if (this.mob.onGround()) {
|
|
- this.mob.setSpeed((float) (this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED)));
|
|
+ this.mob.setSpeed((float) (this.getSpeedModifier() * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED) * (slime.getRider() != null && slime.isControllable() && (slime.getRider().getForwardMot() != 0 || slime.getRider().getStrafeMot() != 0) ? 2.0D : 1.0D))); // Purpur
|
|
if (this.jumpDelay-- <= 0) {
|
|
this.jumpDelay = this.slime.getJumpDelay();
|
|
if (this.isAggressive) {
|
|
@@ -469,7 +560,7 @@ public class Slime extends Mob implements Enemy {
|
|
this.mob.setSpeed(0.0F);
|
|
}
|
|
} else {
|
|
- this.mob.setSpeed((float) (this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED)));
|
|
+ this.mob.setSpeed((float) (this.getSpeedModifier() * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED) * (slime.getRider() != null && slime.isControllable() && (slime.getRider().getForwardMot() != 0 || slime.getRider().getStrafeMot() != 0) ? 2.0D : 1.0D))); // Purpur
|
|
}
|
|
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Spider.java b/src/main/java/net/minecraft/world/entity/monster/Spider.java
|
|
index 91e521414c3ea5722aac7506b7589fbb399e9636..1669acbcf97bee0fa6b0ee91cf53217c53cf55d8 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Spider.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java
|
|
@@ -51,9 +51,43 @@ public class Spider extends Monster {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.spiderRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.spiderRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.spiderControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.spiderMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.spiderScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.spiderTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.spiderAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(1, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Armadillo.class, 6.0F, 1.0D, 1.2D, (entityliving) -> {
|
|
return !((Armadillo) entityliving).isScared();
|
|
}));
|
|
@@ -62,6 +96,7 @@ public class Spider extends Monster {
|
|
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8D));
|
|
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F));
|
|
this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0]));
|
|
this.targetSelector.addGoal(2, new Spider.SpiderTargetGoal<>(this, Player.class));
|
|
this.targetSelector.addGoal(3, new Spider.SpiderTargetGoal<>(this, IronGolem.class));
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Stray.java b/src/main/java/net/minecraft/world/entity/monster/Stray.java
|
|
index baaf17107584b253d7e268749849bf5b0d0c88ab..bb6984d82e6c0a83f456e725b20e0f21e0cac602 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Stray.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Stray.java
|
|
@@ -22,6 +22,38 @@ public class Stray extends AbstractSkeleton {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.strayRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.strayRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.strayControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.strayMaxHealth);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.strayTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.strayAlwaysDropExp;
|
|
+ }
|
|
+
|
|
public static boolean checkStraySpawnRules(
|
|
EntityType<Stray> type, ServerLevelAccessor world, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
|
|
) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Strider.java b/src/main/java/net/minecraft/world/entity/monster/Strider.java
|
|
index 711b7eb8e9fdedbc87965828e573fe8d5c357d53..c3b5b34a54de945071692293645b8a8865aed961 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Strider.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Strider.java
|
|
@@ -91,12 +91,45 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
|
|
super(type, world);
|
|
this.steering = new ItemBasedSteering(this.entityData, Strider.DATA_BOOST_TIME, Strider.DATA_SADDLE_ID);
|
|
this.blocksBuilding = true;
|
|
- this.setPathfindingMalus(PathType.WATER, -1.0F);
|
|
+ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur
|
|
this.setPathfindingMalus(PathType.LAVA, 0.0F);
|
|
this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F);
|
|
this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.striderRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.striderRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.striderControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.striderMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.striderScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.striderBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.striderAlwaysDropExp;
|
|
+ }
|
|
+
|
|
public static boolean checkStriderSpawnRules(EntityType<Strider> type, LevelAccessor world, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random) {
|
|
BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable();
|
|
|
|
@@ -158,6 +191,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(1, new PanicGoal(this, 1.65D));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D));
|
|
this.temptGoal = new TemptGoal(this, 1.4D, (itemstack) -> {
|
|
return itemstack.is(ItemTags.STRIDER_TEMPT_ITEMS);
|
|
@@ -412,7 +446,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
|
|
|
|
@Override
|
|
public boolean isSensitiveToWater() {
|
|
- return true;
|
|
+ return this.level().purpurConfig.striderTakeDamageFromWater; // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -454,6 +488,19 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
|
|
public InteractionResult mobInteract(Player player, InteractionHand hand) {
|
|
boolean flag = this.isFood(player.getItemInHand(hand));
|
|
|
|
+ // Purpur start
|
|
+ if (level().purpurConfig.striderGiveSaddleBack && player.isSecondaryUseActive() && !flag && isSaddled() && !isVehicle()) {
|
|
+ this.steering.setSaddle(false);
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ ItemStack saddle = new ItemStack(Items.SADDLE);
|
|
+ if (!player.getInventory().add(saddle)) {
|
|
+ player.drop(saddle, false);
|
|
+ }
|
|
+ }
|
|
+ return InteractionResult.SUCCESS;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
if (!flag && this.isSaddled() && !this.isVehicle() && !player.isSecondaryUseActive()) {
|
|
if (!this.level().isClientSide) {
|
|
player.startRiding(this);
|
|
@@ -466,7 +513,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
|
|
if (!enuminteractionresult.consumesAction()) {
|
|
ItemStack itemstack = player.getItemInHand(hand);
|
|
|
|
- return (InteractionResult) (itemstack.is(Items.SADDLE) ? itemstack.interactLivingEntity(player, this, hand) : InteractionResult.PASS);
|
|
+ return (InteractionResult) (itemstack.is(Items.SADDLE) ? itemstack.interactLivingEntity(player, this, hand) : tryRide(player, hand)); // Purpur
|
|
} else {
|
|
if (flag && !this.isSilent()) {
|
|
this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.STRIDER_EAT, this.getSoundSource(), 1.0F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java
|
|
index 183a33b7d666d652b455baa7e8339e9c4a870a58..fe19c0cf6a2c81b547158179518bf26be388cc7a 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Vex.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java
|
|
@@ -59,6 +59,66 @@ public class Vex extends Monster implements TraceableEntity {
|
|
this.xpReward = 3;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.vexRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.vexRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.vexControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double getMaxY() {
|
|
+ return level().purpurConfig.vexMaxY;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void travel(Vec3 vec3) {
|
|
+ super.travel(vec3);
|
|
+ if (getRider() != null && this.isControllable()) {
|
|
+ float speed;
|
|
+ if (onGround) {
|
|
+ speed = (float) getAttributeValue(Attributes.MOVEMENT_SPEED) * 0.1F;
|
|
+ } else {
|
|
+ speed = (float) getAttributeValue(Attributes.FLYING_SPEED);
|
|
+ }
|
|
+ setSpeed(speed);
|
|
+ Vec3 mot = getDeltaMovement();
|
|
+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed));
|
|
+ setDeltaMovement(mot.scale(0.9D));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) {
|
|
+ return false; // no fall damage please
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.vexMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.vexScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.vexTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.vexAlwaysDropExp;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public boolean isFlapping() {
|
|
return this.tickCount % Vex.TICKS_PER_FLAP == 0;
|
|
@@ -71,7 +131,7 @@ public class Vex extends Monster implements TraceableEntity {
|
|
|
|
@Override
|
|
public void tick() {
|
|
- this.noPhysics = true;
|
|
+ this.noPhysics = getRider() == null || !this.isControllable(); // Purpur
|
|
super.tick();
|
|
this.noPhysics = false;
|
|
this.setNoGravity(true);
|
|
@@ -86,17 +146,19 @@ public class Vex extends Monster implements TraceableEntity {
|
|
protected void registerGoals() {
|
|
super.registerGoals();
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(4, new Vex.VexChargeAttackGoal());
|
|
this.goalSelector.addGoal(8, new Vex.VexRandomMoveGoal());
|
|
this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F));
|
|
this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers());
|
|
this.targetSelector.addGoal(2, new Vex.VexCopyOwnerTargetGoal(this));
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
|
}
|
|
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
- return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 14.0D).add(Attributes.ATTACK_DAMAGE, 4.0D);
|
|
+ return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 14.0D).add(Attributes.ATTACK_DAMAGE, 4.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur;
|
|
}
|
|
|
|
@Override
|
|
@@ -228,14 +290,14 @@ public class Vex extends Monster implements TraceableEntity {
|
|
this.setDropChance(EquipmentSlot.MAINHAND, 0.0F);
|
|
}
|
|
|
|
- private class VexMoveControl extends MoveControl {
|
|
+ private class VexMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur
|
|
|
|
public VexMoveControl(final Vex entityvex) {
|
|
super(entityvex);
|
|
}
|
|
|
|
@Override
|
|
- public void tick() {
|
|
+ public void vanillaTick() { // Purpur
|
|
if (this.operation == MoveControl.Operation.MOVE_TO) {
|
|
Vec3 vec3d = new Vec3(this.wantedX - Vex.this.getX(), this.wantedY - Vex.this.getY(), this.wantedZ - Vex.this.getZ());
|
|
double d0 = vec3d.length();
|
|
@@ -244,7 +306,7 @@ public class Vex extends Monster implements TraceableEntity {
|
|
this.operation = MoveControl.Operation.WAIT;
|
|
Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().scale(0.5D));
|
|
} else {
|
|
- Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().add(vec3d.scale(this.speedModifier * 0.05D / d0)));
|
|
+ Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().add(vec3d.scale(this.getSpeedModifier() * 0.05D / d0))); // Purpur
|
|
if (Vex.this.getTarget() == null) {
|
|
Vec3 vec3d1 = Vex.this.getDeltaMovement();
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java
|
|
index 96b105697c91314148fd1b783501389214b1a3f0..a2c81d2a1077b2977f1595fd592044baf3e81bab 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java
|
|
@@ -55,15 +55,50 @@ public class Vindicator extends AbstractIllager {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.vindicatorRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.vindicatorRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.vindicatorControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.vindicatorMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.vindicatorScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.vindicatorTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.vindicatorAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
super.registerGoals();
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2));
|
|
this.goalSelector.addGoal(2, new Vindicator.VindicatorBreakDoorGoal(this));
|
|
this.goalSelector.addGoal(3, new AbstractIllager.RaiderOpenDoorGoal(this));
|
|
this.goalSelector.addGoal(4, new Raider.HoldGroundAttackGoal(this, 10.0F));
|
|
this.goalSelector.addGoal(5, new MeleeAttackGoal(this, 1.0, false));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers());
|
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true));
|
|
@@ -132,6 +167,11 @@ public class Vindicator extends AbstractIllager {
|
|
RandomSource randomSource = world.getRandom();
|
|
this.populateDefaultEquipmentSlots(randomSource, difficulty);
|
|
this.populateDefaultEquipmentEnchantments(world, randomSource, difficulty);
|
|
+ // Purpur start
|
|
+ if (level().purpurConfig.vindicatorJohnnySpawnChance > 0D && random.nextDouble() <= level().purpurConfig.vindicatorJohnnySpawnChance) {
|
|
+ setCustomName(Component.translatable("Johnny"));
|
|
+ }
|
|
+ // Purpur end
|
|
return spawnGroupData;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Witch.java b/src/main/java/net/minecraft/world/entity/monster/Witch.java
|
|
index a03fa8a3e648532a7ffaaf523ca87c13e8af4c0a..313228811d1eff478887511f99b49706efc49774 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Witch.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java
|
|
@@ -57,6 +57,39 @@ public class Witch extends Raider implements RangedAttackMob {
|
|
super(type, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.witchRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witchRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.witchControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.witchMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.witchScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.witchTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.witchAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
super.registerGoals();
|
|
@@ -65,10 +98,12 @@ public class Witch extends Raider implements RangedAttackMob {
|
|
});
|
|
this.attackPlayersGoal = new NearestAttackableWitchTargetGoal<>(this, Player.class, 10, true, false, (TargetingConditions.Selector) null);
|
|
this.goalSelector.addGoal(1, new FloatGoal(this));
|
|
+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.goalSelector.addGoal(2, new RangedAttackGoal(this, 1.0D, 60, 10.0F));
|
|
this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D));
|
|
this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 8.0F));
|
|
this.goalSelector.addGoal(3, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[]{Raider.class}));
|
|
this.targetSelector.addGoal(2, this.healRaidersGoal);
|
|
this.targetSelector.addGoal(3, this.attackPlayersGoal);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java
|
|
index 37d3acda84a984bf4f1c44b3d27e2102839d3e8e..23fc36780a3e15260f8cb1001c8d676464a9df3a 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java
|
|
@@ -33,6 +33,39 @@ public class WitherSkeleton extends AbstractSkeleton {
|
|
this.setPathfindingMalus(PathType.LAVA, 8.0F);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.witherSkeletonRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witherSkeletonRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.witherSkeletonControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.witherSkeletonMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.witherSkeletonScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.witherSkeletonTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.witherSkeletonAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true));
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java
|
|
index 35b0c5c322864e2f5ae5a412296072f268adcd05..f30ad422f19757664228f2064465fbcb22bb54f6 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java
|
|
@@ -85,6 +85,39 @@ public class Zoglin extends Monster implements HoglinBase {
|
|
this.xpReward = 5;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.zoglinRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zoglinRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.zoglinControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zoglinMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.zoglinScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.zoglinTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.zoglinAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected Brain.Provider<Zoglin> brainProvider() {
|
|
return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
|
|
@@ -248,10 +281,11 @@ public class Zoglin extends Monster implements HoglinBase {
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller profilerFiller = Profiler.get();
|
|
- profilerFiller.push("zoglinBrain");
|
|
+ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur
|
|
+ //profilerFiller.push("zoglinBrain"); // Purpur
|
|
+ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider
|
|
this.getBrain().tick(world, this);
|
|
- profilerFiller.pop();
|
|
+ //profilerFiller.pop(); // Purpur
|
|
this.updateActivity();
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
|
index a12461907278cfbfa3b1c0aa74b9f07a31768b8a..85b03e0bf7436cb846df13c575ad78ac6a17a151 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
|
@@ -99,22 +99,70 @@ public class Zombie extends Monster {
|
|
private int inWaterTime;
|
|
public int conversionTime;
|
|
// private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field // Paper - remove anti tick skipping measures / wall time
|
|
- private boolean shouldBurnInDay = true; // Paper - Add more Zombie API
|
|
+ //private boolean shouldBurnInDay = true; // Paper - Add more Zombie API // Purpur - implemented in LivingEntity - API for any mob to burn daylight
|
|
|
|
public Zombie(EntityType<? extends Zombie> type, Level world) {
|
|
super(type, world);
|
|
this.breakDoorGoal = new BreakDoorGoal(this, com.google.common.base.Predicates.in(world.paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(type, world.paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.ZOMBIE)))); // Paper - Configurable door breaking difficulty
|
|
+ this.setShouldBurnInDay(true); // Purpur - API for any mob to burn daylight
|
|
}
|
|
|
|
public Zombie(Level world) {
|
|
this(EntityType.ZOMBIE, world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.zombieRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.zombieControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombieMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.zombieScale);
|
|
+ }
|
|
+
|
|
+ public boolean jockeyOnlyBaby() {
|
|
+ return level().purpurConfig.zombieJockeyOnlyBaby;
|
|
+ }
|
|
+
|
|
+ public double jockeyChance() {
|
|
+ return level().purpurConfig.zombieJockeyChance;
|
|
+ }
|
|
+
|
|
+ public boolean jockeyTryExistingChickens() {
|
|
+ return level().purpurConfig.zombieJockeyTryExistingChickens;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.zombieTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.zombieAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
if (this.level().paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); // Paper - Add zombie targets turtle egg config
|
|
this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F));
|
|
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
this.addBehaviourGoals();
|
|
}
|
|
|
|
@@ -124,7 +172,19 @@ public class Zombie extends Monster {
|
|
this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D));
|
|
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers(ZombifiedPiglin.class));
|
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
|
- if ( this.level().spigotConfig.zombieAggressiveTowardsVillager ) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Spigot
|
|
+ // Purpur start
|
|
+ if ( this.level().spigotConfig.zombieAggressiveTowardsVillager ) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false) { // Spigot
|
|
+ @Override
|
|
+ public boolean canUse() {
|
|
+ return (level().purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !level().getServer().server.isLagging()) && super.canUse();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canContinueToUse() {
|
|
+ return (level().purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !level().getServer().server.isLagging()) && super.canContinueToUse();
|
|
+ }
|
|
+ });
|
|
+ // Purpur end
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
|
|
this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR));
|
|
}
|
|
@@ -239,32 +299,7 @@ public class Zombie extends Monster {
|
|
|
|
@Override
|
|
public void aiStep() {
|
|
- if (this.isAlive()) {
|
|
- boolean flag = this.isSunSensitive() && this.isSunBurnTick();
|
|
-
|
|
- if (flag) {
|
|
- ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD);
|
|
-
|
|
- if (!itemstack.isEmpty()) {
|
|
- if (itemstack.isDamageableItem()) {
|
|
- Item item = itemstack.getItem();
|
|
-
|
|
- itemstack.setDamageValue(itemstack.getDamageValue() + this.random.nextInt(2));
|
|
- if (itemstack.getDamageValue() >= itemstack.getMaxDamage()) {
|
|
- this.onEquippedItemBroken(item, EquipmentSlot.HEAD);
|
|
- this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY);
|
|
- }
|
|
- }
|
|
-
|
|
- flag = false;
|
|
- }
|
|
-
|
|
- if (flag) {
|
|
- this.igniteForSeconds(8.0F);
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
+ // Purpur - implemented in LivingEntity - API for any mob to burn daylight
|
|
super.aiStep();
|
|
}
|
|
|
|
@@ -324,6 +359,7 @@ public class Zombie extends Monster {
|
|
// CraftBukkit end
|
|
}
|
|
|
|
+ public boolean shouldBurnInDay() { return this.isSunSensitive(); } // Purpur - for ABI compatibility - API for any mob to burn daylight
|
|
public boolean isSunSensitive() {
|
|
return this.shouldBurnInDay; // Paper - Add more Zombie API
|
|
}
|
|
@@ -462,7 +498,7 @@ public class Zombie extends Monster {
|
|
nbt.putBoolean("CanBreakDoors", this.canBreakDoors());
|
|
nbt.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1);
|
|
nbt.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1);
|
|
- nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API
|
|
+ //nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API // Purpur - implemented in LivingEntity - API for any mob to burn daylight
|
|
}
|
|
|
|
@Override
|
|
@@ -475,7 +511,7 @@ public class Zombie extends Monster {
|
|
this.startUnderWaterConversion(nbt.getInt("DrownedConversionTime"));
|
|
}
|
|
// Paper start - Add more Zombie API
|
|
- if (nbt.contains("Paper.ShouldBurnInDay")) {
|
|
+ if (false && nbt.contains("Paper.ShouldBurnInDay")) { // Purpur - implemented in LivingEntity - API for any mob to burn daylight
|
|
this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay");
|
|
}
|
|
// Paper end - Add more Zombie API
|
|
@@ -528,19 +564,20 @@ public class Zombie extends Monster {
|
|
}
|
|
|
|
if (object instanceof Zombie.ZombieGroupData entityzombie_groupdatazombie) {
|
|
- if (entityzombie_groupdatazombie.isBaby) {
|
|
- this.setBaby(true);
|
|
+ // Purpur start
|
|
+ if (!jockeyOnlyBaby() || entityzombie_groupdatazombie.isBaby) {
|
|
+ this.setBaby(entityzombie_groupdatazombie.isBaby);
|
|
if (entityzombie_groupdatazombie.canSpawnJockey) {
|
|
- if ((double) randomsource.nextFloat() < 0.05D) {
|
|
- List<Chicken> list = world.getEntitiesOfClass(Chicken.class, this.getBoundingBox().inflate(5.0D, 3.0D, 5.0D), EntitySelector.ENTITY_NOT_BEING_RIDDEN);
|
|
+ if ((double) randomsource.nextFloat() < jockeyChance()) {
|
|
+ List<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) randomsource.nextFloat() < 0.05D) {
|
|
+ } else { // Purpur
|
|
Chicken entitychicken1 = (Chicken) EntityType.CHICKEN.create(this.level(), EntitySpawnReason.JOCKEY);
|
|
|
|
if (entitychicken1 != null) {
|
|
@@ -550,6 +587,7 @@ public class Zombie extends Monster {
|
|
this.startRiding(entitychicken1);
|
|
world.addFreshEntity(entitychicken1, CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit
|
|
}
|
|
+ } // Purpur
|
|
}
|
|
}
|
|
}
|
|
@@ -562,11 +600,7 @@ public class Zombie extends Monster {
|
|
}
|
|
|
|
if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
|
|
- LocalDate localdate = LocalDate.now();
|
|
- int i = localdate.get(ChronoField.DAY_OF_MONTH);
|
|
- int j = localdate.get(ChronoField.MONTH_OF_YEAR);
|
|
-
|
|
- if (j == 10 && i == 31 && randomsource.nextFloat() < 0.25F) {
|
|
+ if (net.minecraft.world.entity.ambient.Bat.isHalloweenSeason(world.getMinecraftWorld()) && this.random.nextFloat() < this.level().purpurConfig.chanceHeadHalloweenOnEntity) { // Purpur
|
|
this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
|
|
this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F;
|
|
}
|
|
@@ -608,7 +642,7 @@ public class Zombie extends Monster {
|
|
}
|
|
|
|
protected void randomizeReinforcementsChance() {
|
|
- this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * 0.10000000149011612D);
|
|
+ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombieSpawnReinforcements); // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java
|
|
index 18c19e4b675000aacb74344909fc104964231008..6f6b32bf7f68d05e4173c31f2e631a409b858a05 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java
|
|
@@ -85,6 +85,58 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
|
|
});
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.zombieVillagerRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieVillagerRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.zombieVillagerControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombieVillagerMaxHealth);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void randomizeReinforcementsChance() {
|
|
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombieVillagerSpawnReinforcements);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.zombieVillagerTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean jockeyOnlyBaby() {
|
|
+ return level().purpurConfig.zombieVillagerJockeyOnlyBaby;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double jockeyChance() {
|
|
+ return level().purpurConfig.zombieVillagerJockeyChance;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean jockeyTryExistingChickens() {
|
|
+ return level().purpurConfig.zombieVillagerJockeyTryExistingChickens;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.zombieVillagerAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
|
super.defineSynchedData(builder);
|
|
@@ -177,10 +229,10 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
|
|
ItemStack itemstack = player.getItemInHand(hand);
|
|
|
|
if (itemstack.is(Items.GOLDEN_APPLE)) {
|
|
- if (this.hasEffect(MobEffects.WEAKNESS)) {
|
|
+ if (this.hasEffect(MobEffects.WEAKNESS) && level().purpurConfig.zombieVillagerCureEnabled) { // Purpur
|
|
itemstack.consume(1, player);
|
|
if (!this.level().isClientSide) {
|
|
- this.startConverting(player.getUUID(), this.random.nextInt(2401) + 3600);
|
|
+ this.startConverting(player.getUUID(), this.random.nextInt(level().purpurConfig.zombieVillagerCuringTimeMax - level().purpurConfig.zombieVillagerCuringTimeMin + 1) + level().purpurConfig.zombieVillagerCuringTimeMin); // Purpur
|
|
}
|
|
|
|
return InteractionResult.SUCCESS_SERVER;
|
|
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 03e3cbe73119ca76417d4dd192e1560bdfc373ec..8c3271dcc8c9aa58e2e007eba282c11e42b4e0c9 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java
|
|
@@ -63,6 +63,54 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
|
|
this.setPathfindingMalus(PathType.LAVA, 8.0F);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.zombifiedPiglinRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombifiedPiglinRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.zombifiedPiglinControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombifiedPiglinMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.zombifiedPiglinScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.zombifiedPiglinTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean jockeyOnlyBaby() {
|
|
+ return level().purpurConfig.zombifiedPiglinJockeyOnlyBaby;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double jockeyChance() {
|
|
+ return level().purpurConfig.zombifiedPiglinJockeyChance;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean jockeyTryExistingChickens() {
|
|
+ return level().purpurConfig.zombifiedPiglinJockeyTryExistingChickens;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.zombifiedPiglinAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
public void setPersistentAngerTarget(@Nullable UUID angryAt) {
|
|
this.persistentAngerTarget = angryAt;
|
|
@@ -110,7 +158,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
|
|
this.maybeAlertOthers();
|
|
}
|
|
|
|
- if (this.isAngry()) {
|
|
+ if (this.isAngry() && this.level().purpurConfig.zombifiedPiglinCountAsPlayerKillWhenAngry) { // Purpur
|
|
this.lastHurtByPlayerTime = this.tickCount;
|
|
}
|
|
|
|
@@ -165,7 +213,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
|
|
this.ticksUntilNextAlert = ZombifiedPiglin.ALERT_INTERVAL.sample(this.random);
|
|
}
|
|
|
|
- if (entityliving instanceof Player) {
|
|
+ if (entityliving instanceof Player && this.level().purpurConfig.zombifiedPiglinCountAsPlayerKillWhenAngry) { // Purpur
|
|
this.setLastHurtByPlayer((Player) entityliving);
|
|
}
|
|
|
|
@@ -245,7 +293,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
|
|
|
|
@Override
|
|
protected void randomizeReinforcementsChance() {
|
|
- this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(0.0D);
|
|
+ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombifiedPiglinSpawnReinforcements); // Purpur
|
|
}
|
|
|
|
@Nullable
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/breeze/Breeze.java b/src/main/java/net/minecraft/world/entity/monster/breeze/Breeze.java
|
|
index a16fd9c4679e874ad2d499f3c00c2ddfd780a7a5..0bc771e20a9bab139cd3fc03ff40baabf787b2f7 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/breeze/Breeze.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/breeze/Breeze.java
|
|
@@ -235,12 +235,12 @@ public class Breeze extends Monster {
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller profilerFiller = Profiler.get();
|
|
- profilerFiller.push("breezeBrain");
|
|
+ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur
|
|
+ //profilerFiller.push("breezeBrain"); // Purpur
|
|
this.getBrain().tick(world, this);
|
|
- profilerFiller.popPush("breezeActivityUpdate");
|
|
+ //profilerFiller.popPush("breezeActivityUpdate"); // Purpur
|
|
BreezeAi.updateActivity(this);
|
|
- profilerFiller.pop();
|
|
+ //profilerFiller.pop(); // Purpur
|
|
super.customServerAiStep(world);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java
|
|
index 6ea90e54759dbeab025e0a1896ee834ea9986427..7afde99f81ec222ecbffbdcdad3aa6404e8221e0 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java
|
|
@@ -92,11 +92,49 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
|
|
this.xpReward = 5;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.hoglinRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.hoglinRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.hoglinControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.hoglinMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.hoglinScale);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@VisibleForTesting
|
|
public void setTimeInOverworld(int timeInOverworld) {
|
|
this.timeInOverworld = timeInOverworld;
|
|
}
|
|
|
|
+ @Override
|
|
+ public int getPurpurBreedTime() {
|
|
+ return this.level().purpurConfig.hoglinBreedingTicks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.hoglinTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.hoglinAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
public boolean canBeLeashed() {
|
|
return true;
|
|
@@ -158,10 +196,11 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller profilerFiller = Profiler.get();
|
|
- profilerFiller.push("hoglinBrain");
|
|
+ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur
|
|
+ //profilerFiller.push("hoglinBrain"); // Purpur
|
|
+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish
|
|
this.getBrain().tick(world, this);
|
|
- profilerFiller.pop();
|
|
+ //profilerFiller.pop(); // Purpur
|
|
HoglinAi.updateActivity(this);
|
|
if (this.isConverting()) {
|
|
this.timeInOverworld++;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java
|
|
index e04d2c5e75dc774fe893a552474fdb8045c32693..b53e4a312ea0dbbd16e948e61c3f6b836d46f3b8 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java
|
|
@@ -96,6 +96,39 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
|
|
this.xpReward = 5;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.piglinRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.piglinRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.piglinControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.piglinMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.piglinScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.piglinTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.piglinAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
public void addAdditionalSaveData(CompoundTag nbt) {
|
|
super.addAdditionalSaveData(nbt);
|
|
@@ -306,11 +339,12 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("piglinBrain");
|
|
+ //gameprofilerfiller.push("piglinBrain"); // Purpur
|
|
+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // // Purpur - TODO: Pufferfish
|
|
this.getBrain().tick(world, this);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
PiglinAi.updateActivity(this);
|
|
super.customServerAiStep(world);
|
|
}
|
|
@@ -405,7 +439,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
|
|
|
|
@Override
|
|
public boolean wantsToPickUp(ServerLevel world, ItemStack stack) {
|
|
- return world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && this.canPickUpLoot() && PiglinAi.wantsToPickup(this, stack);
|
|
+ return (world.purpurConfig.piglinBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && this.canPickUpLoot() && PiglinAi.wantsToPickup(this, stack); // Purpur
|
|
}
|
|
|
|
protected boolean canReplaceCurrentItem(ItemStack stack) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java
|
|
index e283b1296c1e831376bfe9491cbf02ed4b3fffe4..27a6de70530c2a1cbe2f77a7fb493038121710ea 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java
|
|
@@ -605,11 +605,18 @@ public class PiglinAi {
|
|
}
|
|
|
|
itemstack = (ItemStack) iterator.next();
|
|
- } while (!itemstack.is(ItemTags.PIGLIN_SAFE_ARMOR));
|
|
+ } while (!itemstack.is(ItemTags.PIGLIN_SAFE_ARMOR) && (!entity.level().purpurConfig.piglinIgnoresArmorWithGoldTrim || !isWearingGoldTrim(itemstack.getItem()))); // Purpur
|
|
|
|
return true;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ private static boolean isWearingGoldTrim(Item itemstack) {
|
|
+ net.minecraft.world.item.equipment.trim.ArmorTrim armorTrim = itemstack.components().get(net.minecraft.core.component.DataComponents.TRIM);
|
|
+ return armorTrim != null && armorTrim.material().is(net.minecraft.world.item.equipment.trim.TrimMaterials.GOLD);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
private static void stopWalking(Piglin piglin) {
|
|
piglin.getBrain().eraseMemory(MemoryModuleType.WALK_TARGET);
|
|
piglin.getNavigation().stop();
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
|
|
index 24eaeb93284fe1a573026b85818a93a34fd9e1ec..719179fb232a4f39a2c1642cc0e9593f4dea4bb8 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
|
|
@@ -65,6 +65,39 @@ public class PiglinBrute extends AbstractPiglin {
|
|
this.xpReward = 20;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.piglinBruteRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.piglinBruteRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.piglinBruteControllable;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.piglinBruteMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.piglinBruteScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.piglinBruteTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.piglinBruteAlwaysDropExp;
|
|
+ }
|
|
+
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
return Monster.createMonsterAttributes()
|
|
.add(Attributes.MAX_HEALTH, 50.0)
|
|
@@ -115,10 +148,11 @@ public class PiglinBrute extends AbstractPiglin {
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
- ProfilerFiller profilerFiller = Profiler.get();
|
|
- profilerFiller.push("piglinBruteBrain");
|
|
+ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur
|
|
+ //profilerFiller.push("piglinBruteBrain"); // Purpur
|
|
+ if (getRider() == null || this.isControllable()) // Purpur - only use brain if no rider
|
|
this.getBrain().tick(world, this);
|
|
- profilerFiller.pop();
|
|
+ //profilerFiller.pop(); // Purpur
|
|
PiglinBruteAi.updateActivity(this);
|
|
PiglinBruteAi.maybePlayActivitySound(this);
|
|
super.customServerAiStep(world);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java
|
|
index 6180019da58b19d2595da508aed3196af922d587..692261880d05daa75fc53dde31d0f2b95dc52746 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java
|
|
@@ -127,8 +127,32 @@ public class Warden extends Monster implements VibrationSystem {
|
|
this.setPathfindingMalus(PathType.LAVA, 8.0F);
|
|
this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F);
|
|
this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F);
|
|
+ this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this, 0.5F); // Purpur
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.wardenRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.wardenRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.wardenControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public Packet<ClientGamePacketListener> getAddEntityPacket(ServerEntity entityTrackerEntry) {
|
|
return new ClientboundAddEntityPacket(this, entityTrackerEntry, this.hasPose(Pose.EMERGING) ? 1 : 0);
|
|
@@ -279,9 +303,9 @@ public class Warden extends Monster implements VibrationSystem {
|
|
protected void customServerAiStep(ServerLevel world) {
|
|
ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
|
|
- gameprofilerfiller.push("wardenBrain");
|
|
+ //gameprofilerfiller.push("wardenBrain"); // Purpur
|
|
this.getBrain().tick(world, this);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
super.customServerAiStep(world);
|
|
if ((this.tickCount + this.getId()) % 120 == 0) {
|
|
Warden.applyDarknessAround(world, this.position(), this, 20);
|
|
@@ -396,17 +420,14 @@ public class Warden extends Monster implements VibrationSystem {
|
|
|
|
@Contract("null->false")
|
|
public boolean canTargetEntity(@Nullable Entity entity) {
|
|
- boolean flag;
|
|
-
|
|
+ if (getRider() != null && isControllable()) return false; // Purpur
|
|
if (entity instanceof LivingEntity entityliving) {
|
|
if (this.level() == entity.level() && EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(entity) && !this.isAlliedTo(entity) && entityliving.getType() != EntityType.ARMOR_STAND && entityliving.getType() != EntityType.WARDEN && !entityliving.isInvulnerable() && !entityliving.isDeadOrDying() && this.level().getWorldBorder().isWithinBounds(entityliving.getBoundingBox())) {
|
|
- flag = true;
|
|
- return flag;
|
|
+ return true; // Purpur - wtf
|
|
}
|
|
}
|
|
|
|
- flag = false;
|
|
- return flag;
|
|
+ return false; // Purpur - wtf
|
|
}
|
|
|
|
public static void applyDarknessAround(ServerLevel world, Vec3 pos, @Nullable Entity entity, int range) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
|
|
index 5f656fc726a1dc5f42657095a2f2b7cf85b92d7c..6c74cf1dea99b3b967b8c3d76f405f823c881fb9 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
|
|
@@ -48,6 +48,7 @@ import org.bukkit.event.entity.VillagerAcquireTradeEvent;
|
|
// CraftBukkit end
|
|
|
|
public abstract class AbstractVillager extends AgeableMob implements InventoryCarrier, Npc, Merchant {
|
|
+ static final net.minecraft.world.item.crafting.Ingredient TEMPT_ITEMS = net.minecraft.world.item.crafting.Ingredient.of(net.minecraft.world.level.block.Blocks.EMERALD_BLOCK.asItem()); // Purpur
|
|
|
|
// CraftBukkit start
|
|
@Override
|
|
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 b0236c7bf9441aa84d3795ffed05dd6099f29636..796dcc0dcf9022b455b8847e045266b8802da0cf 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java
|
|
@@ -27,7 +27,7 @@ public class CatSpawner implements CustomSpawner {
|
|
if (this.nextTick > 0) {
|
|
return 0;
|
|
} else {
|
|
- this.nextTick = 1200;
|
|
+ this.nextTick = world.purpurConfig.catSpawnDelay; // Purpur
|
|
Player player = world.getRandomPlayer();
|
|
if (player == null) {
|
|
return 0;
|
|
@@ -61,8 +61,12 @@ public class CatSpawner implements CustomSpawner {
|
|
|
|
private int spawnInVillage(ServerLevel world, BlockPos pos) {
|
|
int i = 48;
|
|
- if (world.getPoiManager().getCountInRange(entry -> entry.is(PoiTypes.HOME), pos, 48, PoiManager.Occupancy.IS_OCCUPIED) > 4L) {
|
|
- List<Cat> list = world.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(48.0, 8.0, 48.0));
|
|
+ // Purpur start
|
|
+ int range = world.purpurConfig.catSpawnVillageScanRange;
|
|
+ if (range <= 0) return 0;
|
|
+ if (world.getPoiManager().getCountInRange(entry -> entry.is(PoiTypes.HOME), pos, range, PoiManager.Occupancy.IS_OCCUPIED) > 4L) {
|
|
+ List<Cat> list = world.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(range, 8.0, range));
|
|
+ // Purpur end
|
|
if (list.size() < 5) {
|
|
return this.spawnCat(pos, world);
|
|
}
|
|
@@ -73,7 +77,11 @@ public class CatSpawner implements CustomSpawner {
|
|
|
|
private int spawnInHut(ServerLevel world, BlockPos pos) {
|
|
int i = 16;
|
|
- List<Cat> list = world.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(16.0, 8.0, 16.0));
|
|
+ // Purpur start
|
|
+ int range = world.purpurConfig.catSpawnSwampHutScanRange;
|
|
+ if (range <= 0) return 0;
|
|
+ List<Cat> list = world.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(range, 8.0, range));
|
|
+ // Purpur end
|
|
return list.size() < 1 ? this.spawnCat(pos, world) : 0;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
|
index b7a34f1c4d7b5ef3f7a843d152e33c839dcdedd5..b4ffad429ace965f16ebf47119c880b709b27f2e 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,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
|
}, MemoryModuleType.MEETING_POINT, (entityvillager, holder) -> {
|
|
return holder.is(PoiTypes.MEETING);
|
|
});
|
|
+ private boolean isLobotomized = false; public boolean isLobotomized() { return this.isLobotomized; } // Purpur
|
|
+ private int notLobotomizedCount = 0; // Purpur
|
|
|
|
public Villager(EntityType<? extends Villager> entityType, Level world) {
|
|
this(entityType, world, VillagerType.PLAINS);
|
|
@@ -154,6 +156,92 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
|
this.getNavigation().setRequiredPathLength(48.0F);
|
|
this.setCanPickUpLoot(true);
|
|
this.setVillagerData(this.getVillagerData().setType(type).setProfession(VillagerProfession.NONE));
|
|
+ if (level().purpurConfig.villagerFollowEmeraldBlock) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.TemptGoal(this, 1.0D, TEMPT_ITEMS, false));
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.villagerRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.villagerRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.villagerControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void registerGoals() {
|
|
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canBeLeashed() {
|
|
+ return level().purpurConfig.villagerCanBeLeashed;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.villagerMaxHealth);
|
|
+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.villagerScale);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.villagerTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.villagerAlwaysDropExp;
|
|
+ }
|
|
+
|
|
+ private boolean checkLobotomized() {
|
|
+ int interval = this.level().purpurConfig.villagerLobotomizeCheckInterval;
|
|
+ boolean shouldCheckForTradeLocked = this.level().purpurConfig.villagerLobotomizeWaitUntilTradeLocked;
|
|
+ if (this.notLobotomizedCount > 3) {
|
|
+ // check half as often if not lobotomized for the last 3+ consecutive checks
|
|
+ interval *= 2;
|
|
+ }
|
|
+ if (this.level().getGameTime() % interval == 0) {
|
|
+ // offset Y for short blocks like dirt_path/farmland
|
|
+ this.isLobotomized = !(shouldCheckForTradeLocked && this.getVillagerXp() == 0) && !canTravelFrom(BlockPos.containing(this.position().x, this.getBoundingBox().minY + 0.0625D, this.position().z));
|
|
+
|
|
+ if (this.isLobotomized) {
|
|
+ this.notLobotomizedCount = 0;
|
|
+ } else {
|
|
+ this.notLobotomizedCount++;
|
|
+ }
|
|
+ }
|
|
+ return this.isLobotomized;
|
|
+ }
|
|
+
|
|
+ private boolean canTravelFrom(BlockPos pos) {
|
|
+ return canTravelTo(pos.east()) || canTravelTo(pos.west()) || canTravelTo(pos.north()) || canTravelTo(pos.south());
|
|
+ }
|
|
+
|
|
+ private boolean canTravelTo(BlockPos pos) {
|
|
+ net.minecraft.world.level.block.state.BlockState state = this.level().getBlockStateIfLoaded(pos);
|
|
+ if (state == null) {
|
|
+ // chunk not loaded
|
|
+ return false;
|
|
+ }
|
|
+ net.minecraft.world.level.block.Block bottom = state.getBlock();
|
|
+ if (bottom instanceof net.minecraft.world.level.block.FenceBlock ||
|
|
+ bottom instanceof net.minecraft.world.level.block.FenceGateBlock ||
|
|
+ bottom instanceof net.minecraft.world.level.block.WallBlock) {
|
|
+ // bottom block is too tall to get over
|
|
+ return false;
|
|
+ }
|
|
+ net.minecraft.world.level.block.Block top = level().getBlockState(pos.above()).getBlock();
|
|
+ // only if both blocks have no collision
|
|
+ return !bottom.hasCollision && !top.hasCollision;
|
|
}
|
|
|
|
@Override
|
|
@@ -190,7 +278,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
|
brain.addActivity(Activity.PLAY, VillagerGoalPackages.getPlayPackage(0.5F));
|
|
} else {
|
|
brain.setSchedule(Schedule.VILLAGER_DEFAULT);
|
|
- brain.addActivityWithConditions(Activity.WORK, VillagerGoalPackages.getWorkPackage(villagerprofession, 0.5F), ImmutableSet.of(Pair.of(MemoryModuleType.JOB_SITE, MemoryStatus.VALUE_PRESENT)));
|
|
+ brain.addActivityWithConditions(Activity.WORK, VillagerGoalPackages.getWorkPackage(villagerprofession, 0.5F, this.level().purpurConfig.villagerClericsFarmWarts), ImmutableSet.of(Pair.of(MemoryModuleType.JOB_SITE, MemoryStatus.VALUE_PRESENT))); // Purpur
|
|
}
|
|
|
|
brain.addActivity(Activity.CORE, VillagerGoalPackages.getCorePackage(villagerprofession, 0.5F));
|
|
@@ -250,13 +338,21 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
|
// Paper start - EAR 2
|
|
this.customServerAiStep(world, false);
|
|
}
|
|
- protected void customServerAiStep(ServerLevel world, final boolean inactive) {
|
|
+ protected void customServerAiStep(ServerLevel world, boolean inactive) { // Purpur - not final
|
|
// Paper end - EAR 2
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("villagerBrain");
|
|
- if (!inactive) this.getBrain().tick(world, this);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.push("villagerBrain"); // Purpur
|
|
+ // Purpur start
|
|
+ if (this.level().purpurConfig.villagerLobotomizeEnabled) {
|
|
+ // treat as inactive if lobotomized
|
|
+ inactive = inactive || checkLobotomized();
|
|
+ } else {
|
|
+ this.isLobotomized = false;
|
|
+ }
|
|
+ // Purpur end
|
|
+ if (!inactive && (getRider() == null || !this.isControllable())) this.getBrain().tick(world, this); // Purpur
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
if (this.assignProfessionWhenSpawned) {
|
|
this.assignProfessionWhenSpawned = false;
|
|
}
|
|
@@ -312,7 +408,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
|
if (!itemstack.is(Items.VILLAGER_SPAWN_EGG) && this.isAlive() && !this.isTrading() && !this.isSleeping()) {
|
|
if (this.isBaby()) {
|
|
this.setUnhappy();
|
|
- return InteractionResult.SUCCESS;
|
|
+ return tryRide(player, hand, InteractionResult.SUCCESS); // Purpur
|
|
} else {
|
|
if (!this.level().isClientSide) {
|
|
boolean flag = this.getOffers().isEmpty();
|
|
@@ -326,9 +422,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
|
}
|
|
|
|
if (flag) {
|
|
- return InteractionResult.CONSUME;
|
|
+ return tryRide(player, hand, InteractionResult.CONSUME); // Purpur
|
|
}
|
|
|
|
+ if (level().purpurConfig.villagerRidable && itemstack.isEmpty()) return tryRide(player, hand); // Purpur
|
|
+ if (this.level().purpurConfig.villagerAllowTrading) // Purpur
|
|
this.startTrading(player);
|
|
}
|
|
|
|
@@ -493,7 +591,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
|
while (iterator.hasNext()) {
|
|
MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
|
|
|
|
- merchantrecipe.updateDemand();
|
|
+ merchantrecipe.updateDemand(this.level().purpurConfig.villagerMinimumDemand); // Purpur
|
|
}
|
|
|
|
}
|
|
@@ -726,7 +824,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
|
|
|
@Override
|
|
public boolean canBreed() {
|
|
- return this.foodLevel + this.countFoodPointsInInventory() >= 12 && !this.isSleeping() && this.getAge() == 0;
|
|
+ return this.level().purpurConfig.villagerCanBreed && this.foodLevel + this.countFoodPointsInInventory() >= 12 && !this.isSleeping() && this.getAge() == 0; // Purpur
|
|
}
|
|
|
|
private boolean hungry() {
|
|
@@ -905,6 +1003,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
|
|
|
public boolean hasFarmSeeds() {
|
|
return this.getInventory().hasAnyMatching((itemstack) -> {
|
|
+ // Purpur start
|
|
+ if (this.level().purpurConfig.villagerClericsFarmWarts && this.getVillagerData().getProfession() == VillagerProfession.CLERIC) {
|
|
+ return itemstack.is(Items.NETHER_WART);
|
|
+ }
|
|
+ // Purpur end
|
|
return itemstack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS);
|
|
});
|
|
}
|
|
@@ -962,6 +1065,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
|
}
|
|
|
|
public void spawnGolemIfNeeded(ServerLevel world, long time, int requiredCount) {
|
|
+ if (world.purpurConfig.villagerSpawnIronGolemRadius > 0 && world.getEntitiesOfClass(net.minecraft.world.entity.animal.IronGolem.class, getBoundingBox().inflate(world.purpurConfig.villagerSpawnIronGolemRadius)).size() > world.purpurConfig.villagerSpawnIronGolemLimit) return; // Purpur
|
|
if (this.wantsToSpawnGolem(time)) {
|
|
AABB axisalignedbb = this.getBoundingBox().inflate(10.0D, 10.0D, 10.0D);
|
|
List<Villager> list = world.getEntitiesOfClass(Villager.class, axisalignedbb);
|
|
@@ -1026,6 +1130,12 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
|
|
|
@Override
|
|
public void startSleeping(BlockPos pos) {
|
|
+ // Purpur start
|
|
+ if (level().purpurConfig.bedExplodeOnVillagerSleep && this.level().getBlockState(pos).getBlock() instanceof net.minecraft.world.level.block.BedBlock) {
|
|
+ this.level().explode(null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (float) this.level().purpurConfig.bedExplosionPower, this.level().purpurConfig.bedExplosionFire, this.level().purpurConfig.bedExplosionEffect);
|
|
+ return;
|
|
+ }
|
|
+ // Purpur end
|
|
super.startSleeping(pos);
|
|
this.brain.setMemory(MemoryModuleType.LAST_SLEPT, this.level().getGameTime()); // CraftBukkit - decompile error
|
|
this.brain.eraseMemory(MemoryModuleType.WALK_TARGET);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java b/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java
|
|
index 8734ab1bd8299bbf43906d81a349c2a13e0981a7..3ca83269311cbc18c9ef3ce62cff6a2d4dc0a683 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java
|
|
@@ -31,7 +31,7 @@ public record VillagerProfession(
|
|
public static final VillagerProfession ARMORER = register("armorer", PoiTypes.ARMORER, SoundEvents.VILLAGER_WORK_ARMORER);
|
|
public static final VillagerProfession BUTCHER = register("butcher", PoiTypes.BUTCHER, SoundEvents.VILLAGER_WORK_BUTCHER);
|
|
public static final VillagerProfession CARTOGRAPHER = register("cartographer", PoiTypes.CARTOGRAPHER, SoundEvents.VILLAGER_WORK_CARTOGRAPHER);
|
|
- public static final VillagerProfession CLERIC = register("cleric", PoiTypes.CLERIC, SoundEvents.VILLAGER_WORK_CLERIC);
|
|
+ public static final VillagerProfession CLERIC = register("cleric", PoiTypes.CLERIC, ImmutableSet.of(Items.NETHER_WART), ImmutableSet.of(Blocks.SOUL_SAND), SoundEvents.VILLAGER_WORK_CLERIC); // Purpur
|
|
public static final VillagerProfession FARMER = register(
|
|
"farmer",
|
|
PoiTypes.FARMER,
|
|
diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
|
|
index 1e77cce428d9e53142aaa2cf780b7f862d536eca..959e10586cddaae2590d2d84f5fd809dad80889b 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
|
|
@@ -72,6 +72,43 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
|
|
//this.setDespawnDelay(48000); // CraftBukkit - set default from MobSpawnerTrader // Paper - move back to MobSpawnerTrader - Vanilla behavior is that only traders spawned by it have this value set.
|
|
}
|
|
|
|
+ // Purpur - start
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return level().purpurConfig.wanderingTraderRidable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.wanderingTraderRidableInWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isControllable() {
|
|
+ return level().purpurConfig.wanderingTraderControllable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canBeLeashed() {
|
|
+ return level().purpurConfig.wanderingTraderCanBeLeashed;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ @Override
|
|
+ public void initAttributes() {
|
|
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.wanderingTraderMaxHealth);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isSensitiveToWater() {
|
|
+ return this.level().purpurConfig.wanderingTraderTakeDamageFromWater;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean isAlwaysExperienceDropper() {
|
|
+ return this.level().purpurConfig.wanderingTraderAlwaysDropExp;
|
|
+ }
|
|
+
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
|
@@ -79,7 +116,7 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
|
|
return this.canDrinkPotion && this.level().isNight() && !entityvillagertrader.isInvisible(); // Paper - Add more WanderingTrader API
|
|
}));
|
|
this.goalSelector.addGoal(0, new UseItemGoal<>(this, new ItemStack(Items.MILK_BUCKET), SoundEvents.WANDERING_TRADER_REAPPEARED, (entityvillagertrader) -> {
|
|
- return this.canDrinkMilk && this.level().isDay() && entityvillagertrader.isInvisible(); // Paper - Add more WanderingTrader API
|
|
+ return level().purpurConfig.milkClearsBeneficialEffects && this.canDrinkMilk && this.level().isDay() && entityvillagertrader.isInvisible(); // Paper - Add more WanderingTrader API // Purpur
|
|
}));
|
|
this.goalSelector.addGoal(1, new TradeWithPlayerGoal(this));
|
|
this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Zombie.class, 8.0F, 0.5D, 0.5D));
|
|
@@ -92,6 +129,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));
|
|
@@ -120,11 +158,13 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
|
|
|
|
if (!this.level().isClientSide) {
|
|
if (this.getOffers().isEmpty()) {
|
|
- return InteractionResult.CONSUME;
|
|
+ return tryRide(player, hand, InteractionResult.CONSUME); // Purpur
|
|
}
|
|
-
|
|
- this.setTradingPlayer(player);
|
|
- this.openTradingScreen(player, this.getDisplayName(), 1);
|
|
+ if (level().purpurConfig.wanderingTraderRidable && itemstack.isEmpty()) return tryRide(player, hand); // Purpur
|
|
+ if (this.level().purpurConfig.wanderingTraderAllowTrading) { // Purpur
|
|
+ this.setTradingPlayer(player);
|
|
+ this.openTradingScreen(player, this.getDisplayName(), 1);
|
|
+ } // Purpur
|
|
}
|
|
|
|
return InteractionResult.SUCCESS;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java
|
|
index a728dcbf956f108f01c966c7531449a506a14a87..4c1378132201c1e5d1bc01f8c0cbba91629bcffa 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java
|
|
@@ -160,7 +160,17 @@ public class WanderingTraderSpawner implements CustomSpawner {
|
|
int k = pos.getX() + this.random.nextInt(range * 2) - range;
|
|
int l = pos.getZ() + this.random.nextInt(range * 2) - range;
|
|
int i1 = world.getHeight(Heightmap.Types.WORLD_SURFACE, k, l);
|
|
- BlockPos blockposition2 = new BlockPos(k, i1, l);
|
|
+ // Purpur start - allow traders to spawn below nether roof
|
|
+ BlockPos.MutableBlockPos blockposition2 = new BlockPos.MutableBlockPos(k, i1, l);
|
|
+ if (world.dimensionType().hasCeiling()) {
|
|
+ do {
|
|
+ blockposition2.relative(net.minecraft.core.Direction.DOWN);
|
|
+ } while (!world.getBlockState(blockposition2).isAir());
|
|
+ do {
|
|
+ blockposition2.relative(net.minecraft.core.Direction.DOWN);
|
|
+ } while (world.getBlockState(blockposition2).isAir() && blockposition2.getY() > 0);
|
|
+ }
|
|
+ // Purpur end
|
|
|
|
if (spawnplacementtype.isSpawnPositionOk(world, blockposition2, EntityType.WANDERING_TRADER)) {
|
|
blockposition1 = blockposition2;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
|
index 61d412c4f1ebd55661cc3f0260468e3ac0efe0bb..c1d068fa99ec0fd5685bbb627a775e4d1587feab 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
|
@@ -197,17 +197,40 @@ public abstract class Player extends LivingEntity {
|
|
private int currentImpulseContextResetGraceTime;
|
|
public boolean affectsSpawning = true; // Paper - Affects Spawning API
|
|
public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage
|
|
+ public int sixRowEnderchestSlotCount = -1; // Purpur
|
|
+ public int burpDelay = 0; // Purpur
|
|
+ public boolean canPortalInstant = false; // Purpur
|
|
|
|
// CraftBukkit start
|
|
public boolean fauxSleeping;
|
|
public int oldLevel = -1;
|
|
|
|
+ public void setAfk(boolean afk) {
|
|
+ }
|
|
+
|
|
+ public boolean isAfk() {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
@Override
|
|
public CraftHumanEntity getBukkitEntity() {
|
|
return (CraftHumanEntity) super.getBukkitEntity();
|
|
}
|
|
// CraftBukkit end
|
|
|
|
+ // Purpur start
|
|
+ public abstract void resetLastActionTime();
|
|
+
|
|
+ @Override
|
|
+ public boolean processClick(InteractionHand hand) {
|
|
+ Entity vehicle = getRootVehicle();
|
|
+ if (vehicle != null && vehicle.getRider() == this) {
|
|
+ return vehicle.onClick(hand);
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public Player(Level world, BlockPos pos, float yaw, GameProfile gameProfile) {
|
|
super(EntityType.PLAYER, world);
|
|
this.lastItemInMainHand = ItemStack.EMPTY;
|
|
@@ -252,6 +275,12 @@ public abstract class Player extends LivingEntity {
|
|
|
|
@Override
|
|
public void tick() {
|
|
+ // Purpur start
|
|
+ if (this.burpDelay > 0 && --this.burpDelay == 0) {
|
|
+ this.level().playSound(null, getX(), getY(), getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 1.0F, this.level().random.nextFloat() * 0.1F + 0.9F);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
this.noPhysics = this.isSpectator();
|
|
if (this.isSpectator()) {
|
|
this.setOnGround(false);
|
|
@@ -332,6 +361,17 @@ public abstract class Player extends LivingEntity {
|
|
this.turtleHelmetTick();
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ if (this.level().purpurConfig.playerNetheriteFireResistanceDuration > 0 && this.level().getGameTime() % 20 == 0) {
|
|
+ if (this.getItemBySlot(EquipmentSlot.HEAD).is(Items.NETHERITE_HELMET)
|
|
+ && this.getItemBySlot(EquipmentSlot.CHEST).is(Items.NETHERITE_CHESTPLATE)
|
|
+ && this.getItemBySlot(EquipmentSlot.LEGS).is(Items.NETHERITE_LEGGINGS)
|
|
+ && this.getItemBySlot(EquipmentSlot.FEET).is(Items.NETHERITE_BOOTS)) {
|
|
+ this.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE, this.level().purpurConfig.playerNetheriteFireResistanceDuration, this.level().purpurConfig.playerNetheriteFireResistanceAmplifier, this.level().purpurConfig.playerNetheriteFireResistanceAmbient, this.level().purpurConfig.playerNetheriteFireResistanceShowParticles, this.level().purpurConfig.playerNetheriteFireResistanceShowIcon), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.NETHERITE_ARMOR);
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
this.cooldowns.tick();
|
|
this.updatePlayerPose();
|
|
if (this.currentImpulseContextResetGraceTime > 0) {
|
|
@@ -622,7 +662,7 @@ public abstract class Player extends LivingEntity {
|
|
while (iterator.hasNext()) {
|
|
Entity entity = (Entity) iterator.next();
|
|
|
|
- if (entity.getType() == EntityType.EXPERIENCE_ORB) {
|
|
+ if (entity.getType() == EntityType.EXPERIENCE_ORB && entity.level().purpurConfig.playerExpPickupDelay >= 0) { // Purpur
|
|
list1.add(entity);
|
|
} else if (!entity.isRemoved()) {
|
|
this.touch(entity);
|
|
@@ -1274,7 +1314,7 @@ public abstract class Player extends LivingEntity {
|
|
flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits
|
|
if (flag2) {
|
|
damagesource = damagesource.critical(true); // Paper start - critical damage API
|
|
- f *= 1.5F;
|
|
+ f *= this.level().purpurConfig.playerCriticalDamageMultiplier; // Purpur
|
|
}
|
|
|
|
float f3 = f + f1;
|
|
@@ -1640,7 +1680,7 @@ public abstract class Player extends LivingEntity {
|
|
}
|
|
|
|
@Override
|
|
- protected boolean canGlide() {
|
|
+ public boolean canGlide() { // Purpur
|
|
return !this.abilities.flying && super.canGlide();
|
|
}
|
|
|
|
@@ -1900,7 +1940,23 @@ public abstract class Player extends LivingEntity {
|
|
|
|
@Override
|
|
protected int getBaseExperienceReward(ServerLevel world) {
|
|
- return !world.getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) && !this.isSpectator() ? Math.min(this.experienceLevel * 7, 100) : 0;
|
|
+ // Purpur start
|
|
+ if (!world.getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) && !this.isSpectator()) {
|
|
+ int toDrop;
|
|
+ try {
|
|
+ toDrop = Math.round(((Number) scriptEngine.eval("let expLevel = " + experienceLevel + "; " +
|
|
+ "let expTotal = " + totalExperience + "; " +
|
|
+ "let exp = " + experienceProgress + "; " +
|
|
+ level().purpurConfig.playerDeathExpDropEquation)).floatValue());
|
|
+ } catch (javax.script.ScriptException e) {
|
|
+ e.printStackTrace();
|
|
+ toDrop = experienceLevel * 7;
|
|
+ }
|
|
+ return Math.min(toDrop, level().purpurConfig.playerDeathExpDropMax);
|
|
+ } else {
|
|
+ return 0;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
|
|
@Override
|
|
@@ -1978,6 +2034,13 @@ public abstract class Player extends LivingEntity {
|
|
return slot != EquipmentSlot.BODY;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean dismountsUnderwater() {
|
|
+ return !level().purpurConfig.playerRidableInWater;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public boolean setEntityOnShoulder(CompoundTag entityNbt) {
|
|
if (!this.isPassenger() && this.onGround() && !this.isInWater() && !this.isInPowderSnow) {
|
|
if (this.getShoulderEntityLeft().isEmpty()) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
|
|
index accc246f441c8bf5e1a755cfc0db8f97c0c01c6b..f91519f73e766cf891351a95d76abb416da2f957 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
|
|
@@ -80,6 +80,7 @@ public abstract class AbstractArrow extends Projectile {
|
|
public ItemStack pickupItemStack;
|
|
@Nullable
|
|
public ItemStack firedFromWeapon;
|
|
+ public net.minecraft.world.item.enchantment.ItemEnchantments actualEnchantments = net.minecraft.world.item.enchantment.ItemEnchantments.EMPTY; // Purpur - Add an option to fix MC-3304 projectile looting
|
|
|
|
// Spigot Start
|
|
@Override
|
|
@@ -371,7 +372,7 @@ public abstract class AbstractArrow extends Projectile {
|
|
Vec3 vec3d = this.getDeltaMovement();
|
|
|
|
this.setDeltaMovement(vec3d.multiply((double) (this.random.nextFloat() * 0.2F), (double) (this.random.nextFloat() * 0.2F), (double) (this.random.nextFloat() * 0.2F)));
|
|
- this.life = 0;
|
|
+ if (this.level().purpurConfig.arrowMovementResetsDespawnCounter) this.life = 0; // Purpur - do not reset despawn counter
|
|
}
|
|
|
|
public boolean isInGround() {
|
|
@@ -623,6 +624,12 @@ public abstract class AbstractArrow extends Projectile {
|
|
return this.firedFromWeapon;
|
|
}
|
|
|
|
+ // Purpur start - Add an option to fix MC-3304 projectile looting
|
|
+ public void setActualEnchantments(net.minecraft.world.item.enchantment.ItemEnchantments actualEnchantments) {
|
|
+ this.actualEnchantments = actualEnchantments;
|
|
+ }
|
|
+ // Purpur end - Add an option to fix MC-3304 projectile looting
|
|
+
|
|
protected SoundEvent getDefaultHitGroundSoundEvent() {
|
|
return SoundEvents.ARROW_HIT;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/projectile/LargeFireball.java b/src/main/java/net/minecraft/world/entity/projectile/LargeFireball.java
|
|
index 2f00676f62478897ae4931ea06e047567c407535..6bd6113cabfae068aa421991f0a9016419f20349 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/projectile/LargeFireball.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/projectile/LargeFireball.java
|
|
@@ -23,13 +23,13 @@ public class LargeFireball extends Fireball {
|
|
|
|
public LargeFireball(EntityType<? extends LargeFireball> type, Level world) {
|
|
super(type, world);
|
|
- this.isIncendiary = (world instanceof ServerLevel worldserver) && worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit
|
|
+ this.isIncendiary = (world instanceof ServerLevel worldserver) && (worldserver.purpurConfig.fireballsBypassMobGriefing || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)); // CraftBukkit // Purpur
|
|
}
|
|
|
|
public LargeFireball(Level world, LivingEntity owner, Vec3 velocity, int explosionPower) {
|
|
super(EntityType.FIREBALL, owner, velocity, world);
|
|
this.explosionPower = explosionPower;
|
|
- this.isIncendiary = (world instanceof ServerLevel worldserver) && worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit
|
|
+ this.isIncendiary = (world instanceof ServerLevel worldserver) && (worldserver.purpurConfig.fireballsBypassMobGriefing || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)); // CraftBukkit // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -38,7 +38,7 @@ public class LargeFireball extends Fireball {
|
|
Level world = this.level();
|
|
|
|
if (world instanceof ServerLevel worldserver) {
|
|
- boolean flag = worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
|
|
+ boolean flag = worldserver.purpurConfig.fireballsBypassMobGriefing || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Purpur
|
|
|
|
// CraftBukkit start - fire ExplosionPrimeEvent
|
|
ExplosionPrimeEvent event = new ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity());
|
|
diff --git a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java
|
|
index 958ea103cc80da7366cc33dc385b76d4f5c809f2..0b7f27a6cc6be58fa5b60002059c9fbb3b1b7b67 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java
|
|
@@ -33,6 +33,12 @@ public class LlamaSpit extends Projectile {
|
|
this.setPos(owner.getX() - (double) (owner.getBbWidth() + 1.0F) * 0.5D * (double) Mth.sin(owner.yBodyRot * 0.017453292F), owner.getEyeY() - 0.10000000149011612D, owner.getZ() + (double) (owner.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(owner.yBodyRot * 0.017453292F));
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public void super_tick() {
|
|
+ super.tick();
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected double getDefaultGravity() {
|
|
return 0.06D;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
|
|
index 6c2d4d6f3a36ab452dfd3c33f66e54f152906639..275347d563fbcffa896b6c1c9f7f51c8797c2379 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
|
|
@@ -480,7 +480,7 @@ public abstract class Projectile extends Entity implements TraceableEntity {
|
|
public boolean mayInteract(ServerLevel world, BlockPos pos) {
|
|
Entity entity = this.getOwner();
|
|
|
|
- return entity instanceof Player ? entity.mayInteract(world, pos) : entity == null || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
|
|
+ return entity instanceof Player ? entity.mayInteract(world, pos) : entity == null || world.purpurConfig.projectilesBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
|
|
}
|
|
|
|
public boolean mayBreak(ServerLevel world) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java b/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java
|
|
index bb159ea4baf208aab6d6fcfbbddacd5b089b55c8..69dd29ed5e3cb37180b65183b0a83c8619d8e9a0 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java
|
|
@@ -30,7 +30,7 @@ public class SmallFireball extends Fireball {
|
|
super(EntityType.SMALL_FIREBALL, owner, velocity, world);
|
|
// CraftBukkit start
|
|
if (this.getOwner() != null && this.getOwner() instanceof Mob) {
|
|
- this.isIncendiary = (world instanceof ServerLevel worldserver) && worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
|
|
+ this.isIncendiary = (world instanceof ServerLevel worldserver) && (worldserver.purpurConfig.fireballsBypassMobGriefing || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)); // Purpur
|
|
}
|
|
// CraftBukkit end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Snowball.java b/src/main/java/net/minecraft/world/entity/projectile/Snowball.java
|
|
index 70961e151666a0ecf5b791853f4581eaebbdcc8b..0db58e7d63a5c1b43a2224c247979f23a1d3f899 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/projectile/Snowball.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/projectile/Snowball.java
|
|
@@ -58,11 +58,41 @@ public class Snowball extends ThrowableItemProjectile {
|
|
protected void onHitEntity(EntityHitResult entityHitResult) {
|
|
super.onHitEntity(entityHitResult);
|
|
Entity entity = entityHitResult.getEntity();
|
|
- int i = entity instanceof Blaze ? 3 : 0;
|
|
+ int i = entity.level().purpurConfig.snowballDamage >= 0 ? entity.level().purpurConfig.snowballDamage : entity instanceof Blaze ? 3 : 0; // Purpur
|
|
|
|
entity.hurt(this.damageSources().thrown(this, this.getOwner()), (float) i);
|
|
}
|
|
|
|
+ // Purpur start - borrowed and modified code from ThrownPotion#onHitBlock and ThrownPotion#dowseFire
|
|
+ @Override
|
|
+ protected void onHitBlock(net.minecraft.world.phys.BlockHitResult blockHitResult) {
|
|
+ super.onHitBlock(blockHitResult);
|
|
+
|
|
+ if (!this.level().isClientSide) {
|
|
+ net.minecraft.core.BlockPos blockposition = blockHitResult.getBlockPos();
|
|
+ net.minecraft.core.BlockPos blockposition1 = blockposition.relative(blockHitResult.getDirection());
|
|
+
|
|
+ net.minecraft.world.level.block.state.BlockState iblockdata = this.level().getBlockState(blockposition);
|
|
+
|
|
+ if (this.level().purpurConfig.snowballExtinguishesFire && this.level().getBlockState(blockposition1).is(net.minecraft.world.level.block.Blocks.FIRE)) {
|
|
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition1, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState())) {
|
|
+ this.level().removeBlock(blockposition1, false);
|
|
+ }
|
|
+ } else if (this.level().purpurConfig.snowballExtinguishesCandles && net.minecraft.world.level.block.AbstractCandleBlock.isLit(iblockdata)) {
|
|
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.setValue(net.minecraft.world.level.block.AbstractCandleBlock.LIT, false))) {
|
|
+ net.minecraft.world.level.block.AbstractCandleBlock.extinguish(null, iblockdata, this.level(), blockposition);
|
|
+ }
|
|
+ } else if (this.level().purpurConfig.snowballExtinguishesCampfires && net.minecraft.world.level.block.CampfireBlock.isLitCampfire(iblockdata)) {
|
|
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.setValue(net.minecraft.world.level.block.CampfireBlock.LIT, false))) {
|
|
+ this.level().levelEvent(null, 1009, blockposition, 0);
|
|
+ net.minecraft.world.level.block.CampfireBlock.dowse(this.getOwner(), this.level(), blockposition, iblockdata);
|
|
+ this.level().setBlockAndUpdate(blockposition, iblockdata.setValue(net.minecraft.world.level.block.CampfireBlock.LIT, false));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void onHit(HitResult hitResult) {
|
|
super.onHit(hitResult);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java
|
|
index bd2684528157f928460f2143dd71a48e11983123..0720df603b4f89dd6aa346091b13033ad5d62907 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java
|
|
@@ -152,10 +152,11 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
|
|
return;
|
|
}
|
|
// CraftBukkit end
|
|
- if (this.random.nextFloat() < 0.05F && worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) {
|
|
+ if (this.random.nextFloat() < worldserver.purpurConfig.enderPearlEndermiteChance && worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { // Purpur
|
|
Endermite entityendermite = (Endermite) EntityType.ENDERMITE.create(worldserver, EntitySpawnReason.TRIGGERED);
|
|
|
|
if (entityendermite != null) {
|
|
+ entityendermite.setPlayerSpawned(true); // Purpur
|
|
entityendermite.moveTo(entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot());
|
|
worldserver.addFreshEntity(entityendermite, CreatureSpawnEvent.SpawnReason.ENDER_PEARL);
|
|
}
|
|
@@ -170,7 +171,7 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
|
|
if (entityplayer1 != null) {
|
|
entityplayer1.resetFallDistance();
|
|
entityplayer1.resetCurrentImpulseContext();
|
|
- entityplayer1.hurtServer(entityplayer.serverLevel(), this.damageSources().enderPearl().customEventDamager(this), 5.0F); // CraftBukkit // Paper - fix DamageSource API
|
|
+ entityplayer1.hurtServer(entityplayer.serverLevel(), this.damageSources().enderPearl().customEventDamager(this), this.level().purpurConfig.enderPearlDamage); // CraftBukkit // Paper - fix DamageSource API // Purpur
|
|
}
|
|
|
|
this.playSound(worldserver, vec3d);
|
|
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 322733266fdca8ce43434a8ffea304c51794bcbb..489c26423a7f5bc9da45d247de57ec989cc74119 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java
|
|
@@ -69,7 +69,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()) {
|
|
Level world = this.level();
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java
|
|
index 4c47b30867e30d84908abf93dbefc252bc8c3453..e63b408594b5d2673148e39c1deafc8510537bee 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java
|
|
@@ -103,7 +103,7 @@ public class WitherSkull extends AbstractHurtingProjectile {
|
|
if (!this.level().isClientSide) {
|
|
// CraftBukkit start
|
|
// this.level().explode(this, this.getX(), this.getY(), this.getZ(), 1.0F, false, World.a.MOB);
|
|
- ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 1.0F, false);
|
|
+ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), this.level().purpurConfig.witherExplosionRadius, false); // Purpur
|
|
this.level().getCraftServer().getPluginManager().callEvent(event);
|
|
|
|
if (!event.isCancelled()) {
|
|
@@ -115,6 +115,19 @@ public class WitherSkull extends AbstractHurtingProjectile {
|
|
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean canHitEntity(Entity target) {
|
|
+ // do not hit rider
|
|
+ return target != this.getRider() && super.canHitEntity(target);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canSaveToDisk() {
|
|
+ return false;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
|
builder.define(WitherSkull.DATA_DANGEROUS, false);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/raid/Raider.java b/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
|
index ab132041982df2a701e4baea8195873f31b4a5fb..4ef87acec025c6eb706fd8845663aa4f415efb29 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
|
@@ -345,7 +345,7 @@ public abstract class Raider extends PatrollingMonster {
|
|
}
|
|
|
|
private boolean cannotPickUpBanner() {
|
|
- if (!getServerLevel(this.mob).getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items
|
|
+ if ((!this.mob.level().purpurConfig.pillagerBypassMobGriefing && !getServerLevel(this.mob).getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING)) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items // Purpur
|
|
if (!this.mob.hasActiveRaid()) {
|
|
return true;
|
|
} else if (this.mob.getCurrentRaid().isOver()) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/raid/Raids.java b/src/main/java/net/minecraft/world/entity/raid/Raids.java
|
|
index 439d61d8689fabe940006b9b317a6810175dccfb..6b30941a84054efb5fcccb5d9e6c80d713a23889 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/raid/Raids.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/raid/Raids.java
|
|
@@ -26,6 +26,7 @@ import net.minecraft.world.phys.Vec3;
|
|
public class Raids extends SavedData {
|
|
|
|
private static final String RAID_FILE_ID = "raids";
|
|
+ public final Map<java.util.UUID, Integer> playerCooldowns = Maps.newHashMap();
|
|
public final Map<Integer, Raid> raidMap = Maps.newHashMap();
|
|
private final ServerLevel level;
|
|
private int nextAvailableID;
|
|
@@ -51,6 +52,17 @@ public class Raids extends SavedData {
|
|
|
|
public void tick() {
|
|
++this.tick;
|
|
+ // Purpur start
|
|
+ if (level.purpurConfig.raidCooldownSeconds != 0 && this.tick % 20 == 0) {
|
|
+ com.google.common.collect.ImmutableMap.copyOf(playerCooldowns).forEach((uuid, i) -> {
|
|
+ if (i < 1) {
|
|
+ playerCooldowns.remove(uuid);
|
|
+ } else {
|
|
+ playerCooldowns.put(uuid, i - 1);
|
|
+ }
|
|
+ });
|
|
+ }
|
|
+ // Purpur end
|
|
Iterator<Raid> iterator = this.raidMap.values().iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
@@ -122,11 +134,13 @@ public class Raids extends SavedData {
|
|
*/
|
|
|
|
if (!raid.isStarted() || (raid.isInProgress() && raid.getRaidOmenLevel() < raid.getMaxRaidOmenLevel())) { // CraftBukkit - fixed a bug with raid: players could add up Bad Omen level even when the raid had finished
|
|
+ if (level.purpurConfig.raidCooldownSeconds != 0 && playerCooldowns.containsKey(player.getUUID())) return null; // Purpur
|
|
// CraftBukkit start
|
|
if (!org.bukkit.craftbukkit.event.CraftEventFactory.callRaidTriggerEvent(raid, player)) {
|
|
player.removeEffect(net.minecraft.world.effect.MobEffects.RAID_OMEN);
|
|
return null;
|
|
}
|
|
+ if (level.purpurConfig.raidCooldownSeconds != 0) playerCooldowns.put(player.getUUID(), level.purpurConfig.raidCooldownSeconds); // Purpur
|
|
|
|
if (!raid.isStarted() && !this.raidMap.containsKey(raid.getId())) {
|
|
this.raidMap.put(raid.getId(), raid);
|
|
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java
|
|
index 1fdbef16cd29c8fc74578ac3328f985eca61088d..56c265940208bc94f531a5af94f564b59f35ebf3 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java
|
|
@@ -499,6 +499,7 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
|
|
|
|
if (f > 0.0F) {
|
|
this.landFriction = f;
|
|
+ if (level().purpurConfig.boatEjectPlayersOnLand) ejectPassengers(); // Purpur
|
|
return AbstractBoat.Status.ON_LAND;
|
|
} else {
|
|
return AbstractBoat.Status.IN_AIR;
|
|
@@ -929,7 +930,13 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
|
|
|
|
@Override
|
|
public final ItemStack getPickResult() {
|
|
- return new ItemStack((ItemLike) this.dropItem.get());
|
|
+ // Purpur start
|
|
+ final ItemStack boat = new ItemStack((ItemLike) this.dropItem.get());
|
|
+ if (!this.level().purpurConfig.persistentDroppableEntityDisplayNames) {
|
|
+ boat.set(net.minecraft.core.component.DataComponents.CUSTOM_NAME, null);
|
|
+ }
|
|
+ return boat;
|
|
+ // Purpur end
|
|
}
|
|
|
|
public static enum Status {
|
|
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 d277f56fef882313d6d21f636fafae2f26630ad7..a1593297b6764ba0229cc1c8f5a55aef107ff9df 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java
|
|
@@ -92,6 +92,7 @@ public abstract class AbstractMinecart extends VehicleEntity {
|
|
private double flyingY = 0.95;
|
|
private double flyingZ = 0.95;
|
|
public double maxSpeed = 0.4D;
|
|
+ public double storedMaxSpeed; // Purpur
|
|
// CraftBukkit end
|
|
public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API
|
|
|
|
@@ -103,6 +104,7 @@ public abstract class AbstractMinecart extends VehicleEntity {
|
|
} else {
|
|
this.behavior = new OldMinecartBehavior(this);
|
|
}
|
|
+ if (world != null) maxSpeed = storedMaxSpeed = world.purpurConfig.minecartMaxSpeed; // Purpur
|
|
|
|
}
|
|
|
|
@@ -289,6 +291,12 @@ public abstract class AbstractMinecart extends VehicleEntity {
|
|
|
|
@Override
|
|
public void tick() {
|
|
+ // Purpur start
|
|
+ if (storedMaxSpeed != level().purpurConfig.minecartMaxSpeed) {
|
|
+ maxSpeed = storedMaxSpeed = level().purpurConfig.minecartMaxSpeed;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
// CraftBukkit start
|
|
double prevX = this.getX();
|
|
double prevY = this.getY();
|
|
@@ -426,16 +434,62 @@ public abstract class AbstractMinecart extends VehicleEntity {
|
|
this.behavior.moveAlongTrack(world);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ private Double lastSpeed;
|
|
+
|
|
+ public double getControllableSpeed() {
|
|
+ BlockState blockState = level().getBlockState(this.blockPosition());
|
|
+ if (!blockState.isSolid()) {
|
|
+ blockState = level().getBlockState(this.blockPosition().relative(Direction.DOWN));
|
|
+ }
|
|
+ Double speed = level().purpurConfig.minecartControllableBlockSpeeds.get(blockState.getBlock());
|
|
+ if (!blockState.isSolid()) {
|
|
+ speed = lastSpeed;
|
|
+ }
|
|
+ if (speed == null) {
|
|
+ speed = level().purpurConfig.minecartControllableBaseSpeed;
|
|
+ }
|
|
+ return lastSpeed = speed;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
protected void comeOffTrack(ServerLevel world) {
|
|
double d0 = this.getMaxSpeed(world);
|
|
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/entity/vehicle/NewMinecartBehavior.java b/src/main/java/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java
|
|
index a8718ee94cd6b9a20bd1e9a49d58d39e6f3f2a7a..4b2c3e30a440ab8d035a48fdd612b61a29143836 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java
|
|
@@ -426,7 +426,7 @@ public class NewMinecartBehavior extends MinecartBehavior {
|
|
private Vec3 calculateBoostTrackSpeed(Vec3 velocity, BlockPos railPos, BlockState railState) {
|
|
if (railState.is(Blocks.POWERED_RAIL) && (Boolean) railState.getValue(PoweredRailBlock.POWERED)) {
|
|
if (velocity.length() > 0.01D) {
|
|
- return velocity.normalize().scale(velocity.length() + 0.06D);
|
|
+ return velocity.normalize().scale(velocity.length() + this.level().purpurConfig.poweredRailBoostModifier); // Purpur
|
|
} else {
|
|
Vec3 vec3d1 = this.minecart.getRedstoneDirection(railPos);
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java b/src/main/java/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java
|
|
index 23cbafcc12f6e5f5755215a72879a6cab306ad18..ca6883d0f0c2cc8f843c59476dbcf46a62cbd550 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java
|
|
@@ -310,9 +310,9 @@ public class OldMinecartBehavior extends MinecartBehavior {
|
|
vec3d5 = this.getDeltaMovement();
|
|
d17 = vec3d5.horizontalDistance();
|
|
if (d17 > 0.01D) {
|
|
- double d19 = 0.06D;
|
|
+ double d19 = world.purpurConfig.poweredRailBoostModifier; // Purpur
|
|
|
|
- this.setDeltaMovement(vec3d5.add(vec3d5.x / d17 * 0.06D, 0.0D, vec3d5.z / d17 * 0.06D));
|
|
+ this.setDeltaMovement(vec3d5.add(vec3d5.x / d17 * world.purpurConfig.poweredRailBoostModifier, 0.0D, vec3d5.z / d17 * world.purpurConfig.poweredRailBoostModifier)); // Purpur
|
|
} else {
|
|
Vec3 vec3d6 = this.getDeltaMovement();
|
|
double d20 = vec3d6.x;
|
|
diff --git a/src/main/java/net/minecraft/world/food/FoodData.java b/src/main/java/net/minecraft/world/food/FoodData.java
|
|
index 6a686be6a69ae890d519a54ca099d4ba14e5b9e1..b8b0b89b7f0a21ecff4ab6286f8a114e2d6b6b39 100644
|
|
--- a/src/main/java/net/minecraft/world/food/FoodData.java
|
|
+++ b/src/main/java/net/minecraft/world/food/FoodData.java
|
|
@@ -44,6 +44,7 @@ public class FoodData {
|
|
org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(entityplayer, foodinfo.nutrition() + oldFoodLevel, itemstack);
|
|
|
|
if (!event.isCancelled()) {
|
|
+ if (entityplayer.level().purpurConfig.playerBurpWhenFull && event.getFoodLevel() == 20 && oldFoodLevel < 20) entityplayer.burpDelay = entityplayer.level().purpurConfig.playerBurpDelay; // Purpur
|
|
this.add(event.getFoodLevel() - oldFoodLevel, foodinfo.saturation());
|
|
}
|
|
|
|
@@ -96,7 +97,7 @@ public class FoodData {
|
|
++this.tickTimer;
|
|
if (this.tickTimer >= this.starvationRate) { // CraftBukkit - add regen rate manipulation
|
|
if (player.getHealth() > 10.0F || enumdifficulty == Difficulty.HARD || player.getHealth() > 1.0F && enumdifficulty == Difficulty.NORMAL) {
|
|
- player.hurtServer(worldserver, player.damageSources().starve(), 1.0F);
|
|
+ player.hurtServer(worldserver, player.damageSources().starve(), player.level().purpurConfig.hungerStarvationDamage); // Purpur
|
|
}
|
|
|
|
this.tickTimer = 0;
|
|
diff --git a/src/main/java/net/minecraft/world/food/FoodProperties.java b/src/main/java/net/minecraft/world/food/FoodProperties.java
|
|
index 882b72799ae532f4e181214d5756ec024af223e2..9a3f2a95debcf8b94f7deb375922ea09b30aabab 100644
|
|
--- a/src/main/java/net/minecraft/world/food/FoodProperties.java
|
|
+++ b/src/main/java/net/minecraft/world/food/FoodProperties.java
|
|
@@ -33,7 +33,7 @@ public record FoodProperties(int nutrition, float saturation, boolean canAlwaysE
|
|
world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), (SoundEvent) consumable.sound().value(), SoundSource.NEUTRAL, 1.0F, randomsource.triangle(1.0F, 0.4F));
|
|
if (user instanceof Player entityhuman) {
|
|
entityhuman.getFoodData().eat(this, stack, (ServerPlayer) entityhuman); // CraftBukkit
|
|
- world.playSound((Player) null, entityhuman.getX(), entityhuman.getY(), entityhuman.getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 0.5F, Mth.randomBetween(randomsource, 0.9F, 1.0F));
|
|
+ //world.playSound((Player) null, entityhuman.getX(), entityhuman.getY(), entityhuman.getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 0.5F, Mth.randomBetween(randomsource, 0.9F, 1.0F)); // Purpur - moved to Player#tick()
|
|
}
|
|
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
|
|
index 4680f77a275d8d2b226018db89a571ac25998dd8..bfc90524bd739ed1d91fe9912e38093b3c28928f 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
|
|
@@ -80,6 +80,7 @@ public abstract class AbstractContainerMenu {
|
|
@Nullable
|
|
private ContainerSynchronizer synchronizer;
|
|
private boolean suppressRemoteUpdates;
|
|
+ @Nullable protected ItemStack activeQuickItem = null; // Purpur - Anvil API
|
|
|
|
// CraftBukkit start
|
|
public boolean checkReachable = true;
|
|
diff --git a/src/main/java/net/minecraft/world/inventory/AbstractFurnaceMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractFurnaceMenu.java
|
|
index 1240df9368855f836412b06cf564926a18bfe90d..e559eabed82d2f402908e5b80d1505076ccc53a2 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/AbstractFurnaceMenu.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/AbstractFurnaceMenu.java
|
|
@@ -114,7 +114,13 @@ public abstract class AbstractFurnaceMenu extends RecipeBookMenu {
|
|
} else if (slot != 1 && slot != 0) {
|
|
if (this.canSmelt(itemstack1)) {
|
|
if (!this.moveItemStackTo(itemstack1, 0, 1, false)) {
|
|
- return ItemStack.EMPTY;
|
|
+ // Purpur start - fix #625
|
|
+ if (this.isFuel(itemstack1)) {
|
|
+ if (!this.moveItemStackTo(itemstack1, 1, 2, false)) {
|
|
+ return ItemStack.EMPTY;
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
} else if (this.isFuel(itemstack1)) {
|
|
if (!this.moveItemStackTo(itemstack1, 1, 2, false)) {
|
|
diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
|
|
index dc2bc53f6fa84fa09bd86450060ad9878307001c..f8476a8fb38897af0dd63bfb20276ac1c4bbd4f0 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
|
|
@@ -25,6 +25,12 @@ import org.slf4j.Logger;
|
|
import org.bukkit.craftbukkit.inventory.view.CraftAnvilView;
|
|
// CraftBukkit end
|
|
|
|
+// Purpur start - Anvil API
|
|
+import net.minecraft.network.protocol.game.ClientboundContainerSetDataPacket;
|
|
+import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+// Purpur end - Anvil API
|
|
+
|
|
public class AnvilMenu extends ItemCombinerMenu {
|
|
|
|
public static final int INPUT_SLOT = 0;
|
|
@@ -55,6 +61,10 @@ public class AnvilMenu extends ItemCombinerMenu {
|
|
private CraftAnvilView bukkitEntity;
|
|
// CraftBukkit end
|
|
public boolean bypassEnchantmentLevelRestriction = false; // Paper - bypass anvil level restrictions
|
|
+ // Purpur start - Anvil API
|
|
+ public boolean bypassCost = false;
|
|
+ public boolean canDoUnsafeEnchants = false;
|
|
+ // Purpur end - Anvil API
|
|
|
|
public AnvilMenu(int syncId, Inventory inventory) {
|
|
this(syncId, inventory, ContainerLevelAccess.NULL);
|
|
@@ -82,12 +92,17 @@ public class AnvilMenu extends ItemCombinerMenu {
|
|
|
|
@Override
|
|
protected boolean mayPickup(Player player, boolean present) {
|
|
- return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST && present; // CraftBukkit - allow cost 0 like a free item
|
|
+ return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && (this.bypassCost || this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST) && present; // CraftBukkit - allow cost 0 like a free item // Purpur - Anvil API
|
|
}
|
|
|
|
@Override
|
|
protected void onTake(Player player, ItemStack stack) {
|
|
+ // Purpur start - Anvil API
|
|
+ ItemStack itemstack = this.activeQuickItem != null ? this.activeQuickItem : stack;
|
|
+ if (org.purpurmc.purpur.event.inventory.AnvilTakeResultEvent.getHandlerList().getRegisteredListeners().length > 0) new org.purpurmc.purpur.event.inventory.AnvilTakeResultEvent(player.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)).callEvent();
|
|
+ // Purpur end - Anvil API
|
|
if (!player.getAbilities().instabuild) {
|
|
+ if (this.bypassCost) ((ServerPlayer) player).lastSentExp = -1; else // Purpur - Anvil API
|
|
player.giveExperienceLevels(-this.cost.get());
|
|
}
|
|
|
|
@@ -138,6 +153,12 @@ public class AnvilMenu extends ItemCombinerMenu {
|
|
|
|
@Override
|
|
public void createResult() {
|
|
+ // Purpur start - Anvil API
|
|
+ this.bypassCost = false;
|
|
+ this.canDoUnsafeEnchants = false;
|
|
+ if (org.purpurmc.purpur.event.inventory.AnvilUpdateResultEvent.getHandlerList().getRegisteredListeners().length > 0) new org.purpurmc.purpur.event.inventory.AnvilUpdateResultEvent(getBukkitView()).callEvent();
|
|
+ // Purpur end - Anvil API
|
|
+
|
|
ItemStack itemstack = this.inputSlots.getItem(0);
|
|
|
|
this.onlyRenaming = false;
|
|
@@ -146,7 +167,7 @@ public class AnvilMenu extends ItemCombinerMenu {
|
|
long j = 0L;
|
|
byte b0 = 0;
|
|
|
|
- if (!itemstack.isEmpty() && EnchantmentHelper.canStoreEnchantments(itemstack)) {
|
|
+ if (!itemstack.isEmpty() && this.canDoUnsafeEnchants || EnchantmentHelper.canStoreEnchantments(itemstack)) { // Purpur - Anvil API
|
|
ItemStack itemstack1 = itemstack.copy();
|
|
ItemStack itemstack2 = this.inputSlots.getItem(1);
|
|
ItemEnchantments.Mutable itemenchantments_a = new ItemEnchantments.Mutable(EnchantmentHelper.getEnchantmentsForCrafting(itemstack1));
|
|
@@ -213,7 +234,10 @@ public class AnvilMenu extends ItemCombinerMenu {
|
|
|
|
i2 = l1 == i2 ? i2 + 1 : Math.max(i2, l1);
|
|
Enchantment enchantment = (Enchantment) holder.value();
|
|
- boolean flag3 = enchantment.canEnchant(itemstack);
|
|
+ // Purpur start - Config to allow unsafe enchants
|
|
+ boolean flag3 = this.canDoUnsafeEnchants || org.purpurmc.purpur.PurpurConfig.allowInapplicableEnchants || enchantment.canEnchant(itemstack); // whether the enchantment can be applied on specific item type
|
|
+ boolean flag4 = true; // whether two incompatible enchantments can be applied on a single item
|
|
+ // Purpur end - Config to allow unsafe enchants
|
|
|
|
if (this.player.getAbilities().instabuild || itemstack.is(Items.ENCHANTED_BOOK)) {
|
|
flag3 = true;
|
|
@@ -225,16 +249,22 @@ public class AnvilMenu extends ItemCombinerMenu {
|
|
Holder<Enchantment> holder1 = (Holder) iterator1.next();
|
|
|
|
if (!holder1.equals(holder) && !Enchantment.areCompatible(holder, holder1)) {
|
|
- flag3 = false;
|
|
+ flag4 = this.canDoUnsafeEnchants || org.purpurmc.purpur.PurpurConfig.allowIncompatibleEnchants; // Purpur - Anvil API // Purpur - flag3 -> flag4 - Config to allow unsafe enchants
|
|
+ // Purpur start - Config to allow unsafe enchants
|
|
+ if (!flag4 && org.purpurmc.purpur.PurpurConfig.replaceIncompatibleEnchants) {
|
|
+ iterator1.remove(); // replace current enchant with the incompatible one trying to be applied
|
|
+ flag4 = true;
|
|
+ }
|
|
+ // Purpur end - Config to allow unsafe enchants
|
|
++i;
|
|
}
|
|
}
|
|
|
|
- if (!flag3) {
|
|
+ if (!flag3 || !flag4) { // Purpur - Config to allow unsafe enchants
|
|
flag2 = true;
|
|
} else {
|
|
flag1 = true;
|
|
- if (i2 > enchantment.getMaxLevel() && !this.bypassEnchantmentLevelRestriction) { // Paper - bypass anvil level restrictions
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.allowHigherEnchantsLevels && i2 > enchantment.getMaxLevel() && !this.bypassEnchantmentLevelRestriction) { // Paper - bypass anvil level restrictions // Purpur - Config to allow unsafe enchants
|
|
i2 = enchantment.getMaxLevel();
|
|
}
|
|
|
|
@@ -264,6 +294,54 @@ public class AnvilMenu extends ItemCombinerMenu {
|
|
if (!this.itemName.equals(itemstack.getHoverName().getString())) {
|
|
b0 = 1;
|
|
i += b0;
|
|
+ // Purpur start
|
|
+ if (this.player != null) {
|
|
+ org.bukkit.craftbukkit.entity.CraftHumanEntity player = this.player.getBukkitEntity();
|
|
+ String name = this.itemName;
|
|
+ boolean removeItalics = false;
|
|
+ if (player.hasPermission("purpur.anvil.remove_italics")) {
|
|
+ if (name.startsWith("&r")) {
|
|
+ name = name.substring(2);
|
|
+ removeItalics = true;
|
|
+ } else if (name.startsWith("<r>")) {
|
|
+ name = name.substring(3);
|
|
+ removeItalics = true;
|
|
+ } else if (name.startsWith("<reset>")) {
|
|
+ name = name.substring(7);
|
|
+ removeItalics = true;
|
|
+ }
|
|
+ }
|
|
+ if (this.player.level().purpurConfig.anvilAllowColors) {
|
|
+ if (player.hasPermission("purpur.anvil.color")) {
|
|
+ java.util.regex.Matcher matcher = java.util.regex.Pattern.compile("(?i)&([0-9a-fr])").matcher(name);
|
|
+ while (matcher.find()) {
|
|
+ String match = matcher.group(1);
|
|
+ name = name.replace("&" + match, "\u00a7" + match.toLowerCase(java.util.Locale.ROOT));
|
|
+ }
|
|
+ //name = name.replaceAll("(?i)&([0-9a-fr])", "\u00a7$1");
|
|
+ }
|
|
+ if (player.hasPermission("purpur.anvil.format")) {
|
|
+ java.util.regex.Matcher matcher = java.util.regex.Pattern.compile("(?i)&([k-or])").matcher(name);
|
|
+ while (matcher.find()) {
|
|
+ String match = matcher.group(1);
|
|
+ name = name.replace("&" + match, "\u00a7" + match.toLowerCase(java.util.Locale.ROOT));
|
|
+ }
|
|
+ //name = name.replaceAll("(?i)&([l-or])", "\u00a7$1");
|
|
+ }
|
|
+ }
|
|
+ net.kyori.adventure.text.Component component;
|
|
+ if (this.player.level().purpurConfig.anvilColorsUseMiniMessage && player.hasPermission("purpur.anvil.minimessage")) {
|
|
+ component = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.bukkit.ChatColor.stripColor(name));
|
|
+ } else {
|
|
+ component = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(name);
|
|
+ }
|
|
+ if (removeItalics) {
|
|
+ component = component.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false);
|
|
+ }
|
|
+ itemstack1.set(DataComponents.CUSTOM_NAME, io.papermc.paper.adventure.PaperAdventure.asVanilla(component));
|
|
+ }
|
|
+ else
|
|
+ // Purpur end
|
|
itemstack1.set(DataComponents.CUSTOM_NAME, Component.literal(this.itemName));
|
|
}
|
|
} else if (itemstack.has(DataComponents.CUSTOM_NAME)) {
|
|
@@ -287,6 +365,12 @@ public class AnvilMenu extends ItemCombinerMenu {
|
|
this.onlyRenaming = true;
|
|
}
|
|
|
|
+ // Purpur start - Anvil API
|
|
+ if (this.bypassCost && this.cost.get() >= this.maximumRepairCost) {
|
|
+ this.cost.set(this.maximumRepairCost - 1);
|
|
+ }
|
|
+ // Purpur end - Anvil API
|
|
+
|
|
if (this.cost.get() >= this.maximumRepairCost && !this.player.getAbilities().instabuild) { // CraftBukkit
|
|
itemstack1 = ItemStack.EMPTY;
|
|
}
|
|
@@ -308,6 +392,13 @@ public class AnvilMenu extends ItemCombinerMenu {
|
|
org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemstack1); // CraftBukkit
|
|
this.sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686: Always send completed inventory to stay in sync with client
|
|
this.broadcastChanges();
|
|
+
|
|
+ // Purpur start - Anvil API
|
|
+ if ((this.canDoUnsafeEnchants || org.purpurmc.purpur.PurpurConfig.allowInapplicableEnchants || org.purpurmc.purpur.PurpurConfig.allowIncompatibleEnchants) && itemstack1 != ItemStack.EMPTY) { // Purpur - Config to allow unsafe enchants
|
|
+ ((ServerPlayer) this.player).connection.send(new ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), 2, itemstack1));
|
|
+ ((ServerPlayer) this.player).connection.send(new ClientboundContainerSetDataPacket(this.containerId, 0, this.cost.get()));
|
|
+ }
|
|
+ // Purpur end - Anvil API
|
|
} else {
|
|
org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit
|
|
this.cost.set(AnvilMenu.DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item
|
|
@@ -315,7 +406,7 @@ public class AnvilMenu extends ItemCombinerMenu {
|
|
}
|
|
|
|
public static int calculateIncreasedRepairCost(int cost) {
|
|
- return (int) Math.min((long) cost * 2L + 1L, 2147483647L);
|
|
+ return org.purpurmc.purpur.PurpurConfig.anvilCumulativeCost ? (int) Math.min((long) cost * 2L + 1L, 2147483647L) : 0; // Purpur - Make anvil cumulative cost configurable
|
|
}
|
|
|
|
public boolean setItemName(String newItemName) {
|
|
diff --git a/src/main/java/net/minecraft/world/inventory/ArmorSlot.java b/src/main/java/net/minecraft/world/inventory/ArmorSlot.java
|
|
index 6c0b6abb1698fac9bb902f695b725d4ab783ee90..091e3c3514fcb378b68098114106d09f04d8fb0d 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/ArmorSlot.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/ArmorSlot.java
|
|
@@ -45,7 +45,7 @@ class ArmorSlot extends Slot {
|
|
@Override
|
|
public boolean mayPickup(Player playerEntity) {
|
|
ItemStack itemStack = this.getItem();
|
|
- return (itemStack.isEmpty() || playerEntity.isCreative() || !EnchantmentHelper.has(itemStack, EnchantmentEffectComponents.PREVENT_ARMOR_CHANGE))
|
|
+ return (itemStack.isEmpty() || playerEntity.isCreative() || (!EnchantmentHelper.has(itemStack, EnchantmentEffectComponents.PREVENT_ARMOR_CHANGE) || playerEntity.level().purpurConfig.playerRemoveBindingWithWeakness && playerEntity.hasEffect(net.minecraft.world.effect.MobEffects.WEAKNESS)))
|
|
&& super.mayPickup(playerEntity);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/inventory/ChestMenu.java b/src/main/java/net/minecraft/world/inventory/ChestMenu.java
|
|
index 48a6b6136ac3414ca735f93a14b1a8d76210603c..27321b07cd04814bc1ff720c65770d7755625bb6 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/ChestMenu.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/ChestMenu.java
|
|
@@ -66,10 +66,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/EnchantmentMenu.java b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java
|
|
index 50a735dd97daab4fb9579f922a4c63de60204f29..5b8ad051347f73553acb65c5ddc690d2b7eaa754 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java
|
|
@@ -42,6 +42,12 @@ import org.bukkit.event.enchantment.PrepareItemEnchantEvent;
|
|
import org.bukkit.entity.Player;
|
|
// CraftBukkit end
|
|
|
|
+// Purpur start
|
|
+import net.minecraft.world.level.block.entity.BlockEntity;
|
|
+import net.minecraft.world.level.block.entity.EnchantingTableBlockEntity;
|
|
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
|
+// Purpur end
|
|
+
|
|
public class EnchantmentMenu extends AbstractContainerMenu {
|
|
|
|
static final ResourceLocation EMPTY_SLOT_LAPIS_LAZULI = ResourceLocation.withDefaultNamespace("item/empty_slot_lapis_lazuli");
|
|
@@ -76,6 +82,22 @@ public class EnchantmentMenu extends AbstractContainerMenu {
|
|
return context.getLocation();
|
|
}
|
|
// CraftBukkit end
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public void onClose(CraftHumanEntity who) {
|
|
+ super.onClose(who);
|
|
+
|
|
+ if (who.getHandle().level().purpurConfig.enchantmentTableLapisPersists) {
|
|
+ access.execute((level, pos) -> {
|
|
+ BlockEntity blockEntity = level.getBlockEntity(pos);
|
|
+ if (blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) {
|
|
+ enchantmentTable.setLapis(this.getItem(1).getCount());
|
|
+ }
|
|
+ });
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
};
|
|
this.random = RandomSource.create();
|
|
this.enchantmentSeed = DataSlot.standalone();
|
|
@@ -100,6 +122,16 @@ public class EnchantmentMenu extends AbstractContainerMenu {
|
|
return Pair.of(InventoryMenu.BLOCK_ATLAS, EnchantmentMenu.EMPTY_SLOT_LAPIS_LAZULI);
|
|
}
|
|
});
|
|
+ // Purpur start
|
|
+ access.execute((level, pos) -> {
|
|
+ if (level.purpurConfig.enchantmentTableLapisPersists) {
|
|
+ BlockEntity blockEntity = level.getBlockEntity(pos);
|
|
+ if (blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) {
|
|
+ this.getSlot(1).set(new ItemStack(Items.LAPIS_LAZULI, enchantmentTable.getLapis()));
|
|
+ }
|
|
+ }
|
|
+ });
|
|
+ // Purpur end
|
|
this.addStandardInventorySlots(playerInventory, 8, 84);
|
|
this.addDataSlot(DataSlot.shared(this.costs, 0));
|
|
this.addDataSlot(DataSlot.shared(this.costs, 1));
|
|
@@ -329,6 +361,7 @@ public class EnchantmentMenu extends AbstractContainerMenu {
|
|
public void removed(net.minecraft.world.entity.player.Player player) {
|
|
super.removed(player);
|
|
this.access.execute((world, blockposition) -> {
|
|
+ if (world.purpurConfig.enchantmentTableLapisPersists) this.getSlot(1).set(ItemStack.EMPTY); // Purpur
|
|
this.clearContainer(player, this.enchantSlots);
|
|
});
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
|
|
index 5687f492fc76f699e2a388790ca5380d9b8c8d0a..111da7435f0abb5a57bd2c5fecead2380ac4347a 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
|
|
@@ -96,12 +96,14 @@ public class GrindstoneMenu extends AbstractContainerMenu {
|
|
|
|
@Override
|
|
public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) {
|
|
+ ItemStack itemstack = activeQuickItem == null ? stack : activeQuickItem; // Purpur
|
|
context.execute((world, blockposition) -> {
|
|
if (world instanceof ServerLevel) {
|
|
// Paper start - Fire BlockExpEvent on grindstone use
|
|
org.bukkit.event.block.BlockExpEvent event = new org.bukkit.event.block.BlockExpEvent(org.bukkit.craftbukkit.block.CraftBlock.at(world, blockposition), this.getExperienceAmount(world));
|
|
event.callEvent();
|
|
- ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), event.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player);
|
|
+ org.purpurmc.purpur.event.inventory.GrindstoneTakeResultEvent grindstoneTakeResultEvent = new org.purpurmc.purpur.event.inventory.GrindstoneTakeResultEvent(player.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), event.getExpToDrop()); grindstoneTakeResultEvent.callEvent(); // Purpur
|
|
+ ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), grindstoneTakeResultEvent.getExperienceAmount(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); // Purpur
|
|
// Paper end - Fire BlockExpEvent on grindstone use
|
|
}
|
|
|
|
@@ -135,7 +137,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
|
|
Holder<Enchantment> holder = (Holder) entry.getKey();
|
|
int k = entry.getIntValue();
|
|
|
|
- if (!holder.is(EnchantmentTags.CURSE)) {
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(holder.value())) { // Purpur
|
|
j += ((Enchantment) holder.value()).getMinCost(k);
|
|
}
|
|
}
|
|
@@ -222,7 +224,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
|
|
Entry<Holder<Enchantment>> entry = (Entry) iterator.next();
|
|
Holder<Enchantment> holder = (Holder) entry.getKey();
|
|
|
|
- if (!holder.is(EnchantmentTags.CURSE) || itemenchantments_a.getLevel(holder) == 0) {
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(holder.value()) || itemenchantments_a.getLevel(holder) == 0) { // Purpur
|
|
itemenchantments_a.upgrade(holder, entry.getIntValue());
|
|
}
|
|
}
|
|
@@ -230,10 +232,70 @@ public class GrindstoneMenu extends AbstractContainerMenu {
|
|
});
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ private java.util.List<net.minecraft.core.component.DataComponentType<?>> GRINDSTONE_REMOVE_ATTRIBUTES_REMOVAL_LIST = java.util.List.of(
|
|
+ // DataComponents.MAX_STACK_SIZE,
|
|
+ // DataComponents.DAMAGE,
|
|
+ // DataComponents.BLOCK_STATE,
|
|
+ DataComponents.CUSTOM_DATA,
|
|
+ // DataComponents.MAX_DAMAGE,
|
|
+ // DataComponents.UNBREAKABLE,
|
|
+ // DataComponents.CUSTOM_NAME,
|
|
+ // DataComponents.ITEM_NAME,
|
|
+ // DataComponents.LORE,
|
|
+ // DataComponents.RARITY,
|
|
+ // DataComponents.ENCHANTMENTS,
|
|
+ // DataComponents.CAN_PLACE_ON,
|
|
+ // DataComponents.CAN_BREAK,
|
|
+ DataComponents.ATTRIBUTE_MODIFIERS,
|
|
+ DataComponents.CUSTOM_MODEL_DATA,
|
|
+ // DataComponents.HIDE_ADDITIONAL_TOOLTIP,
|
|
+ // DataComponents.HIDE_TOOLTIP,
|
|
+ // DataComponents.REPAIR_COST,
|
|
+ // DataComponents.CREATIVE_SLOT_LOCK,
|
|
+ // DataComponents.ENCHANTMENT_GLINT_OVERRIDE,
|
|
+ // DataComponents.INTANGIBLE_PROJECTILE,
|
|
+ // DataComponents.FOOD,
|
|
+ // DataComponents.FIRE_RESISTANT,
|
|
+ // DataComponents.TOOL,
|
|
+ // DataComponents.STORED_ENCHANTMENTS,
|
|
+ DataComponents.DYED_COLOR,
|
|
+ // DataComponents.MAP_COLOR,
|
|
+ // DataComponents.MAP_ID,
|
|
+ // DataComponents.MAP_DECORATIONS,
|
|
+ // DataComponents.MAP_POST_PROCESSING,
|
|
+ // DataComponents.CHARGED_PROJECTILES,
|
|
+ // DataComponents.BUNDLE_CONTENTS,
|
|
+ // DataComponents.POTION_CONTENTS,
|
|
+ DataComponents.SUSPICIOUS_STEW_EFFECTS
|
|
+ // DataComponents.WRITABLE_BOOK_CONTENT,
|
|
+ // DataComponents.WRITTEN_BOOK_CONTENT,
|
|
+ // DataComponents.TRIM,
|
|
+ // DataComponents.DEBUG_STICK_STATE,
|
|
+ // DataComponents.ENTITY_DATA,
|
|
+ // DataComponents.BUCKET_ENTITY_DATA,
|
|
+ // DataComponents.BLOCK_ENTITY_DATA,
|
|
+ // DataComponents.INSTRUMENT,
|
|
+ // DataComponents.OMINOUS_BOTTLE_AMPLIFIER,
|
|
+ // DataComponents.RECIPES,
|
|
+ // DataComponents.LODESTONE_TRACKER,
|
|
+ // DataComponents.FIREWORK_EXPLOSION,
|
|
+ // DataComponents.FIREWORKS,
|
|
+ // DataComponents.PROFILE,
|
|
+ // DataComponents.NOTE_BLOCK_SOUND,
|
|
+ // DataComponents.BANNER_PATTERNS,
|
|
+ // DataComponents.BASE_COLOR,
|
|
+ // DataComponents.POT_DECORATIONS,
|
|
+ // DataComponents.CONTAINER,
|
|
+ // DataComponents.BEES,
|
|
+ // DataComponents.LOCK,
|
|
+ // DataComponents.CONTAINER_LOOT,
|
|
+ );
|
|
+ // Purpur end
|
|
private ItemStack removeNonCursesFrom(ItemStack item) {
|
|
ItemEnchantments itemenchantments = EnchantmentHelper.updateEnchantments(item, (itemenchantments_a) -> {
|
|
itemenchantments_a.removeIf((holder) -> {
|
|
- return !holder.is(EnchantmentTags.CURSE);
|
|
+ return !org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(holder.value()); // Purpur
|
|
});
|
|
});
|
|
|
|
@@ -248,6 +310,23 @@ public class GrindstoneMenu extends AbstractContainerMenu {
|
|
}
|
|
|
|
item.set(DataComponents.REPAIR_COST, i);
|
|
+
|
|
+ // Purpur start
|
|
+ net.minecraft.core.component.DataComponentPatch.Builder builder = net.minecraft.core.component.DataComponentPatch.builder();
|
|
+ if (org.purpurmc.purpur.PurpurConfig.grindstoneRemoveAttributes) {
|
|
+ item.getComponents().forEach(typedDataComponent -> {
|
|
+ if (GRINDSTONE_REMOVE_ATTRIBUTES_REMOVAL_LIST.contains(typedDataComponent.type())) {
|
|
+ builder.remove(typedDataComponent.type());
|
|
+ }
|
|
+ });
|
|
+ }
|
|
+ if (org.purpurmc.purpur.PurpurConfig.grindstoneRemoveDisplay) {
|
|
+ builder.remove(DataComponents.CUSTOM_NAME);
|
|
+ builder.remove(DataComponents.LORE);
|
|
+ }
|
|
+ item.applyComponents(builder.build());
|
|
+ // Purpur end
|
|
+
|
|
return item;
|
|
}
|
|
|
|
@@ -309,7 +388,9 @@ public class GrindstoneMenu extends AbstractContainerMenu {
|
|
return ItemStack.EMPTY;
|
|
}
|
|
|
|
+ this.activeQuickItem = itemstack; // Purpur
|
|
slot1.onTake(player, itemstack1);
|
|
+ this.activeQuickItem = null; // Purpur
|
|
}
|
|
|
|
return itemstack;
|
|
diff --git a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
|
|
index a5d53a656513ae81cc3f9fc506caf6adaba62a8e..ac9df238ef0f3d009f25976b95e0b750e963e952 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
|
|
@@ -164,7 +164,9 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu {
|
|
return ItemStack.EMPTY;
|
|
}
|
|
|
|
+ this.activeQuickItem = itemstack; // Purpur - Anvil API
|
|
slot1.onTake(player, itemstack1);
|
|
+ this.activeQuickItem = null; // Purpur - Anvil API
|
|
}
|
|
|
|
return itemstack;
|
|
diff --git a/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java b/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java
|
|
index a15d5ff872dbd77f3c3145e0328f3d02e431ff8c..1dcf36d502990d32fc4cd3ea69c3ea334baed69a 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java
|
|
@@ -31,11 +31,18 @@ public class PlayerEnderChestContainer extends SimpleContainer {
|
|
}
|
|
|
|
public PlayerEnderChestContainer(Player owner) {
|
|
- super(27);
|
|
+ super(org.purpurmc.purpur.PurpurConfig.enderChestSixRows ? 54 : 27); // Purpur
|
|
this.owner = owner;
|
|
// CraftBukkit end
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public int getContainerSize() {
|
|
+ return owner.sixRowEnderchestSlotCount < 0 ? super.getContainerSize() : owner.sixRowEnderchestSlotCount;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public void setActiveChest(EnderChestBlockEntity blockEntity) {
|
|
this.activeChest = blockEntity;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/item/ArmorStandItem.java b/src/main/java/net/minecraft/world/item/ArmorStandItem.java
|
|
index cb4baebe22eeab17aed67a5ecc506b932fe2230b..c1a6734cc08de1c9fc413b1fa81a199ac9547ec2 100644
|
|
--- a/src/main/java/net/minecraft/world/item/ArmorStandItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/ArmorStandItem.java
|
|
@@ -59,6 +59,14 @@ public class ArmorStandItem extends Item {
|
|
return InteractionResult.FAIL;
|
|
}
|
|
// CraftBukkit end
|
|
+ // Purpur start
|
|
+ if (!world.purpurConfig.persistentDroppableEntityDisplayNames) {
|
|
+ entityarmorstand.setCustomName(null);
|
|
+ }
|
|
+ if (world.purpurConfig.armorstandSetNameVisible && entityarmorstand.getCustomName() != null) {
|
|
+ entityarmorstand.setCustomNameVisible(true);
|
|
+ }
|
|
+ // Purpur end
|
|
worldserver.addFreshEntityWithPassengers(entityarmorstand);
|
|
world.playSound((Player) null, entityarmorstand.getX(), entityarmorstand.getY(), entityarmorstand.getZ(), SoundEvents.ARMOR_STAND_PLACE, SoundSource.BLOCKS, 0.75F, 0.8F);
|
|
entityarmorstand.gameEvent(GameEvent.ENTITY_PLACE, context.getPlayer());
|
|
diff --git a/src/main/java/net/minecraft/world/item/AxeItem.java b/src/main/java/net/minecraft/world/item/AxeItem.java
|
|
index abff08f2d61014944235ffe2f5494a718a28cc10..dc2c415ab227e1357533079ada4903e9f69d4f55 100644
|
|
--- a/src/main/java/net/minecraft/world/item/AxeItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/AxeItem.java
|
|
@@ -62,13 +62,15 @@ public class AxeItem extends DiggerItem {
|
|
if (playerHasShieldUseIntent(context)) {
|
|
return InteractionResult.PASS;
|
|
} else {
|
|
- Optional<BlockState> optional = this.evaluateNewBlockState(level, blockPos, player, level.getBlockState(blockPos));
|
|
+ Optional<org.purpurmc.purpur.tool.Actionable> optional = this.evaluateActionable(level, blockPos, player, level.getBlockState(blockPos)); // Purpur
|
|
if (optional.isEmpty()) {
|
|
return InteractionResult.PASS;
|
|
} else {
|
|
+ org.purpurmc.purpur.tool.Actionable actionable = optional.get(); // Purpur
|
|
+ BlockState state = actionable.into().withPropertiesOf(level.getBlockState(blockPos)); // Purpur
|
|
ItemStack itemStack = context.getItemInHand();
|
|
// Paper start - EntityChangeBlockEvent
|
|
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, optional.get())) {
|
|
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, state)) { // Purpur
|
|
return InteractionResult.PASS;
|
|
}
|
|
// Paper end
|
|
@@ -76,8 +78,15 @@ public class AxeItem extends DiggerItem {
|
|
CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, blockPos, itemStack);
|
|
}
|
|
|
|
- level.setBlock(blockPos, optional.get(), 11);
|
|
- level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(player, optional.get()));
|
|
+ // Purpur start
|
|
+ level.setBlock(blockPos, state, 11);
|
|
+ actionable.drops().forEach((drop, chance) -> {
|
|
+ if (level.random.nextDouble() < chance) {
|
|
+ Block.popResourceFromFace(level, blockPos, context.getClickedFace(), new ItemStack(drop));
|
|
+ }
|
|
+ });
|
|
+ level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(player, state));
|
|
+ // Purpur end
|
|
if (player != null) {
|
|
itemStack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(context.getHand()));
|
|
}
|
|
@@ -92,22 +101,24 @@ public class AxeItem extends DiggerItem {
|
|
return context.getHand().equals(InteractionHand.MAIN_HAND) && player.getOffhandItem().is(Items.SHIELD) && !player.isSecondaryUseActive();
|
|
}
|
|
|
|
- private Optional<BlockState> evaluateNewBlockState(Level world, BlockPos pos, @Nullable Player player, BlockState state) {
|
|
- Optional<BlockState> optional = this.getStripped(state);
|
|
+ private Optional<org.purpurmc.purpur.tool.Actionable> evaluateActionable(Level world, BlockPos pos, @Nullable Player player, BlockState state) { // Purpur
|
|
+ Optional<org.purpurmc.purpur.tool.Actionable> optional = Optional.ofNullable(world.purpurConfig.axeStrippables.get(state.getBlock())); // Purpur
|
|
if (optional.isPresent()) {
|
|
- world.playSound(player, pos, SoundEvents.AXE_STRIP, SoundSource.BLOCKS, 1.0F, 1.0F);
|
|
+ world.playSound(STRIPPABLES.containsKey(state.getBlock()) ? player : null, pos, SoundEvents.AXE_STRIP, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - force sound
|
|
return optional;
|
|
} else {
|
|
- Optional<BlockState> optional2 = WeatheringCopper.getPrevious(state);
|
|
+ Optional<org.purpurmc.purpur.tool.Actionable> optional2 = Optional.ofNullable(world.purpurConfig.axeWeatherables.get(state.getBlock())); // Purpur
|
|
if (optional2.isPresent()) {
|
|
- world.playSound(player, pos, SoundEvents.AXE_SCRAPE, SoundSource.BLOCKS, 1.0F, 1.0F);
|
|
+ world.playSound(WeatheringCopper.getPrevious(state).isPresent() ? player : null, pos, SoundEvents.AXE_SCRAPE, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - force sound
|
|
world.levelEvent(player, 3005, pos, 0);
|
|
return optional2;
|
|
} else {
|
|
- Optional<BlockState> optional3 = Optional.ofNullable(HoneycombItem.WAX_OFF_BY_BLOCK.get().get(state.getBlock()))
|
|
- .map(block -> block.withPropertiesOf(state));
|
|
+ // Purpur start
|
|
+ Optional<org.purpurmc.purpur.tool.Actionable> optional3 = Optional.ofNullable(world.purpurConfig.axeWaxables.get(state.getBlock()));
|
|
+ // .map(block -> block.withPropertiesOf(state));
|
|
+ // Purpur end
|
|
if (optional3.isPresent()) {
|
|
- world.playSound(player, pos, SoundEvents.AXE_WAX_OFF, SoundSource.BLOCKS, 1.0F, 1.0F);
|
|
+ world.playSound(HoneycombItem.WAX_OFF_BY_BLOCK.get().containsKey(state.getBlock()) ? player : null, pos, SoundEvents.AXE_WAX_OFF, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - force sound
|
|
world.levelEvent(player, 3004, pos, 0);
|
|
return optional3;
|
|
} else {
|
|
diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java
|
|
index c816c935ecc74a811ffdffbe6ded73c06e92324a..d58619d1d63a03598b8740dd789d4b6f2c93f8d0 100644
|
|
--- a/src/main/java/net/minecraft/world/item/BlockItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/BlockItem.java
|
|
@@ -151,7 +151,16 @@ public class BlockItem extends Item {
|
|
}
|
|
|
|
protected boolean updateCustomBlockEntityTag(BlockPos pos, Level world, @Nullable Player player, ItemStack stack, BlockState state) {
|
|
- return BlockItem.updateCustomBlockEntityTag(world, player, pos, stack);
|
|
+ // Purpur start
|
|
+ boolean handled = updateCustomBlockEntityTag(world, player, pos, stack);
|
|
+ if (world.purpurConfig.persistentTileEntityLore) {
|
|
+ BlockEntity blockEntity1 = world.getBlockEntity(pos);
|
|
+ if (blockEntity1 != null) {
|
|
+ blockEntity1.setPersistentLore(stack.getOrDefault(DataComponents.LORE, net.minecraft.world.item.component.ItemLore.EMPTY));
|
|
+ }
|
|
+ }
|
|
+ return handled;
|
|
+ // Purpur end
|
|
}
|
|
|
|
@Nullable
|
|
@@ -213,6 +222,7 @@ public class BlockItem extends Item {
|
|
|
|
if (tileentity != null) {
|
|
if (!world.isClientSide && tileentity.onlyOpCanSetNbt() && (player == null || !(player.canUseGameMasterBlocks() || (player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.nbt.place"))))) { // Spigot - add permission
|
|
+ if (!(!world.isClientSide && world.purpurConfig.silkTouchEnabled && tileentity instanceof net.minecraft.world.level.block.entity.SpawnerBlockEntity && player.getBukkitEntity().hasPermission("purpur.drop.spawners")))
|
|
return false;
|
|
}
|
|
|
|
@@ -248,6 +258,7 @@ public class BlockItem extends Item {
|
|
ItemContainerContents itemcontainercontents = (ItemContainerContents) entity.getItem().set(DataComponents.CONTAINER, ItemContainerContents.EMPTY);
|
|
|
|
if (itemcontainercontents != null) {
|
|
+ if (entity.level().purpurConfig.shulkerBoxItemDropContentsWhenDestroyed && this.getBlock() instanceof ShulkerBoxBlock) // Purpur
|
|
ItemUtils.onContainerDestroyed(entity, itemcontainercontents.nonEmptyItemsCopy());
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/item/BoatItem.java b/src/main/java/net/minecraft/world/item/BoatItem.java
|
|
index e51ffd6c5047ee907a58f3029f0ea7fc66aedfa7..78d41d57df9cb61b295f1f54db1e1d62c13db701 100644
|
|
--- a/src/main/java/net/minecraft/world/item/BoatItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/BoatItem.java
|
|
@@ -71,6 +71,11 @@ public class BoatItem extends Item {
|
|
return InteractionResult.FAIL;
|
|
} else {
|
|
abstractboat.setYRot(user.getYRot());
|
|
+ // Purpur start
|
|
+ if (!world.purpurConfig.persistentDroppableEntityDisplayNames) {
|
|
+ abstractboat.setCustomName(null);
|
|
+ }
|
|
+ // Purpur end
|
|
if (!world.noCollision(abstractboat, abstractboat.getBoundingBox())) {
|
|
return InteractionResult.FAIL;
|
|
} else {
|
|
diff --git a/src/main/java/net/minecraft/world/item/BowItem.java b/src/main/java/net/minecraft/world/item/BowItem.java
|
|
index bb593209c95c9cf1f9c5d52d52fab4a33ddbabcf..58fa528e4b2589d362eb976afd6221cd94f2623c 100644
|
|
--- a/src/main/java/net/minecraft/world/item/BowItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/BowItem.java
|
|
@@ -28,6 +28,11 @@ public class BowItem extends ProjectileWeaponItem {
|
|
return false;
|
|
} else {
|
|
ItemStack itemStack = player.getProjectile(stack);
|
|
+ // Purpur start
|
|
+ if (world.purpurConfig.infinityWorksWithoutArrows && itemStack.isEmpty() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, stack) > 0) {
|
|
+ itemStack = new ItemStack(Items.ARROW);
|
|
+ }
|
|
+ // Purpur end
|
|
if (itemStack.isEmpty()) {
|
|
return false;
|
|
} else {
|
|
@@ -38,7 +43,7 @@ public class BowItem extends ProjectileWeaponItem {
|
|
} else {
|
|
List<ItemStack> list = draw(stack, itemStack, player);
|
|
if (world instanceof ServerLevel serverLevel && !list.isEmpty()) {
|
|
- this.shoot(serverLevel, player, player.getUsedItemHand(), stack, list, f * 3.0F, 1.0F, f == 1.0F, null);
|
|
+ this.shoot(serverLevel, player, player.getUsedItemHand(), stack, list, f * 3.0F, (float) world.purpurConfig.bowProjectileOffset, f == 1.0F, null); // Purpur
|
|
}
|
|
|
|
world.playSound(
|
|
@@ -89,7 +94,7 @@ public class BowItem extends ProjectileWeaponItem {
|
|
public InteractionResult use(Level world, Player user, InteractionHand hand) {
|
|
ItemStack itemStack = user.getItemInHand(hand);
|
|
boolean bl = !user.getProjectile(itemStack).isEmpty();
|
|
- if (!user.hasInfiniteMaterials() && !bl) {
|
|
+ if (!user.hasInfiniteMaterials() && !bl && !(world.purpurConfig.infinityWorksWithoutArrows && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, itemStack) > 0)) { // Purpur
|
|
return InteractionResult.FAIL;
|
|
} else {
|
|
user.startUsingItem(hand);
|
|
diff --git a/src/main/java/net/minecraft/world/item/BucketItem.java b/src/main/java/net/minecraft/world/item/BucketItem.java
|
|
index 3bddfb6f7412ab86e0c090d0cbc6cf254b3f891c..6aa8ee091d3a7d2826d08ab9a03f970ef71a81ea 100644
|
|
--- a/src/main/java/net/minecraft/world/item/BucketItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/BucketItem.java
|
|
@@ -196,7 +196,7 @@ public class BucketItem extends Item implements DispensibleContainerItem {
|
|
// CraftBukkit end
|
|
if (!flag2) {
|
|
return movingobjectpositionblock != null && this.emptyContents(entityhuman, world, movingobjectpositionblock.getBlockPos().relative(movingobjectpositionblock.getDirection()), (BlockHitResult) null, enumdirection, clicked, itemstack, enumhand); // CraftBukkit
|
|
- } else if (world.dimensionType().ultraWarm() && this.content.is(FluidTags.WATER)) {
|
|
+ } else if ((world.dimensionType().ultraWarm() || (world.isTheEnd() && !org.purpurmc.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) && this.content.is(FluidTags.WATER)) { // Purpur
|
|
int i = blockposition.getX();
|
|
int j = blockposition.getY();
|
|
int k = blockposition.getZ();
|
|
@@ -204,7 +204,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/item/CrossbowItem.java b/src/main/java/net/minecraft/world/item/CrossbowItem.java
|
|
index 52c40eafc77e50a6fd21b9a7a250cea501f11690..86204c2ab5bbd5d45ddb1d626f844d91ccae6b4f 100644
|
|
--- a/src/main/java/net/minecraft/world/item/CrossbowItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/CrossbowItem.java
|
|
@@ -69,7 +69,7 @@ public class CrossbowItem extends ProjectileWeaponItem {
|
|
ItemStack itemStack = user.getItemInHand(hand);
|
|
ChargedProjectiles chargedProjectiles = itemStack.get(DataComponents.CHARGED_PROJECTILES);
|
|
if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) {
|
|
- this.performShooting(world, user, hand, itemStack, getShootingPower(chargedProjectiles), 1.0F, null);
|
|
+ this.performShooting(world, user, hand, itemStack, getShootingPower(chargedProjectiles), (float) world.purpurConfig.crossbowProjectileOffset, null); // Purpur
|
|
return InteractionResult.CONSUME;
|
|
} else if (!user.getProjectile(itemStack).isEmpty()) {
|
|
this.startSoundPlayed = false;
|
|
diff --git a/src/main/java/net/minecraft/world/item/DyeColor.java b/src/main/java/net/minecraft/world/item/DyeColor.java
|
|
index 79dc7cf5bfe92b4df21d164f39726dfe618331e4..6721432f9cdd11c9658c34f0ac407be217f9d276 100644
|
|
--- a/src/main/java/net/minecraft/world/item/DyeColor.java
|
|
+++ b/src/main/java/net/minecraft/world/item/DyeColor.java
|
|
@@ -103,4 +103,10 @@ public enum DyeColor implements StringRepresentable {
|
|
public String getSerializedName() {
|
|
return this.name;
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ public static DyeColor random(net.minecraft.util.RandomSource random) {
|
|
+ return values()[random.nextInt(values().length)];
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/item/EggItem.java b/src/main/java/net/minecraft/world/item/EggItem.java
|
|
index 3ddd34e5d05fa1355a2affd329d72dea216cd0e4..770bdb3fb2426083ff6785f1c38ffe9d11f898e5 100644
|
|
--- a/src/main/java/net/minecraft/world/item/EggItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/EggItem.java
|
|
@@ -27,7 +27,7 @@ public class EggItem extends Item implements ProjectileItem {
|
|
if (world instanceof ServerLevel worldserver) {
|
|
// CraftBukkit start
|
|
// Paper start - PlayerLaunchProjectileEvent
|
|
- final Projectile.Delayed<ThrownEgg> thrownEgg = Projectile.spawnProjectileFromRotationDelayed(ThrownEgg::new, worldserver, itemstack, user, 0.0F, 1.5F, 1.0F);
|
|
+ final Projectile.Delayed<ThrownEgg> thrownEgg = Projectile.spawnProjectileFromRotationDelayed(ThrownEgg::new, worldserver, itemstack, user, 0.0F, 1.5F, (float) worldserver.purpurConfig.eggProjectileOffset); // Purpur
|
|
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) thrownEgg.projectile().getBukkitEntity());
|
|
if (event.callEvent() && thrownEgg.attemptSpawn()) {
|
|
if (event.shouldConsume()) {
|
|
diff --git a/src/main/java/net/minecraft/world/item/EndCrystalItem.java b/src/main/java/net/minecraft/world/item/EndCrystalItem.java
|
|
index b62db8c7c8c57e43869ee239ebf4b02f112355d9..f60e39e56a5dab2de62ae9cfd7a30a70b4985c09 100644
|
|
--- a/src/main/java/net/minecraft/world/item/EndCrystalItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/EndCrystalItem.java
|
|
@@ -27,7 +27,7 @@ public class EndCrystalItem extends Item {
|
|
BlockPos blockposition = context.getClickedPos();
|
|
BlockState iblockdata = world.getBlockState(blockposition);
|
|
|
|
- if (!iblockdata.is(Blocks.OBSIDIAN) && !iblockdata.is(Blocks.BEDROCK)) {
|
|
+ if (!world.purpurConfig.endCrystalPlaceAnywhere && !iblockdata.is(Blocks.OBSIDIAN) && !iblockdata.is(Blocks.BEDROCK)) {
|
|
return InteractionResult.FAIL;
|
|
} else {
|
|
BlockPos blockposition1 = blockposition.above(); final BlockPos aboveBlockPosition = blockposition1; // Paper - OBFHELPER
|
|
diff --git a/src/main/java/net/minecraft/world/item/EnderpearlItem.java b/src/main/java/net/minecraft/world/item/EnderpearlItem.java
|
|
index b232390d8ee8e449e61c0ea7f3af60df507abb97..4039d300debadf29e6c544e8b4c950b7121a02d1 100644
|
|
--- a/src/main/java/net/minecraft/world/item/EnderpearlItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/EnderpearlItem.java
|
|
@@ -24,7 +24,7 @@ public class EnderpearlItem extends Item {
|
|
if (world instanceof ServerLevel worldserver) {
|
|
// CraftBukkit start
|
|
// Paper start - PlayerLaunchProjectileEvent
|
|
- final Projectile.Delayed<ThrownEnderpearl> thrownEnderpearl = Projectile.spawnProjectileFromRotationDelayed(ThrownEnderpearl::new, worldserver, itemstack, user, 0.0F, 1.5F, 1.0F);
|
|
+ final Projectile.Delayed<ThrownEnderpearl> thrownEnderpearl = Projectile.spawnProjectileFromRotationDelayed(ThrownEnderpearl::new, worldserver, itemstack, user, 0.0F, 1.5F, (float) worldserver.purpurConfig.enderPearlProjectileOffset); // Purpur
|
|
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) thrownEnderpearl.projectile().getBukkitEntity());
|
|
if (event.callEvent() && thrownEnderpearl.attemptSpawn()) {
|
|
if (event.shouldConsume()) {
|
|
@@ -35,6 +35,7 @@ public class EnderpearlItem extends Item {
|
|
|
|
world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.ENDER_PEARL_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
|
user.awardStat(Stats.ITEM_USED.get(this));
|
|
+ user.getCooldowns().addCooldown(itemstack, user.getAbilities().instabuild ? world.purpurConfig.enderPearlCooldownCreative : world.purpurConfig.enderPearlCooldown); // Purpur
|
|
} else {
|
|
// Paper end - PlayerLaunchProjectileEvent
|
|
if (user instanceof net.minecraft.server.level.ServerPlayer) {
|
|
diff --git a/src/main/java/net/minecraft/world/item/FireworkRocketItem.java b/src/main/java/net/minecraft/world/item/FireworkRocketItem.java
|
|
index 7e308b364227dedc2d05496f5e0c90573f4a53f7..52e0a741e0a2274d3d70e8d8cdfa56f5e934deb2 100644
|
|
--- a/src/main/java/net/minecraft/world/item/FireworkRocketItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/FireworkRocketItem.java
|
|
@@ -66,6 +66,18 @@ public class FireworkRocketItem extends Item implements ProjectileItem {
|
|
com.destroystokyo.paper.event.player.PlayerElytraBoostEvent event = new com.destroystokyo.paper.event.player.PlayerElytraBoostEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Firework) delayed.projectile().getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand));
|
|
if (event.callEvent() && delayed.attemptSpawn()) {
|
|
user.awardStat(Stats.ITEM_USED.get(this)); // Moved up from below
|
|
+
|
|
+ // Purpur start
|
|
+ if (world.purpurConfig.elytraDamagePerFireworkBoost > 0) {
|
|
+ List<net.minecraft.world.entity.EquipmentSlot> list = net.minecraft.world.entity.EquipmentSlot.VALUES.stream().filter((enumitemslot) -> net.minecraft.world.entity.LivingEntity.canGlideUsing(user.getItemBySlot(enumitemslot), enumitemslot)).toList();
|
|
+ net.minecraft.world.entity.EquipmentSlot enumitemslot = net.minecraft.Util.getRandom(list, user.random);
|
|
+
|
|
+ ItemStack glideItem = user.getItemBySlot(enumitemslot);
|
|
+ if (user.canGlide()) {
|
|
+ glideItem.hurtAndBreak(world.purpurConfig.elytraDamagePerFireworkBoost, user, enumitemslot);
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
if (event.shouldConsume() && !user.hasInfiniteMaterials()) {
|
|
itemStack.shrink(1); // Moved up from below
|
|
} else ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory();
|
|
diff --git a/src/main/java/net/minecraft/world/item/HangingEntityItem.java b/src/main/java/net/minecraft/world/item/HangingEntityItem.java
|
|
index cdc17ad948d8ac5de62f14b1a561433d33211f32..44a7cee7df2927a923455e8cedaab59307b42506 100644
|
|
--- a/src/main/java/net/minecraft/world/item/HangingEntityItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/HangingEntityItem.java
|
|
@@ -75,6 +75,11 @@ public class HangingEntityItem extends Item {
|
|
|
|
if (!customdata.isEmpty()) {
|
|
EntityType.updateCustomEntityTag(world, entityhuman, (Entity) object, customdata);
|
|
+ // Purpur start
|
|
+ if (!world.purpurConfig.persistentDroppableEntityDisplayNames) {
|
|
+ ((Entity) object).setCustomName(null);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
|
|
if (((HangingEntity) object).survives()) {
|
|
diff --git a/src/main/java/net/minecraft/world/item/HoeItem.java b/src/main/java/net/minecraft/world/item/HoeItem.java
|
|
index d2871bb4fd670ae4133d13f290b3256c9177d8e6..0936bdc945f73c7750c20a34276aead2921eeb61 100644
|
|
--- a/src/main/java/net/minecraft/world/item/HoeItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/HoeItem.java
|
|
@@ -46,15 +46,23 @@ public class HoeItem extends DiggerItem {
|
|
public InteractionResult useOn(UseOnContext context) {
|
|
Level level = context.getLevel();
|
|
BlockPos blockPos = context.getClickedPos();
|
|
- Pair<Predicate<UseOnContext>, Consumer<UseOnContext>> pair = TILLABLES.get(level.getBlockState(blockPos).getBlock());
|
|
- if (pair == null) {
|
|
- return InteractionResult.PASS;
|
|
- } else {
|
|
- Predicate<UseOnContext> predicate = pair.getFirst();
|
|
- Consumer<UseOnContext> consumer = pair.getSecond();
|
|
+ // Purpur start
|
|
+ Block clickedBlock = level.getBlockState(blockPos).getBlock();
|
|
+ var tillable = level.purpurConfig.hoeTillables.get(clickedBlock);
|
|
+ if (tillable == null) { return InteractionResult.PASS; } else {
|
|
+ Predicate<UseOnContext> predicate = tillable.condition().predicate();
|
|
+ Consumer<UseOnContext> consumer = (ctx) -> {
|
|
+ level.setBlock(blockPos, tillable.into().defaultBlockState(), 11);
|
|
+ tillable.drops().forEach((drop, chance) -> {
|
|
+ if (level.random.nextDouble() < chance) {
|
|
+ Block.popResourceFromFace(level, blockPos, ctx.getClickedFace(), new ItemStack(drop));
|
|
+ }
|
|
+ });
|
|
+ };
|
|
+ // Purpur end
|
|
if (predicate.test(context)) {
|
|
Player player = context.getPlayer();
|
|
- level.playSound(player, blockPos, SoundEvents.HOE_TILL, SoundSource.BLOCKS, 1.0F, 1.0F);
|
|
+ if (!TILLABLES.containsKey(clickedBlock)) level.playSound(null, blockPos, SoundEvents.HOE_TILL, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - force sound
|
|
if (!level.isClientSide) {
|
|
consumer.accept(context);
|
|
if (player != null) {
|
|
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
|
|
index 33e7d2884195677c4d6340d8b84c1dd85c636ec1..42b259c3878bd34b8e7cb768887fd1456be8db35 100644
|
|
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
|
|
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
|
|
@@ -503,6 +503,7 @@ public final class ItemStack implements DataComponentHolder {
|
|
world.isBlockPlaceCancelled = true; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent
|
|
for (BlockState blockstate : blocks) {
|
|
blockstate.update(true, false);
|
|
+ ((CraftBlock) blockstate.getBlock()).getNMS().getBlock().forgetPlacer(); // Purpur
|
|
}
|
|
world.isBlockPlaceCancelled = false; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent
|
|
world.preventPoiUpdated = false;
|
|
@@ -535,6 +536,7 @@ public final class ItemStack implements DataComponentHolder {
|
|
if (!(block.getBlock() instanceof BaseEntityBlock)) { // Containers get placed automatically
|
|
block.onPlace(world, newblockposition, oldBlock, true, context);
|
|
}
|
|
+ block.getBlock().forgetPlacer(); // Purpur
|
|
|
|
world.notifyAndUpdatePhysics(newblockposition, null, oldBlock, block, world.getBlockState(newblockposition), updateFlag, 512); // send null chunk as chunk.k() returns false by this point
|
|
}
|
|
@@ -681,6 +683,26 @@ public final class ItemStack implements DataComponentHolder {
|
|
return this.isDamageableItem() && this.getDamageValue() > 0;
|
|
}
|
|
|
|
+ // Purpur start - Add option to mend the most damaged equipment first
|
|
+ public float getDamagePercent() {
|
|
+ if (this.has(DataComponents.UNBREAKABLE)) {
|
|
+ return 0.0F;
|
|
+ }
|
|
+
|
|
+ final int maxDamage = this.getOrDefault(DataComponents.MAX_DAMAGE, 0);
|
|
+ if (maxDamage == 0) {
|
|
+ return 0.0F;
|
|
+ }
|
|
+
|
|
+ final int damage = this.getOrDefault(DataComponents.DAMAGE, 0);
|
|
+ if (damage == 0) {
|
|
+ return 0.0F;
|
|
+ }
|
|
+
|
|
+ return (float) damage / maxDamage;
|
|
+ }
|
|
+ // Purpur end - Add option to mend the most damaged equipment first
|
|
+
|
|
public int getDamageValue() {
|
|
return Mth.clamp((Integer) this.getOrDefault(DataComponents.DAMAGE, 0), 0, this.getMaxDamage());
|
|
}
|
|
@@ -761,6 +783,12 @@ public final class ItemStack implements DataComponentHolder {
|
|
org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent(serverPlayer, this); // Paper - Add EntityDamageItemEvent
|
|
}
|
|
// CraftBukkit end
|
|
+ // Purpur start
|
|
+ if (this.has(DataComponents.GLIDER)) {
|
|
+ setDamageValue(this.getMaxDamage() - 1);
|
|
+ return;
|
|
+ }
|
|
+ // Purpur end
|
|
|
|
this.shrink(1);
|
|
breakCallback.accept(item);
|
|
@@ -1325,6 +1353,12 @@ public final class ItemStack implements DataComponentHolder {
|
|
return !((ItemEnchantments) this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY)).isEmpty();
|
|
}
|
|
|
|
+ // Purpur start - Config to allow unsafe enchants
|
|
+ public boolean hasEnchantment(Holder<Enchantment> enchantment) {
|
|
+ return this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY).getLevel(enchantment) > 0;
|
|
+ }
|
|
+ // Purpur end - Config to allow unsafe enchants
|
|
+
|
|
public ItemEnchantments getEnchantments() {
|
|
return (ItemEnchantments) this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/item/Items.java b/src/main/java/net/minecraft/world/item/Items.java
|
|
index 5a70111cd39af50981cfd440c021340da1de5eab..580bd63fdbf9555f867362d3c1f39f41fd750089 100644
|
|
--- a/src/main/java/net/minecraft/world/item/Items.java
|
|
+++ b/src/main/java/net/minecraft/world/item/Items.java
|
|
@@ -363,7 +363,7 @@ public class Items {
|
|
public static final Item PURPUR_BLOCK = registerBlock(Blocks.PURPUR_BLOCK);
|
|
public static final Item PURPUR_PILLAR = registerBlock(Blocks.PURPUR_PILLAR);
|
|
public static final Item PURPUR_STAIRS = registerBlock(Blocks.PURPUR_STAIRS);
|
|
- public static final Item SPAWNER = registerBlock(Blocks.SPAWNER);
|
|
+ public static final Item SPAWNER = registerBlock(Blocks.SPAWNER, org.purpurmc.purpur.item.SpawnerItem::new, new Item.Properties().rarity(Rarity.EPIC)); // Purpur
|
|
public static final Item CREAKING_HEART = registerBlock(Blocks.CREAKING_HEART);
|
|
public static final Item CHEST = registerBlock(Blocks.CHEST, settings -> settings.component(DataComponents.CONTAINER, ItemContainerContents.EMPTY));
|
|
public static final Item CRAFTING_TABLE = registerBlock(Blocks.CRAFTING_TABLE);
|
|
@@ -2104,7 +2104,7 @@ public class Items {
|
|
"sweet_berries", createBlockItemWithCustomItemName(Blocks.SWEET_BERRY_BUSH), new Item.Properties().food(Foods.SWEET_BERRIES)
|
|
);
|
|
public static final Item GLOW_BERRIES = registerItem(
|
|
- "glow_berries", createBlockItemWithCustomItemName(Blocks.CAVE_VINES), new Item.Properties().food(Foods.GLOW_BERRIES)
|
|
+ "glow_berries", settings -> new org.purpurmc.purpur.item.GlowBerryItem(Blocks.CAVE_VINES, settings.useItemDescriptionPrefix()), new Item.Properties().food(Foods.GLOW_BERRIES) // Purpur
|
|
);
|
|
public static final Item CAMPFIRE = registerBlock(Blocks.CAMPFIRE, settings -> settings.component(DataComponents.CONTAINER, ItemContainerContents.EMPTY));
|
|
public static final Item SOUL_CAMPFIRE = registerBlock(
|
|
diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java
|
|
index 571f2540a1e9422025efe651167e26b44b437daa..c2f3c8b3d8eeb609b6d6067c4fb404aefbf94ec5 100644
|
|
--- a/src/main/java/net/minecraft/world/item/MapItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/MapItem.java
|
|
@@ -194,6 +194,7 @@ public class MapItem extends Item {
|
|
public static void renderBiomePreviewMap(ServerLevel world, ItemStack map) {
|
|
MapItemSavedData mapItemSavedData = getSavedData(map, world);
|
|
if (mapItemSavedData != null) {
|
|
+ mapItemSavedData.isExplorerMap = true; // Purpur
|
|
if (world.dimension() == mapItemSavedData.dimension) {
|
|
int i = 1 << mapItemSavedData.scale;
|
|
int j = mapItemSavedData.centerX;
|
|
diff --git a/src/main/java/net/minecraft/world/item/MinecartItem.java b/src/main/java/net/minecraft/world/item/MinecartItem.java
|
|
index 7153d9ed12276a0f2d8b8a17c79734aa25ed1fa5..dc49ea6454e04ae8ec68af12c4bf2ff022540671 100644
|
|
--- a/src/main/java/net/minecraft/world/item/MinecartItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/MinecartItem.java
|
|
@@ -35,8 +35,9 @@ public class MinecartItem extends Item {
|
|
BlockState iblockdata = world.getBlockState(blockposition);
|
|
|
|
if (!iblockdata.is(BlockTags.RAILS)) {
|
|
- return InteractionResult.FAIL;
|
|
- } else {
|
|
+ if (!world.purpurConfig.minecartPlaceAnywhere) return InteractionResult.FAIL; // Purpur
|
|
+ if (iblockdata.isSolid()) blockposition = blockposition.relative(context.getClickedFace());
|
|
+ } // else { // Purpur - place minecarts anywhere
|
|
ItemStack itemstack = context.getItemInHand();
|
|
RailShape blockpropertytrackposition = iblockdata.getBlock() instanceof BaseRailBlock ? (RailShape) iblockdata.getValue(((BaseRailBlock) iblockdata.getBlock()).getShapeProperty()) : RailShape.NORTH_SOUTH;
|
|
double d0 = 0.0D;
|
|
@@ -80,6 +81,6 @@ public class MinecartItem extends Item {
|
|
itemstack.shrink(1);
|
|
return InteractionResult.SUCCESS;
|
|
}
|
|
- }
|
|
+ // } // Purpur - place minecarts anywhere
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/item/NameTagItem.java b/src/main/java/net/minecraft/world/item/NameTagItem.java
|
|
index 000d1863bfba98b5132dfc6743362d687b2f54f3..20fece9908382f40b4082f7b1fb7d41914ae31be 100644
|
|
--- a/src/main/java/net/minecraft/world/item/NameTagItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/NameTagItem.java
|
|
@@ -23,6 +23,7 @@ public class NameTagItem extends Item {
|
|
if (!event.callEvent()) return InteractionResult.PASS;
|
|
LivingEntity newEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getEntity()).getHandle();
|
|
newEntity.setCustomName(event.getName() != null ? io.papermc.paper.adventure.PaperAdventure.asVanilla(event.getName()) : null);
|
|
+ if (user.level().purpurConfig.armorstandFixNametags && entity instanceof net.minecraft.world.entity.decoration.ArmorStand) entity.setCustomNameVisible(true); // Purpur
|
|
if (event.isPersistent() && newEntity instanceof Mob mob) {
|
|
// Paper end - Add PlayerNameEntityEvent
|
|
mob.setPersistenceRequired();
|
|
diff --git a/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java b/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java
|
|
index 78ba170a83f8c026bd110eae494c52577182ed61..c2ae50872cead7202246b9cce4db6e0a81e1cf5f 100644
|
|
--- a/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java
|
|
@@ -105,6 +105,8 @@ public abstract class ProjectileWeaponItem extends Item {
|
|
entityarrow.setCritArrow(true);
|
|
}
|
|
|
|
+ entityarrow.setActualEnchantments(weaponStack.getEnchantments()); // Purpur - Add an option to fix MC-3304 projectile looting
|
|
+
|
|
return entityarrow;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/item/ShovelItem.java b/src/main/java/net/minecraft/world/item/ShovelItem.java
|
|
index 55c18f182166f4905d623d6f5e909eefd5ed2483..d10c4705cc9e7faabd4a5619e1da107231bdb37e 100644
|
|
--- a/src/main/java/net/minecraft/world/item/ShovelItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/ShovelItem.java
|
|
@@ -47,9 +47,12 @@ public class ShovelItem extends DiggerItem {
|
|
BlockState blockState2 = FLATTENABLES.get(blockState.getBlock());
|
|
BlockState blockState3 = null;
|
|
Runnable afterAction = null; // Paper
|
|
- if (blockState2 != null && level.getBlockState(blockPos.above()).isAir()) {
|
|
- afterAction = () -> level.playSound(player, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper
|
|
- blockState3 = blockState2;
|
|
+ // Purpur start
|
|
+ var flattenable = level.purpurConfig.shovelFlattenables.get(blockState.getBlock());
|
|
+ if (flattenable != null && level.getBlockState(blockPos.above()).isAir()) {
|
|
+ afterAction = () -> {if (!FLATTENABLES.containsKey(blockState.getBlock())) level.playSound(null, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F);}; // Paper
|
|
+ blockState3 = flattenable.into().defaultBlockState();
|
|
+ // Purpur end
|
|
} else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) {
|
|
afterAction = () -> { // Paper
|
|
if (!level.isClientSide()) {
|
|
diff --git a/src/main/java/net/minecraft/world/item/SnowballItem.java b/src/main/java/net/minecraft/world/item/SnowballItem.java
|
|
index 57872ebef6beb8cdc03c9f8f19de94652ee19062..60a064c26de0566aaf9f8be886402e291c03ca3b 100644
|
|
--- a/src/main/java/net/minecraft/world/item/SnowballItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/SnowballItem.java
|
|
@@ -27,7 +27,7 @@ public class SnowballItem extends Item implements ProjectileItem {
|
|
// world.playSound((EntityHuman) null, entityhuman.getX(), entityhuman.getY(), entityhuman.getZ(), SoundEffects.SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
|
|
if (world instanceof ServerLevel worldserver) {
|
|
// Paper start - PlayerLaunchProjectileEvent
|
|
- final Projectile.Delayed<Snowball> snowball = Projectile.spawnProjectileFromRotationDelayed(Snowball::new, worldserver, itemstack, user, 0.0F, 1.5F, 1.0F);
|
|
+ final Projectile.Delayed<Snowball> snowball = Projectile.spawnProjectileFromRotationDelayed(Snowball::new, worldserver, itemstack, user, 0.0F, 1.5F, (float) worldserver.purpurConfig.snowballProjectileOffset); // Purpur
|
|
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) snowball.projectile().getBukkitEntity());
|
|
if (event.callEvent() && snowball.attemptSpawn()) {
|
|
user.awardStat(Stats.ITEM_USED.get(this));
|
|
diff --git a/src/main/java/net/minecraft/world/item/SpawnEggItem.java b/src/main/java/net/minecraft/world/item/SpawnEggItem.java
|
|
index 9956ed42df55daa6d97fd6e3ab5368dad91cfaf0..e0e746d6c78421b40777125ba49f0a04809f5415 100644
|
|
--- a/src/main/java/net/minecraft/world/item/SpawnEggItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/SpawnEggItem.java
|
|
@@ -73,6 +73,24 @@ public class SpawnEggItem extends Item {
|
|
Spawner spawner = (Spawner) tileentity;
|
|
|
|
entitytypes = this.getType(itemstack);
|
|
+
|
|
+ // Purpur start
|
|
+ if (spawner instanceof net.minecraft.world.level.block.entity.SpawnerBlockEntity) {
|
|
+ org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());
|
|
+ org.purpurmc.purpur.event.PlayerSetSpawnerTypeWithEggEvent event = new org.purpurmc.purpur.event.PlayerSetSpawnerTypeWithEggEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), bukkitBlock, (org.bukkit.block.CreatureSpawner) bukkitBlock.getState(), org.bukkit.entity.EntityType.fromName(entitytypes.getName()));
|
|
+ if (!event.callEvent()) {
|
|
+ return InteractionResult.FAIL;
|
|
+ }
|
|
+ entitytypes = EntityType.getFromBukkitType(event.getEntityType());
|
|
+ } else if (spawner instanceof net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity) {
|
|
+ org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());
|
|
+ org.purpurmc.purpur.event.PlayerSetTrialSpawnerTypeWithEggEvent event = new org.purpurmc.purpur.event.PlayerSetTrialSpawnerTypeWithEggEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), bukkitBlock, (org.bukkit.block.TrialSpawner) bukkitBlock.getState(), org.bukkit.entity.EntityType.fromName(entitytypes.getName()));
|
|
+ if (!event.callEvent()) {
|
|
+ return InteractionResult.FAIL;
|
|
+ }
|
|
+ entitytypes = EntityType.getFromBukkitType(event.getEntityType());
|
|
+ }
|
|
+ // Purpur end
|
|
spawner.setEntityId(entitytypes, world.getRandom());
|
|
world.sendBlockUpdated(blockposition, iblockdata, iblockdata, 3);
|
|
world.gameEvent((Entity) context.getPlayer(), (Holder) GameEvent.BLOCK_CHANGE, blockposition);
|
|
diff --git a/src/main/java/net/minecraft/world/item/ThrowablePotionItem.java b/src/main/java/net/minecraft/world/item/ThrowablePotionItem.java
|
|
index fa9d2ae44fcdd06f8f33cd14ffca422b20a01451..ffbc71ca2a27800d7758e3db339bf06a39ef1f11 100644
|
|
--- a/src/main/java/net/minecraft/world/item/ThrowablePotionItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/ThrowablePotionItem.java
|
|
@@ -21,7 +21,7 @@ public class ThrowablePotionItem extends PotionItem implements ProjectileItem {
|
|
ItemStack itemStack = user.getItemInHand(hand);
|
|
if (world instanceof ServerLevel serverLevel) {
|
|
// Paper start - PlayerLaunchProjectileEvent
|
|
- final Projectile.Delayed<ThrownPotion> thrownPotion = Projectile.spawnProjectileFromRotationDelayed(ThrownPotion::new, serverLevel, itemStack, user, -20.0F, 0.5F, 1.0F);
|
|
+ final Projectile.Delayed<ThrownPotion> thrownPotion = Projectile.spawnProjectileFromRotationDelayed(ThrownPotion::new, serverLevel, itemStack, user, -20.0F, 0.5F, (float) serverLevel.purpurConfig.throwablePotionProjectileOffset); // Purpur
|
|
// Paper start - PlayerLaunchProjectileEvent
|
|
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) thrownPotion.projectile().getBukkitEntity());
|
|
if (event.callEvent() && thrownPotion.attemptSpawn()) {
|
|
diff --git a/src/main/java/net/minecraft/world/item/TridentItem.java b/src/main/java/net/minecraft/world/item/TridentItem.java
|
|
index 8b9a93ef71164cce8a616735b71d96d37e83b1a8..d7eb680b977656556a618431b1511c1050f6db5e 100644
|
|
--- a/src/main/java/net/minecraft/world/item/TridentItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/TridentItem.java
|
|
@@ -88,7 +88,7 @@ public class TridentItem extends Item implements ProjectileItem {
|
|
// itemstack.hurtWithoutBreaking(1, entityhuman); // CraftBukkit - moved down
|
|
if (f == 0.0F) {
|
|
// Paper start - PlayerLaunchProjectileEvent
|
|
- Projectile.Delayed<ThrownTrident> tridentDelayed = Projectile.spawnProjectileFromRotationDelayed(ThrownTrident::new, worldserver, stack, entityhuman, 0.0F, 2.5F, 1.0F);
|
|
+ Projectile.Delayed<ThrownTrident> tridentDelayed = Projectile.spawnProjectileFromRotationDelayed(ThrownTrident::new, worldserver, stack, entityhuman, 0.0F, 2.5F, (float) worldserver.purpurConfig.tridentProjectileOffset); // Purpur
|
|
// Paper start - PlayerLaunchProjectileEvent
|
|
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), (org.bukkit.entity.Projectile) tridentDelayed.projectile().getBukkitEntity());
|
|
if (!event.callEvent() || !tridentDelayed.attemptSpawn()) {
|
|
@@ -100,6 +100,9 @@ public class TridentItem extends Item implements ProjectileItem {
|
|
return false;
|
|
}
|
|
ThrownTrident entitythrowntrident = tridentDelayed.projectile(); // Paper - PlayerLaunchProjectileEvent
|
|
+
|
|
+ entitythrowntrident.setActualEnchantments(stack.getEnchantments()); // Purpur - Add an option to fix MC-3304 projectile looting
|
|
+
|
|
if (event.shouldConsume()) stack.hurtWithoutBreaking(1, entityhuman); // Paper - PlayerLaunchProjectileEvent
|
|
entitythrowntrident.pickupItemStack = stack.copy(); // SPIGOT-4511 update since damage call moved
|
|
// CraftBukkit end
|
|
@@ -132,6 +135,16 @@ public class TridentItem extends Item implements ProjectileItem {
|
|
f4 *= f / f6;
|
|
f5 *= f / f6;
|
|
org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRiptideEvent(entityhuman, stack, f3, f4, f5); // CraftBukkit
|
|
+
|
|
+ // Purpur start
|
|
+ List<EquipmentSlot> list = EquipmentSlot.VALUES.stream().filter((enumitemslot) -> LivingEntity.canGlideUsing(entityhuman.getItemBySlot(enumitemslot), enumitemslot)).toList();
|
|
+ EquipmentSlot enumitemslot = net.minecraft.Util.getRandom(list, entityhuman.random);
|
|
+ ItemStack glideItem = entityhuman.getItemBySlot(enumitemslot);
|
|
+ if (glideItem.has(net.minecraft.core.component.DataComponents.GLIDER) && world.purpurConfig.elytraDamagePerTridentBoost > 0) {
|
|
+ glideItem.hurtAndBreak(world.purpurConfig.elytraDamagePerTridentBoost, entityhuman, enumitemslot);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
entityhuman.push((double) f3, (double) f4, (double) f5);
|
|
entityhuman.startAutoSpinAttack(20, 8.0F, stack);
|
|
if (entityhuman.onGround()) {
|
|
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 f99b87cf70df7eaac13d46f4e0234b1e6483d342..73241113e50dc8be89ef8850d49d95ec31fb194f 100644
|
|
--- a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java
|
|
+++ b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java
|
|
@@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.List;
|
|
+import java.util.Map;
|
|
import java.util.Optional;
|
|
import java.util.function.BiConsumer;
|
|
import java.util.function.Consumer;
|
|
@@ -578,4 +579,58 @@ public class EnchantmentHelper {
|
|
interface EnchantmentVisitor {
|
|
void accept(Holder<Enchantment> enchantment, int level);
|
|
}
|
|
+
|
|
+ // Purpur start - Enchantment convenience methods
|
|
+ public static Holder.Reference<Enchantment> getEnchantmentHolder(ResourceKey<Enchantment> enchantment) {
|
|
+ return net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.ENCHANTMENT).getOrThrow(enchantment);
|
|
+ }
|
|
+
|
|
+ public static int getItemEnchantmentLevel(ResourceKey<Enchantment> enchantment, ItemStack stack) {
|
|
+ return getItemEnchantmentLevel(getEnchantmentHolder(enchantment), stack);
|
|
+ }
|
|
+ // Purpur end - Enchantment convenience methods
|
|
+
|
|
+ // Purpur start - Add option to mend the most damaged equipment first
|
|
+ public static Optional<EnchantedItemInUse> getMostDamagedItemWith(DataComponentType<?> componentType, LivingEntity entity) {
|
|
+ ItemStack maxStack = null;
|
|
+ EquipmentSlot maxSlot = null;
|
|
+ float maxPercent = 0.0F;
|
|
+
|
|
+ equipmentSlotLoop:
|
|
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.values()) {
|
|
+ ItemStack stack = entity.getItemBySlot(equipmentSlot);
|
|
+
|
|
+ // do not even check enchantments for item with lower or equal damage percent
|
|
+ float percent = stack.getDamagePercent();
|
|
+ if (percent <= maxPercent) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ ItemEnchantments itemEnchantments = stack.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY);
|
|
+
|
|
+ for (Entry<Holder<Enchantment>> entry : itemEnchantments.entrySet()) {
|
|
+ Enchantment enchantment = entry.getKey().value();
|
|
+
|
|
+ net.minecraft.core.component.DataComponentMap effects = enchantment.effects();
|
|
+ if (!effects.has(componentType)) {
|
|
+ // try with another enchantment
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (enchantment.matchingSlot(equipmentSlot)) {
|
|
+ maxStack = stack;
|
|
+ maxSlot = equipmentSlot;
|
|
+ maxPercent = percent;
|
|
+
|
|
+ // check another slot now
|
|
+ continue equipmentSlotLoop;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return maxStack != null
|
|
+ ? Optional.of(new EnchantedItemInUse(maxStack, maxSlot, entity))
|
|
+ : Optional.empty();
|
|
+ }
|
|
+ // Purpur end - Add option to mend the most damaged equipment first
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java b/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java
|
|
index cfc6a657cae92c68868a76c1b7b1febe2a16e9f4..a12c08da793139e39dc11c213c94796b83bd8240 100644
|
|
--- a/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java
|
|
+++ b/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java
|
|
@@ -35,7 +35,7 @@ public class ItemEnchantments implements TooltipProvider {
|
|
private static final java.util.Comparator<Holder<Enchantment>> ENCHANTMENT_ORDER = java.util.Comparator.comparing(Holder::getRegisteredName);
|
|
public static final ItemEnchantments EMPTY = new ItemEnchantments(new Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), true);
|
|
// Paper end
|
|
- private static final Codec<Integer> LEVEL_CODEC = Codec.intRange(1, 255);
|
|
+ private static final Codec<Integer> LEVEL_CODEC = Codec.intRange(1, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)); // Purpur
|
|
private static final Codec<Object2IntAVLTreeMap<Holder<Enchantment>>> LEVELS_CODEC = Codec.unboundedMap(
|
|
Enchantment.CODEC, LEVEL_CODEC
|
|
)// Paper start - sort enchantments
|
|
@@ -69,7 +69,7 @@ public class ItemEnchantments implements TooltipProvider {
|
|
|
|
for (Entry<Holder<Enchantment>> entry : enchantments.object2IntEntrySet()) {
|
|
int i = entry.getIntValue();
|
|
- if (i < 0 || i > 255) {
|
|
+ if (i < 0 || i > (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)) { // Purpur
|
|
throw new IllegalArgumentException("Enchantment " + entry.getKey() + " has invalid level " + i);
|
|
}
|
|
}
|
|
@@ -164,13 +164,13 @@ public class ItemEnchantments implements TooltipProvider {
|
|
if (level <= 0) {
|
|
this.enchantments.removeInt(enchantment);
|
|
} else {
|
|
- this.enchantments.put(enchantment, Math.min(level, 255));
|
|
+ this.enchantments.put(enchantment, Math.min(level, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767))); // Purpur
|
|
}
|
|
}
|
|
|
|
public void upgrade(Holder<Enchantment> enchantment, int level) {
|
|
if (level > 0) {
|
|
- this.enchantments.merge(enchantment, Math.min(level, 255), Integer::max);
|
|
+ this.enchantments.merge(enchantment, Math.min(level, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)), Integer::max); // Purpur
|
|
}
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
|
index 0efc8d997b34302c3e0a5d7ec73a11a940dbeefe..af157881d440b34cfe79fbc9b03cc9ef28515eb8 100644
|
|
--- a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
|
+++ b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
|
@@ -131,7 +131,12 @@ public class MerchantOffer {
|
|
}
|
|
|
|
public void updateDemand() {
|
|
- this.demand = Math.max(0, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962
|
|
+ // Purpur start
|
|
+ this.updateDemand(0);
|
|
+ }
|
|
+ public void updateDemand(int minimumDemand) {
|
|
+ this.demand = Math.max(minimumDemand, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962
|
|
+ // Purpur end
|
|
}
|
|
|
|
public ItemStack assemble() {
|
|
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
|
index 7de66aa435dd36899b80f4ecc64480680e474d94..bb4411cfdf1bc7adc12c2f918d2eec830299f38b 100644
|
|
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
|
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
|
@@ -59,6 +59,7 @@ public abstract class BaseSpawner {
|
|
}
|
|
|
|
public boolean isNearPlayer(Level world, BlockPos pos) {
|
|
+ if (world.purpurConfig.spawnerDeactivateByRedstone && world.hasNeighborSignal(pos)) return false; // Purpur
|
|
return world.hasNearbyAlivePlayerThatAffectsSpawning((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange); // Paper - Affects Spawning API
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java
|
|
index 5d7a6e4b73f032db356e7ec369b150013e940ee6..6b2cda6d578a0983b2401ea20629275431018433 100644
|
|
--- a/src/main/java/net/minecraft/world/level/EntityGetter.java
|
|
+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java
|
|
@@ -184,7 +184,7 @@ public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_syst
|
|
|
|
default boolean hasNearbyAlivePlayer(double x, double y, double z, double range) {
|
|
for (Player player : this.players()) {
|
|
- if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) {
|
|
+ if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player) && EntitySelector.notAfk.test(player)) { // Purpur
|
|
double d = player.distanceToSqr(x, y, z);
|
|
if (range < 0.0 || d < range * range) {
|
|
return true;
|
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
|
index 022de445bbbb869c38be4972c98dcf1c665539ec..7493262c2879af196e5585b15faad69ae42764e3 100644
|
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
|
@@ -174,6 +174,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
// Paper end - add paper world config
|
|
|
|
public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
|
|
+ public final org.purpurmc.purpur.PurpurWorldConfig purpurConfig; // Purpur
|
|
public static BlockPos lastPhysicsProblem; // Spigot
|
|
private org.spigotmc.TickLimiter entityLimiter;
|
|
private org.spigotmc.TickLimiter tileLimiter;
|
|
@@ -181,6 +182,49 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
public final Map<ServerExplosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
|
|
public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> redstoneUpdateInfos; // Paper - Faster redstone torch rapid clock removal; Move from Map in BlockRedstoneTorch to here
|
|
|
|
+ // Purpur start
|
|
+ private com.google.common.cache.Cache<BreedingCooldownPair, Object> playerBreedingCooldowns;
|
|
+
|
|
+ private com.google.common.cache.Cache<BreedingCooldownPair, Object> getNewBreedingCooldownCache() {
|
|
+ return com.google.common.cache.CacheBuilder.newBuilder().expireAfterWrite(this.purpurConfig.animalBreedingCooldownSeconds, java.util.concurrent.TimeUnit.SECONDS).build();
|
|
+ }
|
|
+
|
|
+ public void resetBreedingCooldowns() {
|
|
+ this.playerBreedingCooldowns = this.getNewBreedingCooldownCache();
|
|
+ }
|
|
+
|
|
+ public boolean hasBreedingCooldown(java.util.UUID player, Class<? extends net.minecraft.world.entity.animal.Animal> animalType) { // Purpur
|
|
+ return this.playerBreedingCooldowns.getIfPresent(new BreedingCooldownPair(player, animalType)) != null;
|
|
+ }
|
|
+
|
|
+ public void addBreedingCooldown(java.util.UUID player, Class<? extends net.minecraft.world.entity.animal.Animal> animalType) {
|
|
+ this.playerBreedingCooldowns.put(new BreedingCooldownPair(player, animalType), new Object());
|
|
+ }
|
|
+
|
|
+ private static final class BreedingCooldownPair {
|
|
+ private final java.util.UUID playerUUID;
|
|
+ private final Class<? extends net.minecraft.world.entity.animal.Animal> animalType;
|
|
+
|
|
+ public BreedingCooldownPair(java.util.UUID playerUUID, Class<? extends net.minecraft.world.entity.animal.Animal> animalType) {
|
|
+ this.playerUUID = playerUUID;
|
|
+ this.animalType = animalType;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean equals(Object o) {
|
|
+ if (this == o) return true;
|
|
+ if (o == null || getClass() != o.getClass()) return false;
|
|
+ BreedingCooldownPair that = (BreedingCooldownPair) o;
|
|
+ return playerUUID.equals(that.playerUUID) && animalType.equals(that.animalType);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int hashCode() {
|
|
+ return java.util.Objects.hash(playerUUID, animalType);
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public CraftWorld getWorld() {
|
|
return this.world;
|
|
}
|
|
@@ -226,7 +270,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
|
|
@Override
|
|
public final <T extends Entity> List<T> getEntitiesOfClass(final Class<T> entityClass, final AABB boundingBox, final Predicate<? super T> predicate) {
|
|
- Profiler.get().incrementCounter("getEntities");
|
|
+ //Profiler.get().incrementCounter("getEntities"); // Purpur
|
|
final List<T> ret = new java.util.ArrayList<>();
|
|
|
|
((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(entityClass, null, boundingBox, ret, predicate);
|
|
@@ -236,7 +280,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
|
|
@Override
|
|
public final List<Entity> moonrise$getHardCollidingEntities(final Entity entity, final AABB box, final Predicate<? super Entity> predicate) {
|
|
- Profiler.get().incrementCounter("getEntities");
|
|
+ //Profiler.get().incrementCounter("getEntities"); // Purpur
|
|
final List<Entity> ret = new java.util.ArrayList<>();
|
|
|
|
((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getHardCollidingEntities(entity, box, ret, predicate);
|
|
@@ -842,6 +886,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
// Paper end - getblock optimisations - cache world height/sections
|
|
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
|
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
|
|
+ this.purpurConfig = new org.purpurmc.purpur.PurpurWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), env); // Purpur
|
|
+ this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); // Purpur
|
|
this.generator = gen;
|
|
this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);
|
|
|
|
@@ -1440,9 +1486,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
}
|
|
|
|
protected void tickBlockEntities() {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur
|
|
|
|
- gameprofilerfiller.push("blockEntities");
|
|
+ //gameprofilerfiller.push("blockEntities"); // Purpur
|
|
this.tickingBlockEntities = true;
|
|
if (!this.pendingBlockEntityTickers.isEmpty()) {
|
|
this.blockEntityTickers.addAll(this.pendingBlockEntityTickers);
|
|
@@ -1480,7 +1526,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075
|
|
|
|
this.tickingBlockEntities = false;
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
this.spigotConfig.currentPrimedTnt = 0; // Spigot
|
|
}
|
|
|
|
@@ -1650,7 +1696,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
|
|
@Override
|
|
public List<Entity> getEntities(@Nullable Entity except, AABB box, Predicate<? super Entity> predicate) {
|
|
- Profiler.get().incrementCounter("getEntities");
|
|
+ //Profiler.get().incrementCounter("getEntities"); // Purpur
|
|
List<Entity> list = Lists.newArrayList();
|
|
|
|
// Paper start - rewrite chunk system
|
|
@@ -1680,7 +1726,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
public <T extends Entity> void getEntities(final EntityTypeTest<Entity, T> entityTypeTest,
|
|
final AABB boundingBox, final Predicate<? super T> predicate,
|
|
final List<? super T> into, final int maxCount) {
|
|
- Profiler.get().incrementCounter("getEntities");
|
|
+ //Profiler.get().incrementCounter("getEntities"); // Purpur
|
|
|
|
if (entityTypeTest instanceof net.minecraft.world.entity.EntityType<T> byType) {
|
|
if (maxCount != Integer.MAX_VALUE) {
|
|
@@ -2031,4 +2077,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
return this.id;
|
|
}
|
|
}
|
|
+
|
|
+ // 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/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
|
index 5297798c2be1ba85569c2b92ed221956bf75477a..7f936a7ba994ccb51c17168c798b42dde0877a5d 100644
|
|
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
|
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
|
@@ -211,7 +211,7 @@ public final class NaturalSpawner {
|
|
}
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
// Paper start - Add mobcaps commands
|
|
@@ -280,7 +280,7 @@ public final class NaturalSpawner {
|
|
blockposition_mutableblockposition.set(l, i, i1);
|
|
double d0 = (double) l + 0.5D;
|
|
double d1 = (double) i1 + 0.5D;
|
|
- Player entityhuman = world.getNearestPlayer(d0, (double) i, d1, -1.0D, false);
|
|
+ Player entityhuman = world.getNearestPlayer(d0, (double) i, d1, -1.0D, world.purpurConfig.mobSpawningIgnoreCreativePlayers); // Purpur
|
|
|
|
if (entityhuman != null) {
|
|
double d2 = entityhuman.distanceToSqr(d0, (double) i, d1);
|
|
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
|
index bbbd451ff184be8fa13bd93d53c89a9502f9951a..3c3d219c9339f64c23ec0b31783bf68a4423636c 100644
|
|
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
|
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
|
@@ -311,7 +311,7 @@ public class ServerExplosion implements Explosion {
|
|
public ServerExplosion(ServerLevel world, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, Vec3 pos, float power, boolean createFire, Explosion.BlockInteraction destructionType) {
|
|
this.level = world;
|
|
this.source = entity;
|
|
- this.radius = (float) Math.max(power, 0.0); // CraftBukkit - clamp bad values
|
|
+ this.radius = (float) (world == null || world.purpurConfig.explosionClampRadius ? Math.max(power, 0.0) : power); // CraftBukkit - clamp bad values // Purpur
|
|
this.center = pos;
|
|
this.fire = createFire;
|
|
this.blockInteraction = destructionType;
|
|
@@ -666,10 +666,27 @@ public class ServerExplosion implements Explosion {
|
|
|
|
public void explode() {
|
|
// CraftBukkit start
|
|
- if (this.radius < 0.1F) {
|
|
+ if ((this.level == null || this.level.purpurConfig.explosionClampRadius) && this.radius < 0.1F) { // Purpur
|
|
return;
|
|
}
|
|
// CraftBukkit end
|
|
+ // Purpur start - add PreExplodeEvents
|
|
+ if (this.source != null) {
|
|
+ Location location = new Location(this.level.getWorld(), this.center.x, this.center.y, this.center.z);
|
|
+ if(!new org.purpurmc.purpur.event.entity.PreEntityExplodeEvent(this.source.getBukkitEntity(), location, this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F, org.bukkit.craftbukkit.CraftExplosionResult.toBukkit(getBlockInteraction())).callEvent()) {
|
|
+ this.wasCanceled = true;
|
|
+ return;
|
|
+ }
|
|
+ } else {
|
|
+ Location location = new Location(this.level.getWorld(), this.center.x, this.center.y, this.center.z);
|
|
+ org.bukkit.block.Block block = location.getBlock();
|
|
+ org.bukkit.block.BlockState blockState = (this.damageSource.getDirectBlockState() != null) ? this.damageSource.getDirectBlockState() : block.getState();
|
|
+ if(!new org.purpurmc.purpur.event.PreBlockExplodeEvent(location.getBlock(), this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F, blockState, org.bukkit.craftbukkit.CraftExplosionResult.toBukkit(getBlockInteraction())).callEvent()) {
|
|
+ this.wasCanceled = true;
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
// Paper start - collision optimisations
|
|
this.blockCache = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
|
|
this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/AnvilBlock.java b/src/main/java/net/minecraft/world/level/block/AnvilBlock.java
|
|
index 50c907c962f936d2035bb7550750cdbd220b29c2..f9a2d2d4f798efa0d691996ec5ff7fe00260b36c 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/AnvilBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/AnvilBlock.java
|
|
@@ -59,6 +59,53 @@ public class AnvilBlock extends FallingBlock {
|
|
return this.defaultBlockState().setValue(FACING, ctx.getHorizontalDirection().getClockWise());
|
|
}
|
|
|
|
+ // Purpur start - repairable/damageable anvils
|
|
+ @Override
|
|
+ protected net.minecraft.world.InteractionResult useItemOn(final net.minecraft.world.item.ItemStack stack, final BlockState state, final Level world, final BlockPos pos, final Player player, final net.minecraft.world.InteractionHand hand, final BlockHitResult hit) {
|
|
+ if (world.purpurConfig.anvilRepairIngotsAmount > 0 && stack.is(net.minecraft.world.item.Items.IRON_INGOT)) {
|
|
+ if (stack.getCount() < world.purpurConfig.anvilRepairIngotsAmount) {
|
|
+ // not enough iron ingots, play "error" sound and consume
|
|
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
|
|
+ return net.minecraft.world.InteractionResult.CONSUME;
|
|
+ }
|
|
+ if (state.is(Blocks.DAMAGED_ANVIL)) {
|
|
+ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3);
|
|
+ } else if (state.is(Blocks.CHIPPED_ANVIL)) {
|
|
+ world.setBlock(pos, Blocks.ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3);
|
|
+ } else if (state.is(Blocks.ANVIL)) {
|
|
+ // anvil is already fully repaired, play "error" sound and consume
|
|
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
|
|
+ return net.minecraft.world.InteractionResult.CONSUME;
|
|
+ }
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ stack.shrink(world.purpurConfig.anvilRepairIngotsAmount);
|
|
+ }
|
|
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_PLACE, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
|
|
+ return net.minecraft.world.InteractionResult.CONSUME;
|
|
+ }
|
|
+ if (world.purpurConfig.anvilDamageObsidianAmount > 0 && stack.is(net.minecraft.world.item.Items.OBSIDIAN)) {
|
|
+ if (stack.getCount() < world.purpurConfig.anvilDamageObsidianAmount) {
|
|
+ // not enough obsidian, play "error" sound and consume
|
|
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
|
|
+ return net.minecraft.world.InteractionResult.CONSUME;
|
|
+ }
|
|
+ if (state.is(Blocks.DAMAGED_ANVIL)) {
|
|
+ world.destroyBlock(pos, false);
|
|
+ } else if (state.is(Blocks.CHIPPED_ANVIL)) {
|
|
+ world.setBlock(pos, Blocks.DAMAGED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3);
|
|
+ } else if (state.is(Blocks.ANVIL)) {
|
|
+ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3);
|
|
+ }
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ stack.shrink(world.purpurConfig.anvilDamageObsidianAmount);
|
|
+ }
|
|
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_LAND, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
|
|
+ return net.minecraft.world.InteractionResult.CONSUME;
|
|
+ }
|
|
+ return net.minecraft.world.InteractionResult.TRY_WITH_EMPTY_HAND;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) {
|
|
if (!world.isClientSide) {
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java b/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java
|
|
index affbbf6abc6bc09ecb652c1dee92aa297458bc39..febc05dc39741807127cba4a2a55aaad62b0800c 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java
|
|
@@ -50,6 +50,20 @@ public class AzaleaBlock extends BushBlock implements BonemealableBlock {
|
|
|
|
@Override
|
|
public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
|
|
+ // Purpur start
|
|
+ growTree(world, random, pos, state);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void randomTick(net.minecraft.world.level.block.state.BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
|
+ double chance = state.getBlock() == Blocks.FLOWERING_AZALEA ? world.purpurConfig.floweringAzaleaGrowthChance : world.purpurConfig.azaleaGrowthChance;
|
|
+ if (chance > 0.0D && world.getMaxLocalRawBrightness(pos.above()) > 9 && random.nextDouble() < chance) {
|
|
+ growTree(world, random, pos, state);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void growTree(ServerLevel world, RandomSource random, BlockPos pos, net.minecraft.world.level.block.state.BlockState state) {
|
|
+ // Purpur end
|
|
TreeGrower.AZALEA.growTree(world, world.getChunkSource().getGenerator(), pos, state, random);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java b/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java
|
|
index d7ca7a43d2d5f8cad416156fd40588cdd6634f52..231338adda19f57bf1a95379cc2e14341d4068d0 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java
|
|
@@ -39,6 +39,7 @@ public abstract class BaseCoralPlantTypeBlock extends Block implements SimpleWat
|
|
}
|
|
|
|
protected static boolean scanForWater(BlockState state, BlockGetter world, BlockPos pos) {
|
|
+ if (!((net.minecraft.world.level.LevelAccessor) world).getMinecraftWorld().purpurConfig.coralDieOutsideWater) return true; // Purpur
|
|
if (state.getValue(WATERLOGGED)) {
|
|
return true;
|
|
} else {
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/BedBlock.java b/src/main/java/net/minecraft/world/level/block/BedBlock.java
|
|
index c02c4834ace843633b77fb43eeadd3ddc7b1f743..c130d316e87f1f896d33ab43831063a89e3bef2b 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/BedBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/BedBlock.java
|
|
@@ -106,7 +106,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock
|
|
|
|
Vec3 vec3d = pos.getCenter();
|
|
|
|
- world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d), (ExplosionDamageCalculator) null, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK);
|
|
+ if (world.purpurConfig.bedExplode) world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d), (ExplosionDamageCalculator) null, vec3d, (float) world.purpurConfig.bedExplosionPower, world.purpurConfig.bedExplosionFire, world.purpurConfig.bedExplosionEffect); // Purpur
|
|
return InteractionResult.SUCCESS_SERVER;
|
|
} else if ((Boolean) state.getValue(BedBlock.OCCUPIED)) {
|
|
if (!BedBlock.canSetSpawn(world)) return this.explodeBed(state, world, pos); // Paper - check explode first
|
|
@@ -159,7 +159,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock
|
|
|
|
Vec3 vec3d = blockposition.getCenter();
|
|
|
|
- world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, blockState), (ExplosionDamageCalculator) null, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); // CraftBukkit - add state
|
|
+ if (world.purpurConfig.bedExplode) world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, blockState), (ExplosionDamageCalculator) null, vec3d, (float) world.purpurConfig.bedExplosionPower, world.purpurConfig.bedExplosionFire, world.purpurConfig.bedExplosionEffect); // CraftBukkit - add state // Purpur
|
|
return InteractionResult.SUCCESS;
|
|
}
|
|
}
|
|
@@ -183,7 +183,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock
|
|
|
|
@Override
|
|
public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
|
|
- super.fallOn(world, state, pos, entity, fallDistance * 0.5F);
|
|
+ super.fallOn(world, state, pos, entity, fallDistance); // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java b/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java
|
|
index 9e3f1441d62128535112621bf259c24f1a90595b..2535e6d71b690f8dfde41a7d9cb76b6f010f5aa7 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java
|
|
@@ -246,7 +246,7 @@ public class BigDripleafBlock extends HorizontalDirectionalBlock implements Bone
|
|
BigDripleafBlock.playTiltSound(world, blockposition, soundeffect);
|
|
}
|
|
|
|
- int i = BigDripleafBlock.DELAY_UNTIL_NEXT_TILT_STATE.getInt(tilt);
|
|
+ int i = world.purpurConfig.bigDripleafTiltDelay.getOrDefault(tilt, -1); // Purpur
|
|
|
|
if (i != -1) {
|
|
world.scheduleTick(blockposition, (Block) this, i);
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
|
|
index b6d6c2cb9b227a17fb4ce42bc75f92206fbea043..1748aea6613e0c8081f70092c9431e7e04907383 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/Block.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
|
|
@@ -88,6 +88,10 @@ public class Block extends BlockBehaviour implements ItemLike {
|
|
public static final int UPDATE_LIMIT = 512;
|
|
protected final StateDefinition<Block, BlockState> stateDefinition;
|
|
private BlockState defaultBlockState;
|
|
+ // Purpur start
|
|
+ public float fallDamageMultiplier = 1.0F;
|
|
+ public float fallDistanceMultiplier = 1.0F;
|
|
+ // Purpur end
|
|
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed
|
|
public final boolean isDestroyable() {
|
|
return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits ||
|
|
@@ -303,7 +307,7 @@ public class Block extends BlockBehaviour implements ItemLike {
|
|
public static void dropResources(BlockState state, LevelAccessor world, BlockPos pos, @Nullable BlockEntity blockEntity) {
|
|
if (world instanceof ServerLevel) {
|
|
Block.getDrops(state, (ServerLevel) world, pos, blockEntity).forEach((itemstack) -> {
|
|
- Block.popResource((ServerLevel) world, pos, itemstack);
|
|
+ Block.popResource((ServerLevel) world, pos, applyLoreFromTile(itemstack, blockEntity)); // Purpur
|
|
});
|
|
state.spawnAfterBreak((ServerLevel) world, pos, ItemStack.EMPTY, true);
|
|
}
|
|
@@ -322,7 +326,7 @@ public class Block extends BlockBehaviour implements ItemLike {
|
|
event.setExpToDrop(block.getExpDrop(state, serverLevel, pos, net.minecraft.world.item.ItemStack.EMPTY, true)); // Paper - Properly handle xp dropping
|
|
event.callEvent();
|
|
for (org.bukkit.inventory.ItemStack drop : event.getDrops()) {
|
|
- popResource(serverLevel, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop));
|
|
+ popResource(serverLevel, pos, applyLoreFromTile(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop), blockEntity)); // Purpur
|
|
}
|
|
state.spawnAfterBreak(serverLevel, pos, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping
|
|
block.popExperience(serverLevel, pos, event.getExpToDrop()); // Paper - Properly handle xp dropping
|
|
@@ -339,13 +343,32 @@ public class Block extends BlockBehaviour implements ItemLike {
|
|
// Paper end - Properly handle xp dropping
|
|
if (world instanceof ServerLevel) {
|
|
Block.getDrops(state, (ServerLevel) world, pos, blockEntity, entity, tool).forEach((itemstack1) -> {
|
|
- Block.popResource(world, pos, itemstack1);
|
|
+ Block.popResource(world, pos, applyLoreFromTile(itemstack1, blockEntity)); // Purpur
|
|
});
|
|
state.spawnAfterBreak((ServerLevel) world, pos, tool, dropExperience); // Paper - Properly handle xp dropping
|
|
}
|
|
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ private static ItemStack applyLoreFromTile(ItemStack stack, @Nullable BlockEntity blockEntity) {
|
|
+ if (stack.getItem() instanceof BlockItem) {
|
|
+ if (blockEntity != null && blockEntity.getLevel() instanceof ServerLevel) {
|
|
+ net.minecraft.world.item.component.ItemLore lore = blockEntity.getPersistentLore();
|
|
+ net.minecraft.core.component.DataComponentPatch.Builder builder = net.minecraft.core.component.DataComponentPatch.builder();
|
|
+ if (blockEntity.getLevel().purpurConfig.persistentTileEntityLore && lore != null) {
|
|
+ builder.set(net.minecraft.core.component.DataComponents.LORE, lore);
|
|
+ }
|
|
+ if (!blockEntity.getLevel().purpurConfig.persistentTileEntityDisplayName) {
|
|
+ builder.remove(net.minecraft.core.component.DataComponents.CUSTOM_NAME);
|
|
+ }
|
|
+ stack.applyComponents(builder.build());
|
|
+ }
|
|
+ }
|
|
+ return stack;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
public static void popResource(Level world, BlockPos pos, ItemStack stack) {
|
|
double d0 = (double) EntityType.ITEM.getHeight() / 2.0D;
|
|
double d1 = (double) pos.getX() + 0.5D + Mth.nextDouble(world.random, -0.25D, 0.25D);
|
|
@@ -433,7 +456,17 @@ public class Block extends BlockBehaviour implements ItemLike {
|
|
} // Paper - fix drops not preventing stats/food exhaustion
|
|
}
|
|
|
|
- public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) {}
|
|
+ // Purpur start
|
|
+ @Nullable protected LivingEntity placer = null;
|
|
+
|
|
+ public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) {
|
|
+ this.placer = placer;
|
|
+ }
|
|
+
|
|
+ public void forgetPlacer() {
|
|
+ this.placer = null;
|
|
+ }
|
|
+ // Purpur end
|
|
|
|
public boolean isPossibleToRespawnInThis(BlockState state) {
|
|
return !state.isSolid() && !state.liquid();
|
|
@@ -444,7 +477,7 @@ public class Block extends BlockBehaviour implements ItemLike {
|
|
}
|
|
|
|
public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
|
|
- entity.causeFallDamage(fallDistance, 1.0F, entity.damageSources().fall());
|
|
+ entity.causeFallDamage(fallDistance * fallDistanceMultiplier, fallDamageMultiplier, entity.damageSources().fall()); // Purpur
|
|
}
|
|
|
|
public void updateEntityMovementAfterFallOn(BlockGetter world, Entity entity) {
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/Blocks.java b/src/main/java/net/minecraft/world/level/block/Blocks.java
|
|
index 66a07f7cbf1c1d6ecbe055cbf4f63eb07d93e90c..63d67d46d30ed8ed57cdc0e59b6cb6b75ab22c1f 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/Blocks.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/Blocks.java
|
|
@@ -6465,6 +6465,7 @@ public class Blocks {
|
|
BlockBehaviour.Properties.of()
|
|
.mapColor(MapColor.PLANT)
|
|
.forceSolidOff()
|
|
+ .randomTicks() // Purpur
|
|
.instabreak()
|
|
.sound(SoundType.AZALEA)
|
|
.noOcclusion()
|
|
@@ -6476,6 +6477,7 @@ public class Blocks {
|
|
BlockBehaviour.Properties.of()
|
|
.mapColor(MapColor.PLANT)
|
|
.forceSolidOff()
|
|
+ .randomTicks() // Purpur
|
|
.instabreak()
|
|
.sound(SoundType.FLOWERING_AZALEA)
|
|
.noOcclusion()
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java b/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java
|
|
index 385da0585f409ee453f10d45f5837cdc09adc21b..c65016cba376a41c267fb4b6499ec0a263851558 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java
|
|
@@ -123,10 +123,10 @@ public class BubbleColumnBlock extends Block implements BucketPickup {
|
|
if (state.is(Blocks.BUBBLE_COLUMN)) {
|
|
return state;
|
|
} else if (state.is(Blocks.SOUL_SAND)) {
|
|
- return Blocks.BUBBLE_COLUMN.defaultBlockState().setValue(DRAG_DOWN, Boolean.valueOf(false));
|
|
+ return Blocks.BUBBLE_COLUMN.defaultBlockState().setValue(DRAG_DOWN, Boolean.valueOf(org.purpurmc.purpur.PurpurConfig.soulSandBlockReverseBubbleColumnFlow)); // Purpur
|
|
} else {
|
|
return state.is(Blocks.MAGMA_BLOCK)
|
|
- ? Blocks.BUBBLE_COLUMN.defaultBlockState().setValue(DRAG_DOWN, Boolean.valueOf(true))
|
|
+ ? Blocks.BUBBLE_COLUMN.defaultBlockState().setValue(DRAG_DOWN, Boolean.valueOf(!org.purpurmc.purpur.PurpurConfig.magmaBlockReverseBubbleColumnFlow)) // Purpur
|
|
: Blocks.WATER.defaultBlockState();
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/BushBlock.java b/src/main/java/net/minecraft/world/level/block/BushBlock.java
|
|
index eb324fda54ada3ed7941713a784ed2d686ec8c4b..09cc76f3fee4a767c9ec3fa592f2c3c6146344ec 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/BushBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/BushBlock.java
|
|
@@ -55,4 +55,24 @@ public abstract class BushBlock extends Block {
|
|
protected boolean isPathfindable(BlockState state, PathComputationType type) {
|
|
return type == PathComputationType.AIR && !this.hasCollision ? true : super.isPathfindable(state, type);
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ public void playerDestroyAndReplant(net.minecraft.world.level.Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, net.minecraft.world.item.ItemStack itemInHand, net.minecraft.world.level.ItemLike itemToReplant) {
|
|
+ player.awardStat(net.minecraft.stats.Stats.BLOCK_MINED.get(this));
|
|
+ player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED);
|
|
+ java.util.List<net.minecraft.world.item.ItemStack> dropList = Block.getDrops(state, (net.minecraft.server.level.ServerLevel) world, pos, blockEntity, player, itemInHand);
|
|
+
|
|
+ boolean planted = false;
|
|
+ for (net.minecraft.world.item.ItemStack itemToDrop : dropList) {
|
|
+ if (!planted && itemToDrop.getItem() == itemToReplant) {
|
|
+ world.setBlock(pos, defaultBlockState(), 3);
|
|
+ itemToDrop.setCount(itemToDrop.getCount() - 1);
|
|
+ planted = true;
|
|
+ }
|
|
+ Block.popResource(world, pos, itemToDrop);
|
|
+ }
|
|
+
|
|
+ state.spawnAfterBreak((net.minecraft.server.level.ServerLevel) world, pos, itemInHand, true);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/CactusBlock.java b/src/main/java/net/minecraft/world/level/block/CactusBlock.java
|
|
index c045b1cccf0047dbef8c04d5a28d31d53389054f..9f163ed07f8e6a5370c4c355b4e910f7a49b6bcd 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/CactusBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/CactusBlock.java
|
|
@@ -24,7 +24,7 @@ import net.minecraft.world.phys.shapes.CollisionContext;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit
|
|
|
|
-public class CactusBlock extends Block {
|
|
+public class CactusBlock extends Block implements BonemealableBlock { // Purpur
|
|
|
|
public static final MapCodec<CactusBlock> CODEC = simpleCodec(CactusBlock::new);
|
|
public static final IntegerProperty AGE = BlockStateProperties.AGE_15;
|
|
@@ -115,7 +115,7 @@ public class CactusBlock extends Block {
|
|
|
|
enumdirection = (Direction) iterator.next();
|
|
iblockdata1 = world.getBlockState(pos.relative(enumdirection));
|
|
- } while (!iblockdata1.isSolid() && !world.getFluidState(pos.relative(enumdirection)).is(FluidTags.LAVA));
|
|
+ } while ((!world.getWorldBorder().world.purpurConfig.cactusBreaksFromSolidNeighbors || !iblockdata1.isSolid()) && !world.getFluidState(pos.relative(enumdirection)).is(FluidTags.LAVA)); // Purpur
|
|
|
|
return false;
|
|
}
|
|
@@ -135,4 +135,34 @@ public class CactusBlock extends Block {
|
|
protected boolean isPathfindable(BlockState state, PathComputationType type) {
|
|
return false;
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isValidBonemealTarget(final LevelReader world, final BlockPos pos, final BlockState state) {
|
|
+ if (!((Level) world).purpurConfig.cactusAffectedByBonemeal || !world.isEmptyBlock(pos.above())) return false;
|
|
+
|
|
+ int cactusHeight = 0;
|
|
+ while (world.getBlockState(pos.below(cactusHeight)).is(this)) {
|
|
+ cactusHeight++;
|
|
+ }
|
|
+
|
|
+ return cactusHeight < ((Level) world).paperConfig().maxGrowthHeight.cactus;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isBonemealSuccess(Level world, RandomSource random, BlockPos pos, BlockState state) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
|
|
+ int cactusHeight = 0;
|
|
+ while (world.getBlockState(pos.below(cactusHeight)).is(this)) {
|
|
+ cactusHeight++;
|
|
+ }
|
|
+ for (int i = 0; i <= world.paperConfig().maxGrowthHeight.cactus - cactusHeight; i++) {
|
|
+ world.setBlockAndUpdate(pos.above(i), state.setValue(CactusBlock.AGE, 0));
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/CakeBlock.java b/src/main/java/net/minecraft/world/level/block/CakeBlock.java
|
|
index 648c2510beb162e73aed236a3169d0bbb8fc5050..3563a241c0b697dc0167cf7b1aa73fef7d1e7934 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/CakeBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/CakeBlock.java
|
|
@@ -119,6 +119,7 @@ public class CakeBlock extends Block {
|
|
org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(player, 2 + oldFoodLevel);
|
|
|
|
if (!event.isCancelled()) {
|
|
+ if (player.level().purpurConfig.playerBurpWhenFull && event.getFoodLevel() == 20 && oldFoodLevel < 20) player.burpDelay = player.level().purpurConfig.playerBurpDelay; // Purpur
|
|
player.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 0.1F);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java
|
|
index 18d4020017d76303d3179fad8974574777ea6305..2ee2b1485f848ac5270bc3f7e1e5b1bc3029b0bb 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java
|
|
@@ -140,7 +140,7 @@ public class CampfireBlock extends BaseEntityBlock implements SimpleWaterloggedB
|
|
BlockPos blockposition = ctx.getClickedPos();
|
|
boolean flag = world.getFluidState(blockposition).getType() == Fluids.WATER;
|
|
|
|
- return (BlockState) ((BlockState) ((BlockState) ((BlockState) this.defaultBlockState().setValue(CampfireBlock.WATERLOGGED, flag)).setValue(CampfireBlock.SIGNAL_FIRE, this.isSmokeSource(world.getBlockState(blockposition.below())))).setValue(CampfireBlock.LIT, !flag)).setValue(CampfireBlock.FACING, ctx.getHorizontalDirection());
|
|
+ return (BlockState) ((BlockState) ((BlockState) ((BlockState) this.defaultBlockState().setValue(CampfireBlock.WATERLOGGED, flag)).setValue(CampfireBlock.SIGNAL_FIRE, this.isSmokeSource(world.getBlockState(blockposition.below())))).setValue(CampfireBlock.LIT, world.purpurConfig.campFireLitWhenPlaced ? !flag : world.purpurConfig.campFireLitWhenPlaced)).setValue(CampfireBlock.FACING, ctx.getHorizontalDirection()); // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/CarvedPumpkinBlock.java b/src/main/java/net/minecraft/world/level/block/CarvedPumpkinBlock.java
|
|
index 22242d11e009acab4c9738a1c6ada8b9ba678a0c..828fa78a89f13ef81c53b4d6ea6ef86c7b53024e 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/CarvedPumpkinBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/CarvedPumpkinBlock.java
|
|
@@ -72,7 +72,7 @@ public class CarvedPumpkinBlock extends HorizontalDirectionalBlock {
|
|
SnowGolem entitysnowman = (SnowGolem) EntityType.SNOW_GOLEM.create(world, EntitySpawnReason.TRIGGERED);
|
|
|
|
if (entitysnowman != null) {
|
|
- CarvedPumpkinBlock.spawnGolemInWorld(world, shapedetector_shapedetectorcollection, entitysnowman, shapedetector_shapedetectorcollection.getBlock(0, 2, 0).getPos());
|
|
+ CarvedPumpkinBlock.spawnGolemInWorld(world, shapedetector_shapedetectorcollection, entitysnowman, shapedetector_shapedetectorcollection.getBlock(0, 2, 0).getPos(), this.placer); // Purpur
|
|
}
|
|
} else {
|
|
BlockPattern.BlockPatternMatch shapedetector_shapedetectorcollection1 = this.getOrCreateIronGolemFull().find(world, pos);
|
|
@@ -82,7 +82,7 @@ public class CarvedPumpkinBlock extends HorizontalDirectionalBlock {
|
|
|
|
if (entityirongolem != null) {
|
|
entityirongolem.setPlayerCreated(true);
|
|
- CarvedPumpkinBlock.spawnGolemInWorld(world, shapedetector_shapedetectorcollection1, entityirongolem, shapedetector_shapedetectorcollection1.getBlock(1, 2, 0).getPos());
|
|
+ CarvedPumpkinBlock.spawnGolemInWorld(world, shapedetector_shapedetectorcollection1, entityirongolem, shapedetector_shapedetectorcollection1.getBlock(1, 2, 0).getPos(), this.placer); // Purpur
|
|
}
|
|
}
|
|
}
|
|
@@ -90,6 +90,16 @@ public class CarvedPumpkinBlock extends HorizontalDirectionalBlock {
|
|
}
|
|
|
|
private static void spawnGolemInWorld(Level world, BlockPattern.BlockPatternMatch patternResult, Entity entity, BlockPos pos) {
|
|
+ // Purpur start
|
|
+ spawnGolemInWorld(world, patternResult, entity, pos, null);
|
|
+ }
|
|
+ private static void spawnGolemInWorld(Level world, BlockPattern.BlockPatternMatch patternResult, Entity entity, BlockPos pos, net.minecraft.world.entity.LivingEntity placer) {
|
|
+ if (entity instanceof SnowGolem snowGolem) {
|
|
+ snowGolem.setSummoner(placer == null ? null : placer.getUUID());
|
|
+ } else if (entity instanceof IronGolem ironGolem) {
|
|
+ ironGolem.setSummoner(placer == null ? null : placer.getUUID());
|
|
+ }
|
|
+ // Purpur end
|
|
// clearPatternBlocks(world, shapedetector_shapedetectorcollection); // CraftBukkit - moved down
|
|
entity.moveTo((double) pos.getX() + 0.5D, (double) pos.getY() + 0.05D, (double) pos.getZ() + 0.5D, 0.0F, 0.0F);
|
|
// CraftBukkit start
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java
|
|
index c9968934f4ecaa8d81e545f279b3001c7b1ce545..03e4fce6f8226451365fc2831b5bf1e5e6091730 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java
|
|
@@ -37,7 +37,7 @@ public class CauldronBlock extends AbstractCauldronBlock {
|
|
}
|
|
|
|
protected static boolean shouldHandlePrecipitation(Level world, Biome.Precipitation precipitation) {
|
|
- return precipitation == Biome.Precipitation.RAIN ? world.getRandom().nextFloat() < 0.05F : (precipitation == Biome.Precipitation.SNOW ? world.getRandom().nextFloat() < 0.1F : false);
|
|
+ return precipitation == Biome.Precipitation.RAIN ? world.getRandom().nextFloat() < world.purpurConfig.cauldronRainChance : (precipitation == Biome.Precipitation.SNOW ? world.getRandom().nextFloat() < world.purpurConfig.cauldronPowderSnowChance : false); // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
|
|
index c4473c2a778116d48bc3e4796afd901f455070e6..e62217c0bfa6cc426c7d41154f3ccc34d8f242ca 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
|
|
@@ -94,4 +94,11 @@ public class CaveVinesBlock extends GrowingPlantHeadBlock implements CaveVines {
|
|
public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
|
|
world.setBlock(pos, state.setValue(BERRIES, Boolean.valueOf(true)), 2);
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public int getMaxGrowthAge() {
|
|
+ return org.purpurmc.purpur.PurpurConfig.caveVinesMaxGrowthAge;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/ChangeOverTimeBlock.java b/src/main/java/net/minecraft/world/level/block/ChangeOverTimeBlock.java
|
|
index daae7fd6e0148cfba8e359d990748a0c83a3376e..0e06b1bcd906e92c083dc74d56d6d0a2a36f62a7 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/ChangeOverTimeBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/ChangeOverTimeBlock.java
|
|
@@ -67,7 +67,7 @@ public interface ChangeOverTimeBlock<T extends Enum<T>> {
|
|
}
|
|
|
|
float f = (float) (k + 1) / (float) (k + j + 1);
|
|
- float f1 = f * f * this.getChanceModifier();
|
|
+ float f1 = world.purpurConfig.disableOxidationProximityPenalty ? this.getChanceModifier() : f * f * this.getChanceModifier(); // Purpur
|
|
|
|
return random.nextFloat() < f1 ? this.getNext(state) : Optional.empty();
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/ChestBlock.java b/src/main/java/net/minecraft/world/level/block/ChestBlock.java
|
|
index edef8fc62f8dba1b57214d8d7d805ff0d83f4114..663eb96b8227f000448957b5d8ea13ca78cee329 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/ChestBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/ChestBlock.java
|
|
@@ -341,6 +341,7 @@ public class ChestBlock extends AbstractChestBlock<ChestBlockEntity> implements
|
|
}
|
|
|
|
public static boolean isBlockedChestByBlock(BlockGetter world, BlockPos pos) {
|
|
+ if (world instanceof Level && ((Level) world).purpurConfig.chestOpenWithBlockOnTop) return false; // Purpur
|
|
BlockPos blockposition1 = pos.above();
|
|
|
|
return world.getBlockState(blockposition1).isRedstoneConductor(world, blockposition1);
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java
|
|
index db837b250fc35af5b528bf973b3b07f63e79bc46..ed3a310d56a0cca8c4c11c3768ac2056cd11edea 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java
|
|
@@ -241,18 +241,27 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder {
|
|
int i = (Integer) state.getValue(ComposterBlock.LEVEL);
|
|
|
|
if (i < 8 && ComposterBlock.COMPOSTABLES.containsKey(stack.getItem())) {
|
|
- if (i < 7 && !world.isClientSide) {
|
|
- BlockState iblockdata1 = ComposterBlock.addItem(player, state, world, pos, stack);
|
|
- // Paper start - handle cancelled events
|
|
- if (iblockdata1 == null) {
|
|
- return InteractionResult.PASS;
|
|
- }
|
|
- // Paper end
|
|
-
|
|
- world.levelEvent(1500, pos, state != iblockdata1 ? 1 : 0);
|
|
- player.awardStat(Stats.ITEM_USED.get(stack.getItem()));
|
|
- stack.consume(1, player);
|
|
+ // Purpur start - sneak to bulk process composter
|
|
+ BlockState newState = process(i, player, state, world, pos, stack);
|
|
+ if (newState == null) {
|
|
+ return InteractionResult.PASS;
|
|
}
|
|
+ if (world.purpurConfig.composterBulkProcess && player.isShiftKeyDown() && newState != state) {
|
|
+ BlockState oldState;
|
|
+ int oldCount, newCount, oldLevel, newLevel;
|
|
+ do {
|
|
+ oldState = newState;
|
|
+ oldCount = stack.getCount();
|
|
+ oldLevel = oldState.getValue(ComposterBlock.LEVEL);
|
|
+ newState = process(oldLevel, player, oldState, world, pos, stack);
|
|
+ if (newState == null) {
|
|
+ return InteractionResult.PASS;
|
|
+ }
|
|
+ newCount = stack.getCount();
|
|
+ newLevel = newState.getValue(ComposterBlock.LEVEL);
|
|
+ } while (newCount > 0 && (newCount != oldCount || newLevel != oldLevel || newState != oldState));
|
|
+ }
|
|
+ // Purpur end
|
|
|
|
return InteractionResult.SUCCESS;
|
|
} else {
|
|
@@ -260,6 +269,25 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder {
|
|
}
|
|
}
|
|
|
|
+ // Purpur start - sneak to bulk process composter
|
|
+ private static @Nullable BlockState process(int level, Player player, BlockState state, Level world, BlockPos pos, ItemStack stack) {
|
|
+ if (level < 7 && !world.isClientSide) {
|
|
+ BlockState iblockdata1 = ComposterBlock.addItem(player, state, world, pos, stack);
|
|
+ // Paper start - handle cancelled events
|
|
+ if (iblockdata1 == null) {
|
|
+ return null;
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
+ world.levelEvent(1500, pos, state != iblockdata1 ? 1 : 0);
|
|
+ player.awardStat(Stats.ITEM_USED.get(stack.getItem()));
|
|
+ stack.consume(1, player);
|
|
+ return iblockdata1;
|
|
+ }
|
|
+ return state;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) {
|
|
int i = (Integer) state.getValue(ComposterBlock.LEVEL);
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/CoralBlock.java b/src/main/java/net/minecraft/world/level/block/CoralBlock.java
|
|
index a59b23f4062fa896836dec72cbd5097411774ad1..c526ea13a726624adaa654f09ff84c899c13ab98 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/CoralBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/CoralBlock.java
|
|
@@ -60,6 +60,7 @@ public class CoralBlock extends Block {
|
|
}
|
|
|
|
protected boolean scanForWater(BlockGetter world, BlockPos pos) {
|
|
+ if (!((net.minecraft.world.level.LevelAccessor) world).getMinecraftWorld().purpurConfig.coralDieOutsideWater) return true; // Purpur
|
|
Direction[] aenumdirection = Direction.values();
|
|
int i = aenumdirection.length;
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/CropBlock.java b/src/main/java/net/minecraft/world/level/block/CropBlock.java
|
|
index 1ada5ed825501666addacf527a513ab7bd4a3a58..4f64011262eef6a24a8e8595ace1e4d1d82923e5 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/CropBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java
|
|
@@ -180,7 +180,7 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
|
|
protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
|
|
if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent
|
|
if (world instanceof ServerLevel worldserver) {
|
|
- if (entity instanceof Ravager && CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit
|
|
+ if (entity instanceof Ravager && world.purpurConfig.ravagerGriefableBlocks.contains(world.getBlockState(pos).getBlock()) && CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), (!world.purpurConfig.ravagerBypassMobGriefing && !worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)))) { // CraftBukkit // Purpur
|
|
worldserver.destroyBlock(pos, true, entity);
|
|
}
|
|
}
|
|
@@ -216,4 +216,15 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
|
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
|
builder.add(CropBlock.AGE);
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public void playerDestroy(Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, ItemStack itemInHand, boolean includeDrops, boolean dropExp) {
|
|
+ if (world.purpurConfig.hoeReplantsCrops && itemInHand.getItem() instanceof net.minecraft.world.item.HoeItem) {
|
|
+ super.playerDestroyAndReplant(world, player, pos, state, blockEntity, itemInHand, getBaseSeedId());
|
|
+ } else {
|
|
+ super.playerDestroy(world, player, pos, state, blockEntity, itemInHand, includeDrops, dropExp);
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/DoorBlock.java b/src/main/java/net/minecraft/world/level/block/DoorBlock.java
|
|
index 077b99caf0ec0ee098786d23194d88e1dc4481ce..daf865c20cc193a12db0d98e3c0472eefdf635c2 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/DoorBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/DoorBlock.java
|
|
@@ -200,6 +200,7 @@ public class DoorBlock extends Block {
|
|
protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) {
|
|
if (!this.type.canOpenByHand()) {
|
|
return InteractionResult.PASS;
|
|
+ } else if (requiresRedstone(world, state, pos)) { return InteractionResult.CONSUME; // Purpur
|
|
} else {
|
|
state = (BlockState) state.cycle(DoorBlock.OPEN);
|
|
world.setBlock(pos, state, 10);
|
|
@@ -301,4 +302,18 @@ public class DoorBlock extends Block {
|
|
flag = false;
|
|
return flag;
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ public static boolean requiresRedstone(Level level, BlockState state, BlockPos pos) {
|
|
+ if (level.purpurConfig.doorRequiresRedstone.contains(state.getBlock())) {
|
|
+ // force update client
|
|
+ BlockPos otherPos = pos.relative(state.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN);
|
|
+ BlockState otherState = level.getBlockState(otherPos);
|
|
+ level.sendBlockUpdated(pos, state, state, 3);
|
|
+ level.sendBlockUpdated(otherPos, otherState, otherState, 3);
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/DragonEggBlock.java b/src/main/java/net/minecraft/world/level/block/DragonEggBlock.java
|
|
index 30d15686b1a81de7ac28feb0c6188eb007c6f2fd..b6799db00e157892dd4339a01d2ca36092c8e491 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/DragonEggBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/DragonEggBlock.java
|
|
@@ -48,8 +48,8 @@ public class DragonEggBlock extends FallingBlock {
|
|
}
|
|
|
|
private void teleport(BlockState state, Level world, BlockPos pos) {
|
|
+ if (!world.purpurConfig.dragonEggTeleport) return; // Purpur
|
|
WorldBorder worldborder = world.getWorldBorder();
|
|
-
|
|
for (int i = 0; i < 1000; ++i) {
|
|
BlockPos blockposition1 = pos.offset(world.random.nextInt(16) - world.random.nextInt(16), world.random.nextInt(8) - world.random.nextInt(8), world.random.nextInt(16) - world.random.nextInt(16));
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java b/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java
|
|
index a7fb500d950687743d1fc0b3ad3e6d10dcc6e31a..ce6a9e15ae0114623e79b5d8c244c2c490a3f74e 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java
|
|
@@ -123,4 +123,18 @@ public class EnchantingTableBlock extends BaseEntityBlock {
|
|
protected boolean isPathfindable(BlockState state, PathComputationType type) {
|
|
return false;
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean moved) {
|
|
+ BlockEntity blockEntity = level.getBlockEntity(pos);
|
|
+
|
|
+ if (level.purpurConfig.enchantmentTableLapisPersists && blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) {
|
|
+ net.minecraft.world.Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.LAPIS_LAZULI, enchantmentTable.getLapis()));
|
|
+ level.updateNeighbourForOutputSignal(pos, this);
|
|
+ }
|
|
+
|
|
+ super.onRemove(state, level, pos, newState, moved);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java b/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java
|
|
index a7a21f071161fb7e73a046717d2462f871ab653c..abb75f9389167a1f51a2c50831664d50181749de 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java
|
|
@@ -104,6 +104,13 @@ public class EndGatewayBlock extends BaseEntityBlock implements Portal {
|
|
TheEndGatewayBlockEntity tileentityendgateway = (TheEndGatewayBlockEntity) tileentity;
|
|
|
|
if (!tileentityendgateway.isCoolingDown()) {
|
|
+ // Purpur start
|
|
+ if (world.purpurConfig.imposeTeleportRestrictionsOnGateways && (entity.isVehicle() || entity.isPassenger())) {
|
|
+ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, PlayerTeleportEvent.TeleportCause.END_GATEWAY).callEvent()) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
entity.setAsInsidePortal(this, pos);
|
|
TheEndGatewayBlockEntity.triggerCooldown(world, pos, state, tileentityendgateway);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java
|
|
index 4aa14f975e1ceedf3d4a427e0daefb58b12fcafe..2dffc3990d9ae3d595d923239885e3a7d8ec04f3 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java
|
|
@@ -70,6 +70,13 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal {
|
|
protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
|
|
if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent
|
|
if (entity.canUsePortal(false)) {
|
|
+ // Purpur start
|
|
+ if (world.purpurConfig.imposeTeleportRestrictionsOnEndPortals && (entity.isVehicle() || entity.isPassenger())) {
|
|
+ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, PlayerTeleportEvent.TeleportCause.END_PORTAL).callEvent()) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
// CraftBukkit start - Entity in portal
|
|
EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.ENDER); // Paper - add portal type
|
|
world.getCraftServer().getPluginManager().callEvent(event);
|
|
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 ebb9baca7a65173f7c9fdf9bf47a8db876719625..d9a1ec9c6ccab71618a42121f049005cf821eb42 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java
|
|
@@ -88,7 +88,7 @@ public class EnderChestBlock extends AbstractChestBlock<EnderChestBlockEntity> i
|
|
} else {
|
|
// Paper start - Fix InventoryOpenEvent cancellation - moved up;
|
|
if (world instanceof ServerLevel serverLevel && player.openMenu(
|
|
- new SimpleMenuProvider((i, inventory, playerx) -> ChestMenu.threeRows(i, inventory, playerEnderChestContainer), CONTAINER_TITLE)
|
|
+ new SimpleMenuProvider((i, inventory, playerx) -> org.purpurmc.purpur.PurpurConfig.enderChestSixRows ? getEnderChestSixRows(i, inventory, player, playerEnderChestContainer) : ChestMenu.threeRows(i, inventory, playerEnderChestContainer), CONTAINER_TITLE) // Purpur
|
|
).isPresent()) {
|
|
// Paper end - Fix InventoryOpenEvent cancellation - moved up;
|
|
playerEnderChestContainer.setActiveChest(enderChestBlockEntity);
|
|
@@ -104,6 +104,35 @@ public class EnderChestBlock extends AbstractChestBlock<EnderChestBlockEntity> i
|
|
}
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ private ChestMenu getEnderChestSixRows(int syncId, net.minecraft.world.entity.player.Inventory inventory, Player player, PlayerEnderChestContainer playerEnderChestContainer) {
|
|
+ if (org.purpurmc.purpur.PurpurConfig.enderChestPermissionRows) {
|
|
+ org.bukkit.craftbukkit.entity.CraftHumanEntity bukkitPlayer = player.getBukkitEntity();
|
|
+ if (bukkitPlayer.hasPermission("purpur.enderchest.rows.six")) {
|
|
+ player.sixRowEnderchestSlotCount = 54;
|
|
+ return ChestMenu.sixRows(syncId, inventory, playerEnderChestContainer);
|
|
+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.five")) {
|
|
+ player.sixRowEnderchestSlotCount = 45;
|
|
+ return ChestMenu.fiveRows(syncId, inventory, playerEnderChestContainer);
|
|
+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.four")) {
|
|
+ player.sixRowEnderchestSlotCount = 36;
|
|
+ return ChestMenu.fourRows(syncId, inventory, playerEnderChestContainer);
|
|
+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.three")) {
|
|
+ player.sixRowEnderchestSlotCount = 27;
|
|
+ return ChestMenu.threeRows(syncId, inventory, playerEnderChestContainer);
|
|
+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.two")) {
|
|
+ player.sixRowEnderchestSlotCount = 18;
|
|
+ return ChestMenu.twoRows(syncId, inventory, playerEnderChestContainer);
|
|
+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.one")) {
|
|
+ player.sixRowEnderchestSlotCount = 9;
|
|
+ return ChestMenu.oneRow(syncId, inventory, playerEnderChestContainer);
|
|
+ }
|
|
+ }
|
|
+ player.sixRowEnderchestSlotCount = -1;
|
|
+ return ChestMenu.sixRows(syncId, inventory, playerEnderChestContainer);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
|
return new EnderChestBlockEntity(pos, state);
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
|
index c3dba0c2c94f3804338f86621dc42405e380a6b3..6db97982972bfc67c828f574fb86391e1cdcd4a5 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
|
@@ -112,7 +112,7 @@ public class FarmBlock extends Block {
|
|
public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
|
|
super.fallOn(world, state, pos, entity, fallDistance); // CraftBukkit - moved here as game rules / events shouldn't affect fall damage.
|
|
if (world instanceof ServerLevel worldserver) {
|
|
- if (world.random.nextFloat() < fallDistance - 0.5F && entity instanceof LivingEntity && (entity instanceof Player || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) {
|
|
+ if ((worldserver.purpurConfig.farmlandTrampleHeight >= 0D ? fallDistance >= worldserver.purpurConfig.farmlandTrampleHeight : world.random.nextFloat() < fallDistance - 0.5F) && entity instanceof LivingEntity && (entity instanceof Player || worldserver.purpurConfig.farmlandBypassMobGriefing || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) { // Purpur
|
|
// CraftBukkit start - Interact soil
|
|
org.bukkit.event.Cancellable cancellable;
|
|
if (entity instanceof Player) {
|
|
@@ -126,6 +126,22 @@ public class FarmBlock extends Block {
|
|
return;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ if (world.purpurConfig.farmlandTramplingDisabled) return;
|
|
+ if (world.purpurConfig.farmlandTramplingOnlyPlayers && !(entity instanceof Player)) return;
|
|
+ if (world.purpurConfig.farmlandAlpha) {
|
|
+ Block block = world.getBlockState(pos.below()).getBlock();
|
|
+ if (block instanceof FenceBlock || block instanceof WallBlock) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ if (world.purpurConfig.farmlandTramplingFeatherFalling) {
|
|
+ Iterator<net.minecraft.world.item.ItemStack> armor = ((LivingEntity) entity).getArmorSlots().iterator();
|
|
+ if (armor.hasNext() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FEATHER_FALLING, armor.next()) >= (int) entity.fallDistance) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
if (!CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.DIRT.defaultBlockState())) {
|
|
return;
|
|
}
|
|
@@ -174,7 +190,7 @@ public class FarmBlock extends Block {
|
|
}
|
|
}
|
|
|
|
- return false;
|
|
+ return ((ServerLevel) world).purpurConfig.farmlandGetsMoistFromBelow && world.getFluidState(pos.relative(Direction.DOWN)).is(FluidTags.WATER); // Purpur;
|
|
// Paper end - Perf: remove abstract block iteration
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
|
|
index 9b424d7661fedf8ee1eb9f3167c62e563f04d4d1..2af311847a085a8073e9bcb26c762d1bbe1eae2c 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
|
|
@@ -34,12 +34,12 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
|
|
|
|
@Override
|
|
public BlockState getStateForPlacement(RandomSource random) {
|
|
- return (BlockState) this.defaultBlockState().setValue(GrowingPlantHeadBlock.AGE, random.nextInt(25));
|
|
+ return (BlockState) this.defaultBlockState().setValue(GrowingPlantHeadBlock.AGE, random.nextInt(getMaxGrowthAge())); // Purpur
|
|
}
|
|
|
|
@Override
|
|
protected boolean isRandomlyTicking(BlockState state) {
|
|
- return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) < 25;
|
|
+ return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) < getMaxGrowthAge(); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -55,7 +55,7 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
|
|
} else {
|
|
modifier = world.spigotConfig.caveVinesModifier;
|
|
}
|
|
- if ((Integer) state.getValue(GrowingPlantHeadBlock.AGE) < 25 && random.nextDouble() < ((modifier / 100.0D) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution
|
|
+ if ((Integer) state.getValue(GrowingPlantHeadBlock.AGE) < getMaxGrowthAge() && random.nextDouble() < ((modifier / 100.0D) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution // Purpur
|
|
// Spigot end
|
|
BlockPos blockposition1 = pos.relative(this.growthDirection);
|
|
|
|
@@ -77,11 +77,11 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
|
|
}
|
|
|
|
public BlockState getMaxAgeState(BlockState state) {
|
|
- return (BlockState) state.setValue(GrowingPlantHeadBlock.AGE, 25);
|
|
+ return (BlockState) state.setValue(GrowingPlantHeadBlock.AGE, getMaxGrowthAge()); // Purpur
|
|
}
|
|
|
|
public boolean isMaxAge(BlockState state) {
|
|
- return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) == 25;
|
|
+ return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) >= getMaxGrowthAge(); // Purpur
|
|
}
|
|
|
|
protected BlockState updateBodyAfterConvertedFromHead(BlockState from, BlockState to) {
|
|
@@ -123,13 +123,13 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
|
|
@Override
|
|
public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
|
|
BlockPos blockposition1 = pos.relative(this.growthDirection);
|
|
- int i = Math.min((Integer) state.getValue(GrowingPlantHeadBlock.AGE) + 1, 25);
|
|
+ int i = Math.min((Integer) state.getValue(GrowingPlantHeadBlock.AGE) + 1, getMaxGrowthAge()); // Purpur
|
|
int j = this.getBlocksToGrowWhenBonemealed(random);
|
|
|
|
for (int k = 0; k < j && this.canGrowInto(world.getBlockState(blockposition1)); ++k) {
|
|
world.setBlockAndUpdate(blockposition1, (BlockState) state.setValue(GrowingPlantHeadBlock.AGE, i));
|
|
blockposition1 = blockposition1.relative(this.growthDirection);
|
|
- i = Math.min(i + 1, 25);
|
|
+ i = Math.min(i + 1, getMaxGrowthAge()); // Purpur
|
|
}
|
|
|
|
}
|
|
@@ -142,4 +142,6 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
|
|
protected GrowingPlantHeadBlock getHeadBlock() {
|
|
return this;
|
|
}
|
|
+
|
|
+ public abstract int getMaxGrowthAge(); // Purpur
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/HayBlock.java b/src/main/java/net/minecraft/world/level/block/HayBlock.java
|
|
index ef364aa171a48482a45bc18cfe730ec20c3f7be6..74971d90506aa253d5ee821b5390fb2551a3a393 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/HayBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/HayBlock.java
|
|
@@ -23,6 +23,6 @@ public class HayBlock extends RotatedPillarBlock {
|
|
|
|
@Override
|
|
public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
|
|
- entity.causeFallDamage(fallDistance, 0.2F, world.damageSources().fall());
|
|
+ super.fallOn(world, state, pos, entity, fallDistance); // Purpur
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/IceBlock.java b/src/main/java/net/minecraft/world/level/block/IceBlock.java
|
|
index a94762e65853ccad38cf90b0049ca256106c0c9f..38633e168a9b36e37feea00964d53e657926639e 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/IceBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/IceBlock.java
|
|
@@ -42,7 +42,7 @@ public class IceBlock extends HalfTransparentBlock {
|
|
public void afterDestroy(Level world, BlockPos pos, ItemStack tool) {
|
|
// Paper end - Improve Block#breakNaturally API
|
|
if (!EnchantmentHelper.hasTag(tool, EnchantmentTags.PREVENTS_ICE_MELTING)) {
|
|
- if (world.dimensionType().ultraWarm()) {
|
|
+ if (world.isNether() || (world.isTheEnd() && !org.purpurmc.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) { // Purpur
|
|
world.removeBlock(pos, false);
|
|
return;
|
|
}
|
|
@@ -70,7 +70,7 @@ public class IceBlock extends HalfTransparentBlock {
|
|
return;
|
|
}
|
|
// CraftBukkit end
|
|
- if (world.dimensionType().ultraWarm()) {
|
|
+ if (world.isNether() || (world.isTheEnd() && !org.purpurmc.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) { // Purpur
|
|
world.removeBlock(pos, false);
|
|
} else {
|
|
world.setBlockAndUpdate(pos, IceBlock.meltsInto());
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/KelpBlock.java b/src/main/java/net/minecraft/world/level/block/KelpBlock.java
|
|
index 784b19bc78c8ad9476b6dac37b6778a409a7c675..d49dd8b20d3785cc9482ed2a34fbd7aed4c9e537 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/KelpBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/KelpBlock.java
|
|
@@ -72,4 +72,11 @@ public class KelpBlock extends GrowingPlantHeadBlock implements LiquidBlockConta
|
|
protected FluidState getFluidState(BlockState state) {
|
|
return Fluids.WATER.getSource(false);
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public int getMaxGrowthAge() {
|
|
+ return org.purpurmc.purpur.PurpurConfig.kelpMaxGrowthAge;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java
|
|
index a2d023ff011f71f80032f02430a53d6a08a23623..399441dd8388dcdec08768665d3cfa189aca0a95 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java
|
|
@@ -140,7 +140,7 @@ public class LiquidBlock extends Block implements BucketPickup {
|
|
|
|
@Override
|
|
protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
|
|
- if (this.shouldSpreadLiquid(world, pos, state)) {
|
|
+ if (world.purpurConfig.tickFluids && this.shouldSpreadLiquid(world, pos, state)) { // Purpur
|
|
world.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(world, pos)); // Paper - Configurable speed for water flowing over lava
|
|
}
|
|
|
|
@@ -168,7 +168,7 @@ public class LiquidBlock extends Block implements BucketPickup {
|
|
|
|
@Override
|
|
protected BlockState updateShape(BlockState state, LevelReader world, ScheduledTickAccess tickView, BlockPos pos, Direction direction, BlockPos neighborPos, BlockState neighborState, RandomSource random) {
|
|
- if (state.getFluidState().isSource() || neighborState.getFluidState().isSource()) {
|
|
+ if (world.getWorldBorder().world.purpurConfig.tickFluids && state.getFluidState().isSource() || neighborState.getFluidState().isSource()) { // Purpur
|
|
tickView.scheduleTick(pos, state.getFluidState().getType(), this.fluid.getTickDelay(world));
|
|
}
|
|
|
|
@@ -177,7 +177,7 @@ public class LiquidBlock extends Block implements BucketPickup {
|
|
|
|
@Override
|
|
protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, @Nullable Orientation wireOrientation, boolean notify) {
|
|
- if (this.shouldSpreadLiquid(world, pos, state)) {
|
|
+ if (world.purpurConfig.tickFluids && this.shouldSpreadLiquid(world, pos, state)) { // Purpur
|
|
world.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(world, pos)); // Paper - Configurable speed for water flowing over lava
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/MagmaBlock.java b/src/main/java/net/minecraft/world/level/block/MagmaBlock.java
|
|
index 7ffdcf18bf4bd8b5325c76945b2d80ca3fe52958..dfa931316fde0b2e80068a0edd1427ffd096b15b 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/MagmaBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/MagmaBlock.java
|
|
@@ -29,7 +29,7 @@ public class MagmaBlock extends Block {
|
|
|
|
@Override
|
|
public void stepOn(Level world, BlockPos pos, BlockState state, Entity entity) {
|
|
- if (!entity.isSteppingCarefully() && entity instanceof LivingEntity) {
|
|
+ if ((!entity.isSteppingCarefully() || world.purpurConfig.magmaBlockDamageWhenSneaking) && entity instanceof LivingEntity) { // Purpur
|
|
entity.hurt(world.damageSources().hotFloor().directBlock(world, pos), 1.0F); // CraftBukkit
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
|
index 2b31bf586c1c0bd393d2aa8d0b6635dd9f22f21c..02bcba52e28f757b59e2f384d5744834962870f0 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
|
@@ -78,7 +78,7 @@ public class NetherPortalBlock extends Block implements Portal {
|
|
|
|
@Override
|
|
protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
|
- if (world.spigotConfig.enableZombiePigmenPortalSpawns && world.dimensionType().natural() && world.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && random.nextInt(2000) < world.getDifficulty().getId()) { // Spigot
|
|
+ if (world.spigotConfig.enableZombiePigmenPortalSpawns && world.dimensionType().natural() && world.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && random.nextInt(world.purpurConfig.piglinPortalSpawnModifier) < world.getDifficulty().getId()) { // Spigot // Purpur
|
|
while (world.getBlockState(pos).is((Block) this)) {
|
|
pos = pos.below();
|
|
}
|
|
@@ -117,6 +117,13 @@ public class NetherPortalBlock extends Block implements Portal {
|
|
protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
|
|
if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent
|
|
if (entity.canUsePortal(false)) {
|
|
+ // Purpur start
|
|
+ if (world.purpurConfig.imposeTeleportRestrictionsOnNetherPortals && (entity.isVehicle() || entity.isPassenger())) {
|
|
+ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.NETHER_PORTAL).callEvent()) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
// CraftBukkit start - Entity in portal
|
|
EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.NETHER); // Paper - add portal type
|
|
world.getCraftServer().getPluginManager().callEvent(event);
|
|
@@ -130,7 +137,7 @@ public class NetherPortalBlock extends Block implements Portal {
|
|
@Override
|
|
public int getPortalTransitionTime(ServerLevel world, Entity entity) {
|
|
if (entity instanceof Player entityhuman) {
|
|
- return Math.max(0, world.getGameRules().getInt(entityhuman.getAbilities().invulnerable ? GameRules.RULE_PLAYERS_NETHER_PORTAL_CREATIVE_DELAY : GameRules.RULE_PLAYERS_NETHER_PORTAL_DEFAULT_DELAY));
|
|
+ return Math.max(0, entityhuman.canPortalInstant ? 1 : world.getGameRules().getInt(entityhuman.getAbilities().invulnerable ? GameRules.RULE_PLAYERS_NETHER_PORTAL_CREATIVE_DELAY : GameRules.RULE_PLAYERS_NETHER_PORTAL_DEFAULT_DELAY)); // Purpur
|
|
} else {
|
|
return 0;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java b/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java
|
|
index acbd60a2f162fe0e254e36d0e8e7face3fc8a7b3..b8355ea1de26c4b6905f477fb4e110f1762447b4 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java
|
|
@@ -16,7 +16,7 @@ import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
|
|
-public class NetherWartBlock extends BushBlock {
|
|
+public class NetherWartBlock extends BushBlock implements BonemealableBlock { // Purpur
|
|
|
|
public static final MapCodec<NetherWartBlock> CODEC = simpleCodec(NetherWartBlock::new);
|
|
public static final int MAX_AGE = 3;
|
|
@@ -68,4 +68,32 @@ public class NetherWartBlock extends BushBlock {
|
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
|
builder.add(NetherWartBlock.AGE);
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public void playerDestroy(net.minecraft.world.level.Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, ItemStack itemInHand, boolean includeDrops, boolean dropExp) {
|
|
+ if (world.purpurConfig.hoeReplantsNetherWarts && itemInHand.getItem() instanceof net.minecraft.world.item.HoeItem) {
|
|
+ super.playerDestroyAndReplant(world, player, pos, state, blockEntity, itemInHand, Items.NETHER_WART);
|
|
+ } else {
|
|
+ super.playerDestroy(world, player, pos, state, blockEntity, itemInHand, includeDrops, dropExp);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isValidBonemealTarget(final net.minecraft.world.level.LevelReader world, final BlockPos pos, final BlockState state) {
|
|
+ return ((net.minecraft.world.level.Level) world).purpurConfig.netherWartAffectedByBonemeal && state.getValue(NetherWartBlock.AGE) < 3;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isBonemealSuccess(net.minecraft.world.level.Level world, RandomSource random, BlockPos pos, BlockState state) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
|
|
+ int i = Math.min(3, state.getValue(NetherWartBlock.AGE) + 1);
|
|
+ state = state.setValue(NetherWartBlock.AGE, i);
|
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, pos, state, 2); // CraftBukkit
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/NoteBlock.java b/src/main/java/net/minecraft/world/level/block/NoteBlock.java
|
|
index 6582db84c5307257f16c321453491cf24e40c9c7..f9015d4e478efeec8a796b7a897638f76064db20 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/NoteBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/NoteBlock.java
|
|
@@ -97,7 +97,7 @@ public class NoteBlock extends Block {
|
|
}
|
|
|
|
private void playNote(@Nullable Entity entity, BlockState state, Level world, BlockPos pos) {
|
|
- if (((NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT)).worksAboveNoteBlock() || world.getBlockState(pos.above()).isAir()) {
|
|
+ if (world.purpurConfig.noteBlockIgnoreAbove || ((NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT)).worksAboveNoteBlock() || world.getBlockState(pos.above()).isAir()) { // Purpur
|
|
// CraftBukkit start
|
|
// org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, state.getValue(NoteBlock.INSTRUMENT), state.getValue(NoteBlock.NOTE));
|
|
// if (event.isCancelled()) {
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/ObserverBlock.java b/src/main/java/net/minecraft/world/level/block/ObserverBlock.java
|
|
index 93ed9406c34804831b86d006dbd6087db9948f08..26cb9990b91991e0a2eadc2dcbbf229e2e88fb2d 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/ObserverBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/ObserverBlock.java
|
|
@@ -75,6 +75,7 @@ public class ObserverBlock extends DirectionalBlock {
|
|
@Override
|
|
protected BlockState updateShape(BlockState state, LevelReader world, ScheduledTickAccess tickView, BlockPos pos, Direction direction, BlockPos neighborPos, BlockState neighborState, RandomSource random) {
|
|
if (state.getValue(ObserverBlock.FACING) == direction && !(Boolean) state.getValue(ObserverBlock.POWERED)) {
|
|
+ if (!world.getWorldBorder().world.purpurConfig.disableObserverClocks || !(neighborState.getBlock() instanceof ObserverBlock) || neighborState.getValue(ObserverBlock.FACING).getOpposite() != direction) // Purpur
|
|
this.startSignal(world, tickView, pos);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java
|
|
index 53cea36ec931de89e0060613acf87beb51dc16ec..fd5489993dca0f940da69e9163f78e5c2e6ee063 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java
|
|
@@ -194,7 +194,7 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate
|
|
|
|
@VisibleForTesting
|
|
public static void maybeTransferFluid(BlockState state, ServerLevel world, BlockPos pos, float dripChance) {
|
|
- if (dripChance <= 0.17578125F || dripChance <= 0.05859375F) {
|
|
+ if (dripChance <= world.purpurConfig.cauldronDripstoneWaterFillChance || dripChance <= world.purpurConfig.cauldronDripstoneLavaFillChance) { // Purpur
|
|
if (PointedDripstoneBlock.isStalactiteStartPos(state, world, pos)) {
|
|
Optional<PointedDripstoneBlock.FluidInfo> optional = PointedDripstoneBlock.getFluidAboveStalactite(world, pos, state);
|
|
|
|
@@ -203,13 +203,13 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate
|
|
float f1;
|
|
|
|
if (fluidtype == Fluids.WATER) {
|
|
- f1 = 0.17578125F;
|
|
+ f1 = world.purpurConfig.cauldronDripstoneWaterFillChance; // Purpur
|
|
} else {
|
|
if (fluidtype != Fluids.LAVA) {
|
|
return;
|
|
}
|
|
|
|
- f1 = 0.05859375F;
|
|
+ f1 = world.purpurConfig.cauldronDripstoneLavaFillChance; // Purpur
|
|
}
|
|
|
|
if (dripChance < f1) {
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java b/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java
|
|
index 53f1a7ed6b4bd6e2d8460531226aabf249994c02..3e1dddab0500bb805e5accd0ece69c450bad478f 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java
|
|
@@ -76,7 +76,7 @@ public class PowderSnowBlock extends Block implements BucketPickup {
|
|
if (world instanceof ServerLevel worldserver) {
|
|
// CraftBukkit start
|
|
if (entity.isOnFire() && entity.mayInteract(worldserver, pos)) {
|
|
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !(worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) || entity instanceof Player))) {
|
|
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !((worldserver.purpurConfig.powderSnowBypassMobGriefing || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) || entity instanceof Player))) { // Purpur
|
|
return;
|
|
}
|
|
// CraftBukkit end
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java b/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java
|
|
index b763361a8f0f1b46093d5dd9afe8dba0cadf9c78..bd14c08defe8afc5ceca59d16a5b1dbad178f594 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java
|
|
@@ -30,7 +30,7 @@ public class PoweredRailBlock extends BaseRailBlock {
|
|
}
|
|
|
|
protected boolean findPoweredRailSignal(Level world, BlockPos pos, BlockState state, boolean flag, int distance) {
|
|
- if (distance >= 8) {
|
|
+ if (distance >= world.purpurConfig.railActivationRange) { // Purpur
|
|
return false;
|
|
} else {
|
|
int j = pos.getX();
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java b/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java
|
|
index 9117c035d5a6ff114b028fad3380ceb1fc2b9691..2c5e394156dbf76107adb4913a094dfd4a598dd7 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java
|
|
@@ -149,7 +149,7 @@ public class RespawnAnchorBlock extends Block {
|
|
};
|
|
Vec3 vec3d = explodedPos.getCenter();
|
|
|
|
- world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, blockState), explosiondamagecalculator, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); // CraftBukkit - add state
|
|
+ if (world.purpurConfig.respawnAnchorExplode) world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, blockState), explosiondamagecalculator, vec3d, (float) world.purpurConfig.respawnAnchorExplosionPower, world.purpurConfig.respawnAnchorExplosionFire, world.purpurConfig.respawnAnchorExplosionEffect); // CraftBukkit - add state // Purpur
|
|
}
|
|
|
|
public static boolean canSetSpawn(Level world) {
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java b/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java
|
|
index 0e05bfef55dcacb50766bba8328ffeb8a5394c31..e00fcea07e74de647c26ff9eb32bc682738c15b7 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java
|
|
@@ -135,7 +135,7 @@ public class SculkShriekerBlock extends BaseEntityBlock implements SimpleWaterlo
|
|
@Nullable
|
|
@Override
|
|
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
|
|
- return (BlockState) this.defaultBlockState().setValue(SculkShriekerBlock.WATERLOGGED, ctx.getLevel().getFluidState(ctx.getClickedPos()).getType() == Fluids.WATER);
|
|
+ return (BlockState) this.defaultBlockState().setValue(SculkShriekerBlock.WATERLOGGED, ctx.getLevel().getFluidState(ctx.getClickedPos()).getType() == Fluids.WATER).setValue(SculkShriekerBlock.CAN_SUMMON, ctx.getLevel().purpurConfig.sculkShriekerCanSummonDefault); // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/SlabBlock.java b/src/main/java/net/minecraft/world/level/block/SlabBlock.java
|
|
index 9274fd639c22e305dda567b303f9b01068adb52c..4433e432ea0ee8d11045b87e68dac3ed43e8cf82 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/SlabBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/SlabBlock.java
|
|
@@ -150,4 +150,25 @@ public class SlabBlock extends Block implements SimpleWaterloggedBlock {
|
|
return false;
|
|
}
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ public boolean halfBreak(BlockState state, BlockPos pos, net.minecraft.server.level.ServerPlayer player) {
|
|
+ if (state.getValue(SlabBlock.TYPE) != SlabType.DOUBLE) {
|
|
+ return false;
|
|
+ }
|
|
+ net.minecraft.world.phys.HitResult result = player.getRayTrace(16, net.minecraft.world.level.ClipContext.Fluid.NONE);
|
|
+ if (result.getType() != net.minecraft.world.phys.HitResult.Type.BLOCK) {
|
|
+ return false;
|
|
+ }
|
|
+ double hitY = result.getLocation().y();
|
|
+ int blockY = org.bukkit.util.NumberConversions.floor(hitY);
|
|
+ player.level().setBlock(pos, state.setValue(SlabBlock.TYPE, (hitY - blockY > 0.5 || blockY - pos.getY() == 1) ? SlabType.BOTTOM : SlabType.TOP), 3);
|
|
+ if (!player.getAbilities().instabuild) {
|
|
+ net.minecraft.world.entity.item.ItemEntity item = new net.minecraft.world.entity.item.ItemEntity(player.level(), pos.getX(), pos.getY(), pos.getZ(), new ItemStack(asItem()));
|
|
+ item.setDefaultPickUpDelay();
|
|
+ player.level().addFreshEntity(item);
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java b/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java
|
|
index 9908a0b5b1fec5f9de518a733f7abbbff7e1a9f9..0ad444cf7f798f63e9140a42c5d5d8cab0fcf14f 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java
|
|
@@ -88,6 +88,12 @@ public class SnowLayerBlock extends Block {
|
|
protected boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
|
BlockState iblockdata1 = world.getBlockState(pos.below());
|
|
|
|
+ // Purpur start
|
|
+ if (iblockdata1.is(Blocks.BLUE_ICE) && !world.getWorldBorder().world.purpurConfig.snowOnBlueIce) {
|
|
+ return false;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
return iblockdata1.is(BlockTags.SNOW_LAYER_CANNOT_SURVIVE_ON) ? false : (iblockdata1.is(BlockTags.SNOW_LAYER_CAN_SURVIVE_ON) ? true : Block.isFaceFull(iblockdata1.getCollisionShape(world, pos.below()), Direction.UP) || iblockdata1.is((Block) this) && (Integer) iblockdata1.getValue(SnowLayerBlock.LAYERS) == 8);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java b/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java
|
|
index 4f190a40b8474aa06a92c8afcc06d0044120ff7b..80ee7a6f010cc838625674007a3ea908f2f9dadd 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java
|
|
@@ -42,6 +42,57 @@ public class SpawnerBlock extends BaseEntityBlock {
|
|
return createTickerHelper(type, BlockEntityType.MOB_SPAWNER, world.isClientSide ? SpawnerBlockEntity::clientTick : SpawnerBlockEntity::serverTick);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public void playerDestroy(Level level, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack, boolean includeDrops, boolean dropExp) {
|
|
+ if (level.purpurConfig.silkTouchEnabled && player.getBukkitEntity().hasPermission("purpur.drop.spawners") && isSilkTouch(level, stack)) {
|
|
+ ItemStack item = new ItemStack(Blocks.SPAWNER.asItem());
|
|
+
|
|
+ net.minecraft.world.level.SpawnData nextSpawnData = blockEntity instanceof SpawnerBlockEntity spawnerBlock ? spawnerBlock.getSpawner().nextSpawnData : null;
|
|
+ java.util.Optional<net.minecraft.world.entity.EntityType<?>> type = java.util.Optional.empty();
|
|
+ if (nextSpawnData != null) {
|
|
+ type = net.minecraft.world.entity.EntityType.by(nextSpawnData.getEntityToSpawn());
|
|
+ net.minecraft.world.level.SpawnData.CODEC.encodeStart(net.minecraft.nbt.NbtOps.INSTANCE, nextSpawnData).result().ifPresent(tag -> item.set(net.minecraft.core.component.DataComponents.CUSTOM_DATA, net.minecraft.world.item.component.CustomData.EMPTY.update(compoundTag -> compoundTag.put("Purpur.SpawnData", tag))));
|
|
+ }
|
|
+
|
|
+ if (type.isPresent()) {
|
|
+ final net.kyori.adventure.text.Component mobName = io.papermc.paper.adventure.PaperAdventure.asAdventure(type.get().getDescription());
|
|
+
|
|
+ String name = level.purpurConfig.silkTouchSpawnerName;
|
|
+ if (name != null && !name.isEmpty() && !name.equals("Monster Spawner")) {
|
|
+ net.kyori.adventure.text.Component displayName = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(name, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("mob", mobName));
|
|
+ if (name.startsWith("<reset>")) {
|
|
+ displayName = displayName.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false);
|
|
+ }
|
|
+ item.set(net.minecraft.core.component.DataComponents.CUSTOM_NAME, io.papermc.paper.adventure.PaperAdventure.asVanilla(displayName));
|
|
+ }
|
|
+
|
|
+ List<String> lore = level.purpurConfig.silkTouchSpawnerLore;
|
|
+ if (lore != null && !lore.isEmpty()) {
|
|
+
|
|
+ List<Component> loreComponentList = new java.util.ArrayList<>();
|
|
+ for (String line : lore) {
|
|
+ net.kyori.adventure.text.Component lineComponent = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(line, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("mob", mobName));
|
|
+ if (line.startsWith("<reset>")) {
|
|
+ lineComponent = lineComponent.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false);
|
|
+ }
|
|
+ loreComponentList.add(io.papermc.paper.adventure.PaperAdventure.asVanilla(lineComponent));
|
|
+ }
|
|
+
|
|
+ item.set(net.minecraft.core.component.DataComponents.LORE, new net.minecraft.world.item.component.ItemLore(loreComponentList, loreComponentList));
|
|
+ }
|
|
+ item.set(net.minecraft.core.component.DataComponents.HIDE_ADDITIONAL_TOOLTIP, net.minecraft.util.Unit.INSTANCE);
|
|
+ }
|
|
+ popResource(level, pos, item);
|
|
+ }
|
|
+ super.playerDestroy(level, player, pos, state, blockEntity, stack, includeDrops, dropExp);
|
|
+ }
|
|
+
|
|
+ private boolean isSilkTouch(Level level, ItemStack stack) {
|
|
+ return stack != null && level.purpurConfig.silkTouchTools.contains(stack.getItem()) && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.SILK_TOUCH, stack) >= level.purpurConfig.minimumSilkTouchSpawnerRequire;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected void spawnAfterBreak(BlockState state, ServerLevel world, BlockPos pos, ItemStack tool, boolean dropExperience) {
|
|
super.spawnAfterBreak(state, world, pos, tool, dropExperience);
|
|
@@ -50,6 +101,7 @@ public class SpawnerBlock extends BaseEntityBlock {
|
|
|
|
@Override
|
|
public int getExpDrop(BlockState iblockdata, ServerLevel worldserver, BlockPos blockposition, ItemStack itemstack, boolean flag) {
|
|
+ if (worldserver.purpurConfig.silkTouchEnabled && isSilkTouch(worldserver, itemstack)) return 0; // Purpur
|
|
if (flag) {
|
|
int i = 15 + worldserver.random.nextInt(15) + worldserver.random.nextInt(15);
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/SpongeBlock.java b/src/main/java/net/minecraft/world/level/block/SpongeBlock.java
|
|
index 59cf905b1b5686f6f4f2bad94730ffa69d3a2834..4c5bc71fef307d13b640e534ace0b4411f6e97e2 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/SpongeBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/SpongeBlock.java
|
|
@@ -61,7 +61,7 @@ public class SpongeBlock extends Block {
|
|
|
|
private boolean removeWaterBreadthFirstSearch(Level world, BlockPos pos) {
|
|
BlockStateListPopulator blockList = new BlockStateListPopulator(world); // CraftBukkit - Use BlockStateListPopulator
|
|
- BlockPos.breadthFirstTraversal(pos, 6, 65, (blockposition1, consumer) -> {
|
|
+ BlockPos.breadthFirstTraversal(pos, world.purpurConfig.spongeAbsorptionRadius, world.purpurConfig.spongeAbsorptionArea, (blockposition1, consumer) -> { // Purpur
|
|
Direction[] aenumdirection = SpongeBlock.ALL_DIRECTIONS;
|
|
int i = aenumdirection.length;
|
|
|
|
@@ -80,7 +80,7 @@ public class SpongeBlock extends Block {
|
|
FluidState fluid = blockList.getFluidState(blockposition1);
|
|
// CraftBukkit end
|
|
|
|
- if (!fluid.is(FluidTags.WATER)) {
|
|
+ if (!fluid.is(FluidTags.WATER) && (!world.purpurConfig.spongeAbsorbsLava || !fluid.is(FluidTags.LAVA)) && (!world.purpurConfig.spongeAbsorbsWaterFromMud || !iblockdata.is(Blocks.MUD))) { // Purpur
|
|
return false;
|
|
} else {
|
|
Block block = iblockdata.getBlock();
|
|
@@ -95,6 +95,10 @@ public class SpongeBlock extends Block {
|
|
|
|
if (iblockdata.getBlock() instanceof LiquidBlock) {
|
|
blockList.setBlock(blockposition1, Blocks.AIR.defaultBlockState(), 3); // CraftBukkit
|
|
+ // Purpur start
|
|
+ } else if (iblockdata.is(Blocks.MUD)) {
|
|
+ blockList.setBlock(blockposition1, Blocks.CLAY.defaultBlockState(), 3);
|
|
+ // Purpur end
|
|
} else {
|
|
if (!iblockdata.is(Blocks.KELP) && !iblockdata.is(Blocks.KELP_PLANT) && !iblockdata.is(Blocks.SEAGRASS) && !iblockdata.is(Blocks.TALL_SEAGRASS)) {
|
|
return false;
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java b/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java
|
|
index e61644241f24b42bb4f702d3eef5b590b4d107c8..0bf6503819b02e5ba2c346d9d563a93f2946d89b 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java
|
|
@@ -98,4 +98,14 @@ public class StonecutterBlock extends Block {
|
|
protected boolean isPathfindable(BlockState state, PathComputationType type) {
|
|
return false;
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public void stepOn(Level level, BlockPos pos, BlockState state, net.minecraft.world.entity.Entity entity) {
|
|
+ if (level.purpurConfig.stonecutterDamage > 0.0F && entity instanceof net.minecraft.world.entity.LivingEntity) {
|
|
+ entity.hurt(entity.damageSources().stonecutter().directBlock(level, pos), level.purpurConfig.stonecutterDamage);
|
|
+ }
|
|
+ super.stepOn(level, pos, state, entity);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
|
|
index 547ea09ed84595286c97c128b3b96f6d387ae25f..d0f8a13f27132257ece6dadf736c2dc6b1e5720e 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
|
|
@@ -20,7 +20,7 @@ import net.minecraft.world.level.material.FluidState;
|
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
|
|
-public class SugarCaneBlock extends Block {
|
|
+public class SugarCaneBlock extends Block implements BonemealableBlock { // Purpur
|
|
|
|
public static final MapCodec<SugarCaneBlock> CODEC = simpleCodec(SugarCaneBlock::new);
|
|
public static final IntegerProperty AGE = BlockStateProperties.AGE_15;
|
|
@@ -113,4 +113,34 @@ public class SugarCaneBlock extends Block {
|
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
|
builder.add(SugarCaneBlock.AGE);
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isValidBonemealTarget(final LevelReader world, final BlockPos pos, final BlockState state) {
|
|
+ if (!((net.minecraft.world.level.Level) world).purpurConfig.sugarCanAffectedByBonemeal || !world.isEmptyBlock(pos.above())) return false;
|
|
+
|
|
+ int reedHeight = 0;
|
|
+ while (world.getBlockState(pos.below(reedHeight)).is(this)) {
|
|
+ reedHeight++;
|
|
+ }
|
|
+
|
|
+ return reedHeight < ((net.minecraft.world.level.Level) world).paperConfig().maxGrowthHeight.reeds;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isBonemealSuccess(net.minecraft.world.level.Level world, RandomSource random, BlockPos pos, BlockState state) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
|
|
+ int reedHeight = 0;
|
|
+ while (world.getBlockState(pos.below(reedHeight)).is(this)) {
|
|
+ reedHeight++;
|
|
+ }
|
|
+ for (int i = 0; i <= world.paperConfig().maxGrowthHeight.reeds - reedHeight; i++) {
|
|
+ world.setBlockAndUpdate(pos.above(i), state.setValue(SugarCaneBlock.AGE, 0));
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
|
|
index 953ddb2ea6fd48e57712e30a6addf23e188e5312..3829dbae8542396f8360eae54f0ed18fbde4cd8c 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
|
|
@@ -171,7 +171,7 @@ public class TurtleEggBlock extends Block {
|
|
private boolean shouldUpdateHatchLevel(Level world) {
|
|
float f = world.getTimeOfDay(1.0F);
|
|
|
|
- return (double) f < 0.69D && (double) f > 0.65D ? true : world.random.nextInt(500) == 0;
|
|
+ return (double) f < 0.69D && (double) f > 0.65D ? true : world.random.nextInt(world.purpurConfig.turtleEggsRandomTickCrackChance) == 0;
|
|
}
|
|
|
|
@Override
|
|
@@ -204,6 +204,31 @@ public class TurtleEggBlock extends Block {
|
|
}
|
|
|
|
private boolean canDestroyEgg(ServerLevel world, Entity entity) {
|
|
- return !(entity instanceof Turtle) && !(entity instanceof Bat) ? (!(entity instanceof LivingEntity) ? false : entity instanceof Player || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) : false;
|
|
+ // Purpur start
|
|
+ if (entity instanceof Turtle || entity instanceof Bat) {
|
|
+ return false;
|
|
+ }
|
|
+ if (world.purpurConfig.turtleEggsBreakFromExpOrbs && entity instanceof net.minecraft.world.entity.ExperienceOrb) {
|
|
+ return true;
|
|
+ }
|
|
+ if (world.purpurConfig.turtleEggsBreakFromItems && entity instanceof net.minecraft.world.entity.item.ItemEntity) {
|
|
+ return true;
|
|
+ }
|
|
+ if (world.purpurConfig.turtleEggsBreakFromMinecarts && entity instanceof net.minecraft.world.entity.vehicle.AbstractMinecart) {
|
|
+ return true;
|
|
+ }
|
|
+ if (!(entity instanceof LivingEntity)) {
|
|
+ return false;
|
|
+ }
|
|
+ if (world.purpurConfig.turtleEggsTramplingFeatherFalling) {
|
|
+ java.util.Iterator<ItemStack> armor = ((LivingEntity) entity).getArmorSlots().iterator();
|
|
+ return !armor.hasNext() || net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FEATHER_FALLING, armor.next()) < (int) entity.fallDistance;
|
|
+ }
|
|
+ if (entity instanceof Player) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return world.purpurConfig.turtleEggsBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
|
|
+ // Purpur end
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/TwistingVinesBlock.java b/src/main/java/net/minecraft/world/level/block/TwistingVinesBlock.java
|
|
index 6342bb11a162b9e6d9475c5989b1670d77e8f0fb..f8be92512446d3f0e5f0f21222bbefd04ab2838a 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/TwistingVinesBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/TwistingVinesBlock.java
|
|
@@ -34,4 +34,11 @@ public class TwistingVinesBlock extends GrowingPlantHeadBlock {
|
|
protected boolean canGrowInto(BlockState state) {
|
|
return NetherVines.isValidGrowthState(state);
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public int getMaxGrowthAge() {
|
|
+ return org.purpurmc.purpur.PurpurConfig.twistingVinesMaxGrowthAge;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/WeepingVinesBlock.java b/src/main/java/net/minecraft/world/level/block/WeepingVinesBlock.java
|
|
index 3dec5a082606ee35a8c8d7f746480262d6a189c5..b2f6ccae9576c176263e51a232e17a08d54543b3 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/WeepingVinesBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/WeepingVinesBlock.java
|
|
@@ -34,4 +34,11 @@ public class WeepingVinesBlock extends GrowingPlantHeadBlock {
|
|
protected boolean canGrowInto(BlockState state) {
|
|
return NetherVines.isValidGrowthState(state);
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public int getMaxGrowthAge() {
|
|
+ return org.purpurmc.purpur.PurpurConfig.weepingVinesMaxGrowthAge;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java b/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java
|
|
index 0fbe66cc02bd3d95c0a5dcd55380a1b4a2f17ca6..3a7126883f11ac5a647947eaf060df15536a6cb2 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java
|
|
@@ -80,6 +80,7 @@ public class WitherSkullBlock extends SkullBlock {
|
|
entitywither.moveTo((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.55D, (double) blockposition1.getZ() + 0.5D, shapedetector_shapedetectorcollection.getForwards().getAxis() == Direction.Axis.X ? 0.0F : 90.0F, 0.0F);
|
|
entitywither.yBodyRot = shapedetector_shapedetectorcollection.getForwards().getAxis() == Direction.Axis.X ? 0.0F : 90.0F;
|
|
entitywither.makeInvulnerable();
|
|
+ entitywither.setSummoner(iblockdata.getBlock().placer == null ? null : iblockdata.getBlock().placer.getUUID()); // Purpur
|
|
// CraftBukkit start
|
|
if (!world.addFreshEntity(entitywither, SpawnReason.BUILD_WITHER)) {
|
|
return;
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
|
index 15e0861486a2bda3e2f4049b1b5a299c870acd31..91a158ed90b7ce3eac7277fd962682a0226c08ed 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
|
@@ -219,6 +219,21 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
|
|
}
|
|
|
|
ItemStack itemstack = (ItemStack) blockEntity.items.get(1);
|
|
+ // Purpur start
|
|
+ boolean usedLavaFromUnderneath = false;
|
|
+ if (world.purpurConfig.furnaceUseLavaFromUnderneath && !blockEntity.isLit() && itemstack.isEmpty() && !blockEntity.items.get(0).isEmpty() && world.getGameTime() % 20 == 0) {
|
|
+ BlockPos below = blockEntity.getBlockPos().below();
|
|
+ BlockState belowState = world.getBlockStateIfLoaded(below);
|
|
+ if (belowState != null && belowState.is(Blocks.LAVA)) {
|
|
+ net.minecraft.world.level.material.FluidState fluidState = belowState.getFluidState();
|
|
+ if (fluidState != null && fluidState.isSource()) {
|
|
+ world.setBlock(below, Blocks.AIR.defaultBlockState(), 3);
|
|
+ itemstack = Items.LAVA_BUCKET.getDefaultInstance();
|
|
+ usedLavaFromUnderneath = true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
ItemStack itemstack1 = (ItemStack) blockEntity.items.get(0);
|
|
boolean flag2 = !itemstack1.isEmpty();
|
|
boolean flag3 = !itemstack.isEmpty();
|
|
@@ -308,6 +323,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
|
|
setChanged(world, pos, state);
|
|
}
|
|
|
|
+ if (usedLavaFromUnderneath) blockEntity.items.set(1, ItemStack.EMPTY); // Purpur
|
|
}
|
|
|
|
private static boolean canBurn(RegistryAccess dynamicRegistryManager, @Nullable RecipeHolder<? extends AbstractCookingRecipe> recipe, SingleRecipeInput input, NonNullList<ItemStack> inventory, int maxCount) {
|
|
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 618552afbdacc919c33b30a6bf4834fb71ab3d5b..7a059d20abdcc0073a314311d78f63ae4bd0365e 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
|
|
@@ -68,7 +68,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
|
|
|
|
public BarrelBlockEntity(BlockPos pos, BlockState state) {
|
|
super(BlockEntityType.BARREL, pos, state);
|
|
- this.items = NonNullList.withSize(27, ItemStack.EMPTY);
|
|
+ // Purpur start
|
|
+ this.items = NonNullList.withSize(switch (org.purpurmc.purpur.PurpurConfig.barrelRows) {
|
|
+ case 6 -> 54;
|
|
+ case 5 -> 45;
|
|
+ case 4 -> 36;
|
|
+ case 2 -> 18;
|
|
+ case 1 -> 9;
|
|
+ default -> 27;
|
|
+ }, ItemStack.EMPTY);
|
|
+ // Purpur end
|
|
this.openersCounter = new ContainerOpenersCounter() {
|
|
@Override
|
|
protected void onOpen(Level world, BlockPos pos, BlockState state) {
|
|
@@ -119,7 +128,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
|
|
|
|
@Override
|
|
public int getContainerSize() {
|
|
- return 27;
|
|
+ // Purpur start
|
|
+ return switch (org.purpurmc.purpur.PurpurConfig.barrelRows) {
|
|
+ case 6 -> 54;
|
|
+ case 5 -> 45;
|
|
+ case 4 -> 36;
|
|
+ case 2 -> 18;
|
|
+ case 1 -> 9;
|
|
+ default -> 27;
|
|
+ };
|
|
+ // Purpur end
|
|
}
|
|
|
|
@Override
|
|
@@ -139,7 +157,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
|
|
|
|
@Override
|
|
protected AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) {
|
|
- return ChestMenu.threeRows(syncId, playerInventory, this);
|
|
+ // Purpur start
|
|
+ return switch (org.purpurmc.purpur.PurpurConfig.barrelRows) {
|
|
+ case 6 -> ChestMenu.sixRows(syncId, playerInventory, this);
|
|
+ case 5 -> ChestMenu.fiveRows(syncId, playerInventory, this);
|
|
+ case 4 -> ChestMenu.fourRows(syncId, playerInventory, this);
|
|
+ case 2 -> ChestMenu.twoRows(syncId, playerInventory, this);
|
|
+ case 1 -> ChestMenu.oneRow(syncId, playerInventory, this);
|
|
+ default -> ChestMenu.threeRows(syncId, playerInventory, this);
|
|
+ };
|
|
+ // Purpur end
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
|
|
index 0e0d178f2793ab014358f534c8dc53218b89f083..2d190b3a6378b8cbadfa65510df1ccfbd5882ef8 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
|
|
@@ -92,6 +92,16 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name
|
|
|
|
public double getEffectRange() {
|
|
if (this.effectRange < 0) {
|
|
+ // Purpur Start
|
|
+ if (this.level != null) {
|
|
+ switch (this.levels) {
|
|
+ case 1: return this.level.purpurConfig.beaconLevelOne;
|
|
+ case 2: return this.level.purpurConfig.beaconLevelTwo;
|
|
+ case 3: return this.level.purpurConfig.beaconLevelThree;
|
|
+ case 4: return this.level.purpurConfig.beaconLevelFour;
|
|
+ }
|
|
+ }
|
|
+ // Purpur End
|
|
return this.levels * 10 + 10;
|
|
} else {
|
|
return effectRange;
|
|
@@ -168,6 +178,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name
|
|
int j = pos.getY();
|
|
int k = pos.getZ();
|
|
BlockPos blockposition1;
|
|
+ boolean isTintedGlass = false;
|
|
|
|
if (blockEntity.lastCheckY < j) {
|
|
blockposition1 = pos;
|
|
@@ -201,6 +212,9 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name
|
|
}
|
|
}
|
|
} else {
|
|
+ if (world.purpurConfig.beaconAllowEffectsWithTintedGlass && block.equals(Blocks.TINTED_GLASS)) {
|
|
+ isTintedGlass = true;
|
|
+ }
|
|
if (tileentitybeacon_beaconcolortracker == null || iblockdata1.getLightBlock() >= 15 && !iblockdata1.is(Blocks.BEDROCK)) {
|
|
blockEntity.checkingBeamSections.clear();
|
|
blockEntity.lastCheckY = l;
|
|
@@ -220,7 +234,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name
|
|
blockEntity.levels = BeaconBlockEntity.updateBase(world, i, j, k);
|
|
}
|
|
|
|
- if (blockEntity.levels > 0 && !blockEntity.beamSections.isEmpty()) {
|
|
+ if (blockEntity.levels > 0 && (!blockEntity.beamSections.isEmpty() || (world.purpurConfig.beaconAllowEffectsWithTintedGlass && isTintedGlass))) {
|
|
BeaconBlockEntity.applyEffects(world, pos, blockEntity.levels, blockEntity.primaryPower, blockEntity.secondaryPower, blockEntity); // Paper - Custom beacon ranges
|
|
BeaconBlockEntity.playSound(world, pos, SoundEvents.BEACON_AMBIENT);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
|
|
index 83ad45aed0894e90825d22e078632352c3a06816..def408384cbd571b7bee23f5cecf430a5d690c4b 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
|
|
@@ -60,7 +60,7 @@ public class BeehiveBlockEntity extends BlockEntity {
|
|
private List<BeehiveBlockEntity.BeeData> stored = Lists.newArrayList();
|
|
@Nullable
|
|
public BlockPos savedFlowerPos;
|
|
- public int maxBees = 3; // CraftBukkit - allow setting max amount of bees a hive can hold
|
|
+ public int maxBees = org.purpurmc.purpur.PurpurConfig.beeInsideBeeHive; // CraftBukkit - allow setting max amount of bees a hive can hold // Purpur
|
|
|
|
public BeehiveBlockEntity(BlockPos pos, BlockState state) {
|
|
super(BlockEntityType.BEEHIVE, pos, state);
|
|
@@ -147,11 +147,33 @@ public class BeehiveBlockEntity extends BlockEntity {
|
|
return list;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public List<Entity> releaseBee(BlockState iblockdata, BeehiveBlockEntity.BeeData data, BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus, boolean force) {
|
|
+ List<Entity> list = Lists.newArrayList();
|
|
+
|
|
+ BeehiveBlockEntity.releaseOccupant(this.level, this.worldPosition, iblockdata, data.occupant, list, tileentitybeehive_releasestatus, this.savedFlowerPos, force);
|
|
+
|
|
+ if (!list.isEmpty()) {
|
|
+ stored.remove(data);
|
|
+
|
|
+ super.setChanged();
|
|
+ }
|
|
+
|
|
+ return list;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@VisibleForDebug
|
|
public int getOccupantCount() {
|
|
return this.stored.size();
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public List<BeeData> getStored() {
|
|
+ return stored;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
// Paper start - Add EntityBlockStorage clearEntities
|
|
public void clearBees() {
|
|
this.stored.clear();
|
|
@@ -472,9 +494,9 @@ public class BeehiveBlockEntity extends BlockEntity {
|
|
}
|
|
}
|
|
|
|
- private static class BeeData {
|
|
+ public static class BeeData { // Purpur - change from private to public
|
|
|
|
- private final BeehiveBlockEntity.Occupant occupant;
|
|
+ public final BeehiveBlockEntity.Occupant occupant; // Purpur - make public
|
|
private int exitTickCounter; // Paper - Fix bees aging inside hives; separate counter for checking if bee should exit to reduce exit attempts
|
|
private int ticksInHive;
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
|
index 1f929b467a0ece3143af58a657cf5983c07a8d51..eaa6ece956f90632831f0558924eaf18680a252b 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
|
@@ -95,6 +95,12 @@ public abstract class BlockEntity {
|
|
if (persistentDataTag instanceof CompoundTag) {
|
|
this.persistentDataContainer.putAll((CompoundTag) persistentDataTag);
|
|
}
|
|
+ // Purpur start
|
|
+ if (nbt.contains("Purpur.persistentLore")) {
|
|
+ net.minecraft.world.item.component.ItemLore.CODEC.decode(net.minecraft.nbt.NbtOps.INSTANCE, nbt.getCompound("Purpur.persistentLore")).result()
|
|
+ .ifPresent(tag -> this.persistentLore = tag.getFirst());
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
// CraftBukkit end
|
|
|
|
@@ -111,6 +117,15 @@ public abstract class BlockEntity {
|
|
this.loadAdditional(nbt, registries);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ protected void saveAdditional(CompoundTag nbt) {
|
|
+ if (this.persistentLore != null) {
|
|
+ net.minecraft.world.item.component.ItemLore.CODEC.encodeStart(net.minecraft.nbt.NbtOps.INSTANCE, this.persistentLore).result()
|
|
+ .ifPresent(tag -> nbt.put("Purpur.persistentLore", tag));
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
protected void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) {}
|
|
|
|
public final CompoundTag saveWithFullMetadata(HolderLookup.Provider registries) {
|
|
@@ -419,4 +434,16 @@ public abstract class BlockEntity {
|
|
|
|
<T> T getOrDefault(DataComponentType<? extends T> type, T fallback);
|
|
}
|
|
+ // Purpur start
|
|
+ @Nullable
|
|
+ private net.minecraft.world.item.component.ItemLore persistentLore = null;
|
|
+
|
|
+ public void setPersistentLore(net.minecraft.world.item.component.ItemLore lore) {
|
|
+ this.persistentLore = lore;
|
|
+ }
|
|
+
|
|
+ public @org.jetbrains.annotations.Nullable net.minecraft.world.item.component.ItemLore getPersistentLore() {
|
|
+ return this.persistentLore;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java
|
|
index d354c2ad41533ec8d52f7c5f63f8f74a0b1ce235..a43c41a26c1e34a2f4eda1c498a562664a783c77 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java
|
|
@@ -169,7 +169,7 @@ public class ConduitBlockEntity extends BlockEntity {
|
|
if ((l > 1 || i1 > 1 || j1 > 1) && (i == 0 && (i1 == 2 || j1 == 2) || j == 0 && (l == 2 || j1 == 2) || k == 0 && (l == 2 || i1 == 2))) {
|
|
BlockPos blockposition2 = pos.offset(i, j, k);
|
|
BlockState iblockdata = world.getBlockState(blockposition2);
|
|
- Block[] ablock = ConduitBlockEntity.VALID_BLOCKS;
|
|
+ Block[] ablock = world.purpurConfig.conduitBlocks; // Purpur
|
|
int k1 = ablock.length;
|
|
|
|
for (int l1 = 0; l1 < k1; ++l1) {
|
|
@@ -189,13 +189,13 @@ public class ConduitBlockEntity extends BlockEntity {
|
|
|
|
private static void applyEffects(Level world, BlockPos pos, List<BlockPos> activatingBlocks) {
|
|
// CraftBukkit start
|
|
- ConduitBlockEntity.applyEffects(world, pos, ConduitBlockEntity.getRange(activatingBlocks));
|
|
+ ConduitBlockEntity.applyEffects(world, pos, ConduitBlockEntity.getRange(activatingBlocks, world)); // Purpur
|
|
}
|
|
|
|
- public static int getRange(List<BlockPos> list) {
|
|
+ public static int getRange(List<BlockPos> list, Level world) { // Purpur
|
|
// CraftBukkit end
|
|
int i = list.size();
|
|
- int j = i / 7 * 16;
|
|
+ int j = i / 7 * world.purpurConfig.conduitDistance; // Purpur
|
|
// CraftBukkit start
|
|
return j;
|
|
}
|
|
@@ -238,20 +238,20 @@ public class ConduitBlockEntity extends BlockEntity {
|
|
tileentityconduit.destroyTarget = ConduitBlockEntity.findDestroyTarget(world, blockposition, tileentityconduit.destroyTargetUUID);
|
|
tileentityconduit.destroyTargetUUID = null;
|
|
} else if (tileentityconduit.destroyTarget == null) {
|
|
- List<LivingEntity> list1 = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(blockposition), (entityliving1) -> {
|
|
+ List<LivingEntity> list1 = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(blockposition, world), (entityliving1) -> { // Purpur
|
|
return entityliving1 instanceof Enemy && entityliving1.isInWaterOrRain();
|
|
});
|
|
|
|
if (!list1.isEmpty()) {
|
|
tileentityconduit.destroyTarget = (LivingEntity) list1.get(world.random.nextInt(list1.size()));
|
|
}
|
|
- } else if (!tileentityconduit.destroyTarget.isAlive() || !blockposition.closerThan(tileentityconduit.destroyTarget.blockPosition(), 8.0D)) {
|
|
+ } else if (!tileentityconduit.destroyTarget.isAlive() || !blockposition.closerThan(tileentityconduit.destroyTarget.blockPosition(), world.purpurConfig.conduitDamageDistance)) { // Purpur
|
|
tileentityconduit.destroyTarget = null;
|
|
}
|
|
|
|
// CraftBukkit start
|
|
if (damageTarget && tileentityconduit.destroyTarget != null) {
|
|
- if (tileentityconduit.destroyTarget.hurtServer((ServerLevel) world, world.damageSources().magic().directBlock(world, blockposition), 4.0F)) {
|
|
+ if (tileentityconduit.destroyTarget.hurtServer((ServerLevel) world, world.damageSources().magic().directBlock(world, blockposition), world.purpurConfig.conduitDamageAmount)) { // Purpur
|
|
world.playSound(null, tileentityconduit.destroyTarget.getX(), tileentityconduit.destroyTarget.getY(), tileentityconduit.destroyTarget.getZ(), SoundEvents.CONDUIT_ATTACK_TARGET, SoundSource.BLOCKS, 1.0F, 1.0F);
|
|
}
|
|
// CraftBukkit end
|
|
@@ -276,16 +276,22 @@ public class ConduitBlockEntity extends BlockEntity {
|
|
}
|
|
|
|
public static AABB getDestroyRangeAABB(BlockPos pos) {
|
|
+ // Purpur start
|
|
+ return getDestroyRangeAABB(pos, null);
|
|
+ }
|
|
+
|
|
+ private static AABB getDestroyRangeAABB(BlockPos pos, Level level) {
|
|
+ // Purpur end
|
|
int i = pos.getX();
|
|
int j = pos.getY();
|
|
int k = pos.getZ();
|
|
|
|
- return (new AABB((double) i, (double) j, (double) k, (double) (i + 1), (double) (j + 1), (double) (k + 1))).inflate(8.0D);
|
|
+ return (new AABB((double) i, (double) j, (double) k, (double) (i + 1), (double) (j + 1), (double) (k + 1))).inflate(level == null ? 8.0D : level.purpurConfig.conduitDamageDistance); // Purpur
|
|
}
|
|
|
|
@Nullable
|
|
private static LivingEntity findDestroyTarget(Level world, BlockPos pos, UUID uuid) {
|
|
- List<LivingEntity> list = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(pos), (entityliving) -> {
|
|
+ List<LivingEntity> list = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(pos, world), (entityliving) -> { // Purpur
|
|
return entityliving.getUUID().equals(uuid);
|
|
});
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java
|
|
index 39aac959775afeaeea211f21d498cb0ddf0a3fcb..6349a342c023f378af431a73a62fb017882e257d 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java
|
|
@@ -28,6 +28,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable
|
|
private static final RandomSource RANDOM = RandomSource.create();
|
|
@Nullable
|
|
private Component name;
|
|
+ private int lapis = 0; // Purpur
|
|
|
|
public EnchantingTableBlockEntity(BlockPos pos, BlockState state) {
|
|
super(BlockEntityType.ENCHANTING_TABLE, pos, state);
|
|
@@ -39,6 +40,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable
|
|
if (this.hasCustomName()) {
|
|
nbt.putString("CustomName", Component.Serializer.toJson(this.name, registries));
|
|
}
|
|
+ nbt.putInt("Purpur.Lapis", this.lapis); // Purpur
|
|
}
|
|
|
|
@Override
|
|
@@ -47,6 +49,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable
|
|
if (nbt.contains("CustomName", 8)) {
|
|
this.name = parseCustomNameSafe(nbt.getString("CustomName"), registries);
|
|
}
|
|
+ this.lapis = nbt.getInt("Purpur.Lapis"); // Purpur
|
|
}
|
|
|
|
public static void bookAnimationTick(Level world, BlockPos pos, BlockState state, EnchantingTableBlockEntity blockEntity) {
|
|
@@ -138,4 +141,14 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable
|
|
public void removeComponentsFromTag(CompoundTag nbt) {
|
|
nbt.remove("CustomName");
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ public int getLapis() {
|
|
+ return this.lapis;
|
|
+ }
|
|
+
|
|
+ public void setLapis(int lapis) {
|
|
+ this.lapis = lapis;
|
|
+ }
|
|
+ // Purpur
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/FuelValues.java b/src/main/java/net/minecraft/world/level/block/entity/FuelValues.java
|
|
index 61ef08ac941b1e8988d001241780d3a1582f7a2d..2eab5b43ab654966d26424597c1f3baa919e8434 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/entity/FuelValues.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/FuelValues.java
|
|
@@ -17,7 +17,7 @@ import net.minecraft.world.level.ItemLike;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
|
|
public class FuelValues {
|
|
- private final Object2IntSortedMap<Item> values;
|
|
+ public final Object2IntSortedMap<Item> values; // Purpur - private -> public
|
|
|
|
FuelValues(Object2IntSortedMap<Item> fuelValues) {
|
|
this.values = fuelValues;
|
|
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 8ac19e1e052e73ff3fd09089bb8e3fd687390ee4..6da1eec98c08e4909ecbd48fe90b3fd62011e284 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
|
|
@@ -201,16 +201,31 @@ public class SignBlockEntity extends BlockEntity {
|
|
return this.setText((SignText) textChanger.apply(signtext), front);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ private Component translateColors(org.bukkit.entity.Player player, String line, Style style) {
|
|
+ if (level.purpurConfig.signAllowColors) {
|
|
+ if (player.hasPermission("purpur.sign.color")) line = line.replaceAll("(?i)&([0-9a-fr])", "\u00a7$1");
|
|
+ if (player.hasPermission("purpur.sign.style")) line = line.replaceAll("(?i)&([l-or])", "\u00a7$1");
|
|
+ if (player.hasPermission("purpur.sign.magic")) line = line.replaceAll("(?i)&([kr])", "\u00a7$1");
|
|
+
|
|
+ return io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(line));
|
|
+ } else {
|
|
+ return Component.literal(line).setStyle(style);
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
private SignText setMessages(net.minecraft.world.entity.player.Player entityhuman, List<FilteredText> list, SignText signtext, boolean front) { // CraftBukkit
|
|
SignText originalText = signtext; // CraftBukkit
|
|
for (int i = 0; i < list.size(); ++i) {
|
|
FilteredText filteredtext = (FilteredText) list.get(i);
|
|
Style chatmodifier = signtext.getMessage(i, entityhuman.isTextFilteringEnabled()).getStyle();
|
|
|
|
+ org.bukkit.entity.Player player = (org.bukkit.craftbukkit.entity.CraftPlayer) entityhuman.getBukkitEntity(); // Purpur
|
|
if (entityhuman.isTextFilteringEnabled()) {
|
|
- signtext = signtext.setMessage(i, Component.literal(net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty())).setStyle(chatmodifier)); // Paper - filter sign text to chat only
|
|
+ signtext = signtext.setMessage(i, translateColors(player, net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty()), chatmodifier)); // Paper - filter sign text to chat only // Purpur
|
|
} else {
|
|
- signtext = signtext.setMessage(i, Component.literal(net.minecraft.util.StringUtil.filterText(filteredtext.raw())).setStyle(chatmodifier), Component.literal(net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty())).setStyle(chatmodifier)); // Paper - filter sign text to chat only
|
|
+ signtext = signtext.setMessage(i, translateColors(player, net.minecraft.util.StringUtil.filterText(filteredtext.raw()), chatmodifier), translateColors(player, net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty()), chatmodifier)); // Paper - filter sign text to chat only // Purpur
|
|
}
|
|
}
|
|
|
|
@@ -348,6 +363,28 @@ public class SignBlockEntity extends BlockEntity {
|
|
return new CommandSourceStack(commandSource, Vec3.atCenterOf(pos), Vec2.ZERO, (ServerLevel) world, 2, s, (Component) object, world.getServer(), player); // Paper - Fix commands from signs not firing command events
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public ClientboundBlockEntityDataPacket getTranslatedUpdatePacket(boolean filtered, boolean front) {
|
|
+ final CompoundTag nbt = new CompoundTag();
|
|
+ this.saveAdditional(nbt, this.getLevel().registryAccess());
|
|
+ final Component[] lines = front ? frontText.getMessages(filtered) : backText.getMessages(filtered);
|
|
+ final String side = front ? "front_text" : "back_text";
|
|
+ for (int i = 0; i < 4; i++) {
|
|
+ final var component = io.papermc.paper.adventure.PaperAdventure.asAdventure(lines[i]);
|
|
+ final String line = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().serialize(component);
|
|
+ final var text = net.kyori.adventure.text.Component.text(line);
|
|
+ final String json = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(text);
|
|
+ if (!nbt.contains(side)) nbt.put(side, new CompoundTag());
|
|
+ final CompoundTag sideNbt = nbt.getCompound(side);
|
|
+ if (!sideNbt.contains("messages")) sideNbt.put("messages", new net.minecraft.nbt.ListTag());
|
|
+ final net.minecraft.nbt.ListTag messagesNbt = sideNbt.getList("messages", Tag.TAG_STRING);
|
|
+ messagesNbt.set(i, net.minecraft.nbt.StringTag.valueOf(json));
|
|
+ }
|
|
+ nbt.putString("PurpurEditor", "true");
|
|
+ return ClientboundBlockEntityDataPacket.create(this, (blockEntity, registryAccess) -> nbt);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public ClientboundBlockEntityDataPacket getUpdatePacket() {
|
|
return ClientboundBlockEntityDataPacket.create(this);
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonStructureResolver.java b/src/main/java/net/minecraft/world/level/block/piston/PistonStructureResolver.java
|
|
index 205e223c356634bd6bc6bd58c6f0b7fda61a6f5f..bea05cb928d540a2f19b51bb7352d032b2dd69cd 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonStructureResolver.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonStructureResolver.java
|
|
@@ -81,7 +81,7 @@ public class PistonStructureResolver {
|
|
return true;
|
|
} else {
|
|
int i = 1;
|
|
- if (i + this.toPush.size() > 12) {
|
|
+ if (i + this.toPush.size() > this.level.purpurConfig.pistonBlockPushLimit) { // Purpur
|
|
return false;
|
|
} else {
|
|
while (isSticky(blockState)) {
|
|
@@ -95,7 +95,7 @@ public class PistonStructureResolver {
|
|
break;
|
|
}
|
|
|
|
- if (++i + this.toPush.size() > 12) {
|
|
+ if (++i + this.toPush.size() > this.level.purpurConfig.pistonBlockPushLimit) { // Purpur
|
|
return false;
|
|
}
|
|
}
|
|
@@ -140,7 +140,7 @@ public class PistonStructureResolver {
|
|
return true;
|
|
}
|
|
|
|
- if (this.toPush.size() >= 12) {
|
|
+ if (this.toPush.size() >= this.level.purpurConfig.pistonBlockPushLimit) { // Purpur
|
|
return false;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
|
index 99fd67a78539133adf78d65e2c520ff3dd260301..852bfe68ab722a5cbdd90dbd70501b751fe81a78 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
|
|
@@ -91,7 +91,7 @@ public abstract class BlockBehaviour implements FeatureElement {
|
|
|
|
protected static final Direction[] UPDATE_SHAPE_ORDER = new Direction[]{Direction.WEST, Direction.EAST, Direction.NORTH, Direction.SOUTH, Direction.DOWN, Direction.UP};
|
|
public final boolean hasCollision;
|
|
- protected final float explosionResistance;
|
|
+ public float explosionResistance; // Purpur - protected final -> public
|
|
protected final boolean isRandomlyTicking;
|
|
protected final SoundType soundType;
|
|
protected final float friction;
|
|
@@ -99,7 +99,7 @@ public abstract class BlockBehaviour implements FeatureElement {
|
|
protected final float jumpFactor;
|
|
protected final boolean dynamicShape;
|
|
protected final FeatureFlagSet requiredFeatures;
|
|
- protected final BlockBehaviour.Properties properties;
|
|
+ public final BlockBehaviour.Properties properties; // Purpur - protected -> public
|
|
protected final Optional<ResourceKey<LootTable>> drops;
|
|
protected final String descriptionId;
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
index 4640baec5bed6c2d53cc0f8ca1d273cc115abe9b..15c83c6f5f56d6a27911d3bbd326cef1c21b1e58 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
@@ -407,11 +407,11 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
|
if (LightEngine.hasDifferentLightProperties(iblockdata1, iblockdata)) {
|
|
ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
|
|
- gameprofilerfiller.push("updateSkyLightSources");
|
|
+ //gameprofilerfiller.push("updateSkyLightSources"); // Purpur
|
|
// Paper - rewrite chunk system
|
|
- gameprofilerfiller.popPush("queueCheckLight");
|
|
+ //gameprofilerfiller.popPush("queueCheckLight"); // Purpur
|
|
this.level.getChunkSource().getLightEngine().checkBlock(blockposition);
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop(); // Purpur
|
|
}
|
|
|
|
boolean flag3 = iblockdata1.hasBlockEntity();
|
|
@@ -1058,9 +1058,9 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
|
|
|
if (LevelChunk.this.isTicking(blockposition)) {
|
|
try {
|
|
- ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
+ //ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
|
|
- gameprofilerfiller.push(this::getType);
|
|
+ //gameprofilerfiller.push(this::getType);
|
|
BlockState iblockdata = LevelChunk.this.getBlockState(blockposition);
|
|
|
|
if (this.blockEntity.getType().isValid(iblockdata)) {
|
|
@@ -1076,7 +1076,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
|
// Paper end - Remove the Block Entity if it's invalid
|
|
}
|
|
|
|
- gameprofilerfiller.pop();
|
|
+ //gameprofilerfiller.pop();
|
|
} catch (Throwable throwable) {
|
|
if (throwable instanceof ThreadDeath) throw throwable; // Paper
|
|
// Paper start - Prevent block entity and entity crashes
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
|
index 356d010506fd21f3c752e4aa86c46c1106fdde3b..86e16dd6b905af31795fda8002f2e1f857ddcb9f 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
|
|
@@ -106,6 +106,7 @@ public class EntityStorage implements EntityPersistentStorage<Entity> {
|
|
}
|
|
// Paper end - Entity load/save limit per chunk
|
|
CompoundTag compoundTagx = new CompoundTag();
|
|
+ if (!entity.canSaveToDisk()) return; // Purpur
|
|
if (entity.save(compoundTagx)) {
|
|
listTag.add(compoundTagx);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
|
index 78922c3e9a69db1774dd846047b79e9523d7cf41..0dde7cd71a32e6c0cde6cbbaef585896a3d7dae7 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
|
@@ -274,7 +274,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
// Paper start
|
|
private static void printOversizedLog(String msg, Path file, int x, int z) {
|
|
- org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PAPER - You may ask for help on Discord, but do not file an issue. These error messages can not be removed.");
|
|
+ org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PURPUR - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); // Purpur
|
|
}
|
|
|
|
private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException {
|
|
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 021221da5d0315f6e371380a705ac6b3f6ac18d3..27eb9a365006884c85603dc6d9dd8eee009c98b3 100644
|
|
--- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
|
+++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
|
@@ -48,7 +48,7 @@ public class PhantomSpawner implements CustomSpawner {
|
|
int spawnAttemptMaxSeconds = world.paperConfig().entities.behavior.phantomsSpawnAttemptMaxSeconds;
|
|
this.nextTick += (spawnAttemptMinSeconds + randomsource.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20;
|
|
// Paper end - Ability to control player's insomnia and phantoms
|
|
- if (world.getSkyDarken() < 5 && world.dimensionType().hasSkyLight()) {
|
|
+ if (world.getSkyDarken() < world.purpurConfig.phantomSpawnMinSkyDarkness && world.dimensionType().hasSkyLight()) { // Purpur
|
|
return 0;
|
|
} else {
|
|
int i = 0;
|
|
@@ -60,10 +60,10 @@ public class PhantomSpawner implements CustomSpawner {
|
|
if (!entityplayer.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityplayer.isCreative())) { // Paper - Add phantom creative and insomniac controls
|
|
BlockPos blockposition = entityplayer.blockPosition();
|
|
|
|
- if (!world.dimensionType().hasSkyLight() || blockposition.getY() >= world.getSeaLevel() && world.canSeeSky(blockposition)) {
|
|
+ if (!world.dimensionType().hasSkyLight() || (!world.purpurConfig.phantomSpawnOnlyAboveSeaLevel || blockposition.getY() >= world.getSeaLevel()) && (!world.purpurConfig.phantomSpawnOnlyWithVisibleSky || world.canSeeSky(blockposition))) { // Purpur
|
|
DifficultyInstance difficultydamagescaler = world.getCurrentDifficultyAt(blockposition);
|
|
|
|
- if (difficultydamagescaler.isHarderThan(randomsource.nextFloat() * 3.0F)) {
|
|
+ if (difficultydamagescaler.isHarderThan(randomsource.nextFloat() * (float) world.purpurConfig.phantomSpawnLocalDifficultyChance)) { // Purpur
|
|
ServerStatsCounter serverstatisticmanager = entityplayer.getStats();
|
|
int j = Mth.clamp(serverstatisticmanager.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE);
|
|
boolean flag2 = true;
|
|
@@ -75,7 +75,7 @@ public class PhantomSpawner implements CustomSpawner {
|
|
|
|
if (NaturalSpawner.isValidEmptySpawnBlock(world, blockposition1, iblockdata, fluid, EntityType.PHANTOM)) {
|
|
SpawnGroupData groupdataentity = null;
|
|
- int k = 1 + randomsource.nextInt(difficultydamagescaler.getDifficulty().getId() + 1);
|
|
+ int k = world.purpurConfig.phantomSpawnMinPerAttempt + world.random.nextInt((world.purpurConfig.phantomSpawnMaxPerAttempt < 0 ? difficultydamagescaler.getDifficulty().getId() : world.purpurConfig.phantomSpawnMaxPerAttempt - world.purpurConfig.phantomSpawnMinPerAttempt) + 1); // Purpur
|
|
|
|
for (int l = 0; l < k; ++l) {
|
|
// Paper start - PhantomPreSpawnEvent
|
|
diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
|
|
index f4fbcbb8ff6d2677af1a02a0801a323c06dce9b1..6f024a29e8824a604ff0c74f88522d23423beb5c 100644
|
|
--- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
|
|
+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
|
|
@@ -266,7 +266,7 @@ public abstract class FlowingFluid extends Fluid {
|
|
}
|
|
}
|
|
|
|
- if (j >= 2 && this.canConvertToSource(world)) {
|
|
+ if (j >= getRequiredSources(world) && this.canConvertToSource(world)) { // Purpur
|
|
BlockState iblockdata2 = world.getBlockState(blockposition_mutableblockposition.setWithOffset(pos, Direction.DOWN));
|
|
FluidState fluid1 = iblockdata2.getFluidState();
|
|
|
|
@@ -356,6 +356,12 @@ public abstract class FlowingFluid extends Fluid {
|
|
|
|
protected abstract boolean canConvertToSource(ServerLevel world);
|
|
|
|
+ // Purpur start
|
|
+ protected int getRequiredSources(Level level) {
|
|
+ return 2;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
protected void spreadTo(LevelAccessor world, BlockPos pos, BlockState state, Direction direction, FluidState fluidState) {
|
|
Block block = state.getBlock();
|
|
|
|
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 884db3e64cb22ed765beec8f11ea309fcf810207..6e643c1a7f7e71cfd20603facaf224985ee81716 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
|
|
@@ -199,6 +199,13 @@ public abstract class LavaFluid extends FlowingFluid {
|
|
world.levelEvent(1501, pos, 0);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ protected int getRequiredSources(Level level) {
|
|
+ return level.purpurConfig.lavaInfiniteRequiredSources;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
protected boolean canConvertToSource(ServerLevel world) {
|
|
return world.getGameRules().getBoolean(GameRules.RULE_LAVA_SOURCE_CONVERSION);
|
|
diff --git a/src/main/java/net/minecraft/world/level/material/WaterFluid.java b/src/main/java/net/minecraft/world/level/material/WaterFluid.java
|
|
index 552925ba47c7475e2e1ec2ded0966f28ed3e50a5..1e741f36b79585f33abe413beafe00cf5205d54f 100644
|
|
--- a/src/main/java/net/minecraft/world/level/material/WaterFluid.java
|
|
+++ b/src/main/java/net/minecraft/world/level/material/WaterFluid.java
|
|
@@ -81,6 +81,13 @@ public abstract class WaterFluid extends FlowingFluid {
|
|
return world.getGameRules().getBoolean(GameRules.RULE_WATER_SOURCE_CONVERSION);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ protected int getRequiredSources(Level level) {
|
|
+ return level.purpurConfig.waterInfiniteRequiredSources;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
// Paper start - Add BlockBreakBlockEvent
|
|
@Override
|
|
protected void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state, BlockPos source) {
|
|
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
|
index cc7d94144e39f7dace7b569b4567def98396e8f9..91abbda59446d462979dddc4b380c6f24d0b4c92 100644
|
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
|
@@ -58,9 +58,9 @@ public class PathFinder {
|
|
@Nullable
|
|
// Paper start - Perf: remove streams and optimize collection
|
|
private Path findPath(Node startNode, List<Map.Entry<Target, BlockPos>> positions, float followRange, int distance, float rangeMultiplier) {
|
|
- ProfilerFiller profilerFiller = Profiler.get();
|
|
- profilerFiller.push("find_path");
|
|
- profilerFiller.markForCharting(MetricCategory.PATH_FINDING);
|
|
+ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur
|
|
+ //profilerFiller.push("find_path"); // Purpur
|
|
+ //profilerFiller.markForCharting(MetricCategory.PATH_FINDING); // Purpur
|
|
// Set<Target> set = positions.keySet();
|
|
startNode.g = 0.0F;
|
|
startNode.h = this.getBestH(startNode, positions); // Paper - optimize collection
|
|
@@ -128,7 +128,7 @@ public class PathFinder {
|
|
if (best == null || comparator.compare(path, best) < 0)
|
|
best = path;
|
|
}
|
|
- profilerFiller.pop();
|
|
+ //profilerFiller.pop(); // Purpur
|
|
return best;
|
|
// Paper end - Perf: remove streams and optimize collection
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
|
index c84fd369d92932903c76bb2012602617d3e2d213..224896124706764412033c8726c822e116f2c0f1 100644
|
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
|
@@ -240,7 +240,7 @@ public class WalkNodeEvaluator extends NodeEvaluator {
|
|
if ((node == null || node.costMalus < 0.0F)
|
|
&& maxYStep > 0
|
|
&& (pathType != PathType.FENCE || this.canWalkOverFences())
|
|
- && pathType != PathType.UNPASSABLE_RAIL
|
|
+ && (this.mob.level().purpurConfig.mobsIgnoreRails || pathType != PathType.UNPASSABLE_RAIL) // Purpur
|
|
&& pathType != PathType.TRAPDOOR
|
|
&& pathType != PathType.POWDER_SNOW) {
|
|
node = this.tryJumpOn(x, y, z, maxYStep, prevFeetY, direction, nodeType, mutableBlockPos);
|
|
@@ -491,7 +491,7 @@ public class WalkNodeEvaluator extends NodeEvaluator {
|
|
return PathType.TRAPDOOR;
|
|
} else if (blockState.is(Blocks.POWDER_SNOW)) {
|
|
return PathType.POWDER_SNOW;
|
|
- } else if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH)) {
|
|
+ } else if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH) || blockState.is(Blocks.STONECUTTER)) { // Purpur
|
|
return PathType.DAMAGE_OTHER;
|
|
} else if (blockState.is(Blocks.HONEY_BLOCK)) {
|
|
return PathType.STICKY_HONEY;
|
|
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalShape.java b/src/main/java/net/minecraft/world/level/portal/PortalShape.java
|
|
index 90056822cd17f3d33d14b3f94b34750ee522a0a9..acdff7b4a00d563739fd301c3633a266875296fa 100644
|
|
--- a/src/main/java/net/minecraft/world/level/portal/PortalShape.java
|
|
+++ b/src/main/java/net/minecraft/world/level/portal/PortalShape.java
|
|
@@ -35,7 +35,7 @@ public class PortalShape {
|
|
private static final int MIN_HEIGHT = 3;
|
|
public static final int MAX_HEIGHT = 21;
|
|
private static final BlockBehaviour.StatePredicate FRAME = (iblockdata, iblockaccess, blockposition) -> {
|
|
- return iblockdata.is(Blocks.OBSIDIAN);
|
|
+ return iblockdata.is(Blocks.OBSIDIAN) || (org.purpurmc.purpur.PurpurConfig.cryingObsidianValidForPortalFrame && iblockdata.is(Blocks.CRYING_OBSIDIAN)); // Purpur
|
|
};
|
|
private static final float SAFE_TRAVEL_MAX_ENTITY_XY = 4.0F;
|
|
private static final double SAFE_TRAVEL_MAX_VERTICAL_DELTA = 1.0D;
|
|
diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
|
index ae321b3b8d98e42ef07fd1f0f738c1a2b428f6db..26da9e7c25ef6a89482838010d8ed6bcf8c87511 100644
|
|
--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
|
+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
|
@@ -81,6 +81,7 @@ public class MapItemSavedData extends SavedData {
|
|
private final Map<String, MapFrame> frameMarkers = Maps.newHashMap();
|
|
private int trackedDecorationCount;
|
|
private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper
|
|
+ public boolean isExplorerMap; // Purpur
|
|
|
|
// CraftBukkit start
|
|
public final CraftMapView mapView;
|
|
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/functions/EnchantedCountIncreaseFunction.java b/src/main/java/net/minecraft/world/level/storage/loot/functions/EnchantedCountIncreaseFunction.java
|
|
index 5f27e1ce23f2ed68e4c8af1986fafce940dbf826..d8cf49cbd82ed12d23fa10a81a88cc4bcf1c0f10 100644
|
|
--- a/src/main/java/net/minecraft/world/level/storage/loot/functions/EnchantedCountIncreaseFunction.java
|
|
+++ b/src/main/java/net/minecraft/world/level/storage/loot/functions/EnchantedCountIncreaseFunction.java
|
|
@@ -66,6 +66,11 @@ public class EnchantedCountIncreaseFunction extends LootItemConditionalFunction
|
|
Entity entity = context.getOptionalParameter(LootContextParams.ATTACKING_ENTITY);
|
|
if (entity instanceof LivingEntity livingEntity) {
|
|
int i = EnchantmentHelper.getEnchantmentLevel(this.enchantment, livingEntity);
|
|
+ // Purpur start - Add an option to fix MC-3304 projectile looting
|
|
+ if (org.purpurmc.purpur.PurpurConfig.fixProjectileLootingTransfer && context.getOptionalParameter(LootContextParams.DIRECT_ATTACKING_ENTITY) instanceof net.minecraft.world.entity.projectile.AbstractArrow arrow) {
|
|
+ i = arrow.actualEnchantments.getLevel(this.enchantment);
|
|
+ }
|
|
+ // Purpur end - Add an option to fix MC-3304 projectile looting
|
|
if (i == 0) {
|
|
return stack;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/phys/AABB.java b/src/main/java/net/minecraft/world/phys/AABB.java
|
|
index 6cf6d4ec7b9e43c7b2b4c0e2fb080964ff588130..e74866e5195a5eeae7666ad7be750edac5947094 100644
|
|
--- a/src/main/java/net/minecraft/world/phys/AABB.java
|
|
+++ b/src/main/java/net/minecraft/world/phys/AABB.java
|
|
@@ -551,4 +551,10 @@ public class AABB {
|
|
public static AABB ofSize(Vec3 center, double dx, double dy, double dz) {
|
|
return new AABB(center.x - dx / 2.0, center.y - dy / 2.0, center.z - dz / 2.0, center.x + dx / 2.0, center.y + dy / 2.0, center.z + dz / 2.0);
|
|
}
|
|
+
|
|
+ // Purpur - tuinity added method
|
|
+ public final AABB offsetY(double dy) {
|
|
+ return new AABB(this.minX, this.minY + dy, this.minZ, this.maxX, this.maxY + dy, this.maxZ);
|
|
+ }
|
|
+ // Purpur
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/ticks/LevelTicks.java b/src/main/java/net/minecraft/world/ticks/LevelTicks.java
|
|
index 778e6476c86d823dc8efe603a95e589e8b2ea9d9..452fb3442221fd66debfe1e1d6e85ee17951e556 100644
|
|
--- a/src/main/java/net/minecraft/world/ticks/LevelTicks.java
|
|
+++ b/src/main/java/net/minecraft/world/ticks/LevelTicks.java
|
|
@@ -79,20 +79,20 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
|
|
}
|
|
|
|
public void tick(long time, int maxTicks, BiConsumer<BlockPos, T> ticker) {
|
|
- ProfilerFiller profilerFiller = Profiler.get();
|
|
- profilerFiller.push("collect");
|
|
- this.collectTicks(time, maxTicks, profilerFiller);
|
|
- profilerFiller.popPush("run");
|
|
- profilerFiller.incrementCounter("ticksToRun", this.toRunThisTick.size());
|
|
+ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur
|
|
+ //profilerFiller.push("collect"); // Purpur
|
|
+ this.collectTicks(time, maxTicks, null); // Purpur
|
|
+ //profilerFiller.popPush("run"); // Purpur
|
|
+ //profilerFiller.incrementCounter("ticksToRun", this.toRunThisTick.size()); // Purpur
|
|
this.runCollectedTicks(ticker);
|
|
- profilerFiller.popPush("cleanup");
|
|
+ //profilerFiller.popPush("cleanup"); // Purpur
|
|
this.cleanupAfterTick();
|
|
- profilerFiller.pop();
|
|
+ //profilerFiller.pop(); // Purpur
|
|
}
|
|
|
|
private void collectTicks(long time, int maxTicks, ProfilerFiller profiler) {
|
|
this.sortContainersToTick(time);
|
|
- profiler.incrementCounter("containersToTick", this.containersToTick.size());
|
|
+ //profiler.incrementCounter("containersToTick", this.containersToTick.size()); // Purpur
|
|
this.drainContainers(time, maxTicks);
|
|
this.rescheduleLeftoverContainers();
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
|
index 94ca0407303c4493ab4928b12ec6ecc75aaca549..a138e1b6b66d99f2035de054137a607aa6b7f0b9 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
|
@@ -363,14 +363,26 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
|
|
|
|
@Override
|
|
public Location getLocation() {
|
|
+ // Purpur start
|
|
+ if (this.isOnline()) {
|
|
+ return this.getPlayer().getLocation();
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
CompoundTag data = this.getData();
|
|
if (data == null) {
|
|
return null;
|
|
}
|
|
|
|
- if (data.contains("Pos") && data.contains("Rotation")) {
|
|
- ListTag position = (ListTag) data.get("Pos");
|
|
- ListTag rotation = (ListTag) data.get("Rotation");
|
|
+ // Purpur start - OfflinePlayer API
|
|
+ //if (data.contains("Pos") && data.contains("Rotation")) {
|
|
+ ListTag position = data.getList("Pos", net.minecraft.nbt.Tag.TAG_DOUBLE);
|
|
+ ListTag rotation = data.getList("Rotation", net.minecraft.nbt.Tag.TAG_FLOAT);
|
|
+
|
|
+ if (position.isEmpty() && rotation.isEmpty()) {
|
|
+ return null;
|
|
+ }
|
|
+ // Purpur end - OfflinePlayer API
|
|
|
|
UUID uuid = new UUID(data.getLong("WorldUUIDMost"), data.getLong("WorldUUIDLeast"));
|
|
|
|
@@ -381,9 +393,9 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
|
|
rotation.getFloat(0),
|
|
rotation.getFloat(1)
|
|
);
|
|
- }
|
|
+ //} // Purpur - OfflinePlayer API
|
|
|
|
- return null;
|
|
+ //return null; // Purpur - OfflinePlayer API
|
|
}
|
|
|
|
@Override
|
|
@@ -626,4 +638,191 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
|
|
manager.save();
|
|
}
|
|
}
|
|
+
|
|
+ // Purpur start - OfflinePlayer API
|
|
+ @Override
|
|
+ public boolean getAllowFlight() {
|
|
+ if (this.isOnline()) {
|
|
+ return this.getPlayer().getAllowFlight();
|
|
+ } else {
|
|
+ CompoundTag data = this.getData();
|
|
+ if (data == null) return false;
|
|
+ if (!data.contains("abilities")) return false;
|
|
+ CompoundTag abilities = data.getCompound("abilities");
|
|
+ return abilities.getByte("mayfly") == (byte) 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setAllowFlight(boolean flight) {
|
|
+ if (this.isOnline()) {
|
|
+ this.getPlayer().setAllowFlight(flight);
|
|
+ } else {
|
|
+ CompoundTag data = this.getData();
|
|
+ if (data == null) return;
|
|
+ if (!data.contains("abilities")) return;
|
|
+ CompoundTag abilities = data.getCompound("abilities");
|
|
+ abilities.putByte("mayfly", (byte) (flight ? 1 : 0));
|
|
+ data.put("abilities", abilities);
|
|
+ save(data);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isFlying() {
|
|
+ if (this.isOnline()) {
|
|
+ return this.isFlying();
|
|
+ } else {
|
|
+ CompoundTag data = this.getData();
|
|
+ if (data == null) return false;
|
|
+ if (!data.contains("abilities")) return false;
|
|
+ CompoundTag abilities = data.getCompound("abilities");
|
|
+ return abilities.getByte("flying") == (byte) 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setFlying(boolean value) {
|
|
+ if (this.isOnline()) {
|
|
+ this.getPlayer().setFlying(value);
|
|
+ } else {
|
|
+ CompoundTag data = this.getData();
|
|
+ if (data == null) return;
|
|
+ if (!data.contains("abilities")) return;
|
|
+ CompoundTag abilities = data.getCompound("abilities");
|
|
+ abilities.putByte("mayfly", (byte) (value ? 1 : 0));
|
|
+ data.put("abilities", abilities);
|
|
+ save(data);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setFlySpeed(float value) throws IllegalArgumentException {
|
|
+ if (value < -1f || value > 1f) throw new IllegalArgumentException("FlySpeed needs to be between -1 and 1");
|
|
+ if (this.isOnline()) {
|
|
+ this.getPlayer().setFlySpeed(value);
|
|
+ } else {
|
|
+ CompoundTag data = this.getData();
|
|
+ if (data == null) return;
|
|
+ if (!data.contains("abilities")) return;
|
|
+ CompoundTag abilities = data.getCompound("abilities");
|
|
+ abilities.putFloat("flySpeed", value);
|
|
+ data.put("abilities", abilities);
|
|
+ save(data);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public float getFlySpeed() {
|
|
+ if (this.isOnline()) {
|
|
+ return this.getPlayer().getFlySpeed();
|
|
+ } else {
|
|
+ CompoundTag data = this.getData();
|
|
+ if (data == null) return 0;
|
|
+ if (!data.contains("abilities")) return 0;
|
|
+ CompoundTag abilities = data.getCompound("abilities");
|
|
+ return abilities.getFloat("flySpeed");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setWalkSpeed(float value) throws IllegalArgumentException {
|
|
+ if (value < -1f || value > 1f) throw new IllegalArgumentException("WalkSpeed needs to be between -1 and 1");
|
|
+ if (this.isOnline()) {
|
|
+ this.getPlayer().setWalkSpeed(value);
|
|
+ } else {
|
|
+ CompoundTag data = this.getData();
|
|
+ if (data == null) return;
|
|
+ if (!data.contains("abilities")) return;
|
|
+ CompoundTag abilities = data.getCompound("abilities");
|
|
+ abilities.putFloat("walkSpeed", value);
|
|
+ data.put("abilities", abilities);
|
|
+ save(data);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public float getWalkSpeed() {
|
|
+ if (this.isOnline()) {
|
|
+ return this.getPlayer().getWalkSpeed();
|
|
+ } else {
|
|
+ CompoundTag data = this.getData();
|
|
+ if (data == null) return 0;
|
|
+ if (!data.contains("abilities")) return 0;
|
|
+ CompoundTag abilities = data.getCompound("abilities");
|
|
+ return abilities.getFloat("walkSpeed");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean teleportOffline(Location destination) {
|
|
+ if (this.isOnline()) {
|
|
+ return this.getPlayer().teleport(destination);
|
|
+ } else {
|
|
+ return setLocation(destination);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean teleportOffline(Location destination, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause){
|
|
+ if (this.isOnline()) {
|
|
+ return this.getPlayer().teleport(destination, cause);
|
|
+ } else {
|
|
+ return setLocation(destination);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public java.util.concurrent.CompletableFuture<Boolean> teleportOfflineAsync(Location destination) {
|
|
+ if (this.isOnline()) {
|
|
+ return this.getPlayer().teleportAsync(destination);
|
|
+ } else {
|
|
+ return java.util.concurrent.CompletableFuture.completedFuture(setLocation(destination));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public java.util.concurrent.CompletableFuture<Boolean> teleportOfflineAsync(Location destination, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) {
|
|
+ if (this.isOnline()) {
|
|
+ return this.getPlayer().teleportAsync(destination, cause);
|
|
+ } else {
|
|
+ return java.util.concurrent.CompletableFuture.completedFuture(setLocation(destination));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private boolean setLocation(Location location) {
|
|
+ CompoundTag data = this.getData();
|
|
+ if (data == null) return false;
|
|
+ data.putLong("WorldUUIDMost", location.getWorld().getUID().getMostSignificantBits());
|
|
+ data.putLong("WorldUUIDLeast", location.getWorld().getUID().getLeastSignificantBits());
|
|
+ net.minecraft.nbt.ListTag position = new net.minecraft.nbt.ListTag();
|
|
+ position.add(net.minecraft.nbt.DoubleTag.valueOf(location.getX()));
|
|
+ position.add(net.minecraft.nbt.DoubleTag.valueOf(location.getY()));
|
|
+ position.add(net.minecraft.nbt.DoubleTag.valueOf(location.getZ()));
|
|
+ data.put("Pos", position);
|
|
+ net.minecraft.nbt.ListTag rotation = new net.minecraft.nbt.ListTag();
|
|
+ rotation.add(net.minecraft.nbt.FloatTag.valueOf(location.getYaw()));
|
|
+ rotation.add(net.minecraft.nbt.FloatTag.valueOf(location.getPitch()));
|
|
+ data.put("Rotation", rotation);
|
|
+ save(data);
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Safely replaces player's .dat file with provided CompoundTag
|
|
+ * @param compoundTag
|
|
+ */
|
|
+ private void save(CompoundTag compoundTag) {
|
|
+ File playerDir = server.console.playerDataStorage.getPlayerDir();
|
|
+ try {
|
|
+ File tempFile = File.createTempFile(this.getUniqueId()+"-", ".dat", playerDir);
|
|
+ net.minecraft.nbt.NbtIo.writeCompressed(compoundTag, tempFile.toPath());
|
|
+ File playerDataFile = new File(playerDir, this.getUniqueId()+".dat");
|
|
+ File playerDataFileOld = new File(playerDir, this.getUniqueId()+".dat_old");
|
|
+ net.minecraft.Util.safeReplaceFile(playerDataFile.toPath(), tempFile.toPath(), playerDataFileOld.toPath());
|
|
+ } catch (java.io.IOException e) {
|
|
+ e.printStackTrace();
|
|
+ }
|
|
+ }
|
|
+ // Purpur end - OfflinePlayer API
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
index b185a9b474121b8a4067816b3c3c39270c2a202e..eef85316dc310afef805f29c6665107a24a6a3d1 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
@@ -414,6 +414,20 @@ public final class CraftServer implements Server {
|
|
this.paperPluginManager = new io.papermc.paper.plugin.manager.PaperPluginManagerImpl(this, this.commandMap, pluginManager);
|
|
this.pluginManager.paperPluginManager = this.paperPluginManager;
|
|
// Paper end
|
|
+ // Purpur start
|
|
+ org.purpurmc.purpur.language.Language.setLanguage(new org.purpurmc.purpur.language.Language() {
|
|
+ private net.minecraft.locale.Language language = net.minecraft.locale.Language.getInstance();
|
|
+ @Override
|
|
+ public boolean has(@org.jetbrains.annotations.NotNull String key) {
|
|
+ return language.has(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @org.jetbrains.annotations.NotNull String getOrDefault(@org.jetbrains.annotations.NotNull String key) {
|
|
+ return language.getOrDefault(key);
|
|
+ }
|
|
+ });
|
|
+ // Purpur end
|
|
|
|
CraftRegistry.setMinecraftRegistry(console.registryAccess());
|
|
|
|
@@ -1074,6 +1088,7 @@ public final class CraftServer implements Server {
|
|
|
|
org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot
|
|
this.console.paperConfigurations.reloadConfigs(this.console);
|
|
+ org.purpurmc.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur
|
|
for (ServerLevel world : this.console.getAllLevels()) {
|
|
// world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
|
|
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
|
|
@@ -1089,6 +1104,7 @@ public final class CraftServer implements Server {
|
|
}
|
|
}
|
|
world.spigotConfig.init(); // Spigot
|
|
+ world.purpurConfig.init(); // Purpur
|
|
}
|
|
|
|
Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
|
|
@@ -1106,6 +1122,7 @@ public final class CraftServer implements Server {
|
|
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
|
|
io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper
|
|
this.spark.registerCommandBeforePlugins(this); // Paper - spark
|
|
+ org.purpurmc.purpur.PurpurConfig.registerCommands(); // Purpur
|
|
this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*");
|
|
this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions");
|
|
|
|
@@ -1614,6 +1631,58 @@ public final class CraftServer implements Server {
|
|
return true;
|
|
}
|
|
|
|
+ // Purpur Start
|
|
+ @Override
|
|
+ public void addFuel(org.bukkit.Material material, int burnTime) {
|
|
+ Preconditions.checkArgument(burnTime > 0, "BurnTime must be greater than 0");
|
|
+
|
|
+ net.minecraft.world.item.ItemStack itemStack = net.minecraft.world.item.ItemStack.fromBukkitCopy(new ItemStack(material));
|
|
+ MinecraftServer.getServer().fuelValues().values.put(itemStack.getItem(), burnTime);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void removeFuel(org.bukkit.Material material) {
|
|
+ net.minecraft.world.item.ItemStack itemStack = net.minecraft.world.item.ItemStack.fromBukkitCopy(new ItemStack(material));
|
|
+ MinecraftServer.getServer().fuelValues().values.keySet().removeIf(itemStack::is);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration) {
|
|
+ sendBlockHighlight(location, duration, "", 0x6400FF00);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, int argb) {
|
|
+ sendBlockHighlight(location, duration, "", argb);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, String text) {
|
|
+ sendBlockHighlight(location, duration, text, 0x6400FF00);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, String text, int argb) {
|
|
+ this.worlds.forEach((name, world) -> world.sendBlockHighlight(location, duration, text, argb));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, org.bukkit.Color color, int transparency) {
|
|
+ sendBlockHighlight(location, duration, "", color, transparency);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, String text, org.bukkit.Color color, int transparency) {
|
|
+ if (transparency < 0 || transparency > 255) throw new IllegalArgumentException("transparency is outside of 0-255 range");
|
|
+ sendBlockHighlight(location, duration, text, transparency << 24 | color.asRGB());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clearBlockHighlights() {
|
|
+ this.worlds.forEach((name, world) -> clearBlockHighlights());
|
|
+ }
|
|
+ // Purpur End
|
|
+
|
|
@Override
|
|
public List<Recipe> getRecipesFor(ItemStack result) {
|
|
Preconditions.checkArgument(result != null, "ItemStack cannot be null");
|
|
@@ -3009,6 +3078,18 @@ public final class CraftServer implements Server {
|
|
return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console);
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public YamlConfiguration getPurpurConfig() {
|
|
+ return org.purpurmc.purpur.PurpurConfig.config;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public java.util.Properties getServerProperties() {
|
|
+ return getProperties().properties;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public void restart() {
|
|
org.spigotmc.RestartCommand.restart();
|
|
@@ -3038,6 +3119,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()
|
|
@@ -3236,4 +3318,16 @@ public final class CraftServer implements Server {
|
|
return this.potionBrewer;
|
|
}
|
|
// Paper end
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public String getServerName() {
|
|
+ return this.getProperties().serverName;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isLagging() {
|
|
+ return getServer().lagging;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
index d41c81158c00931e6b11093cce141f6a3085ba05..ea1b4f0073f775fdd18eb080886d60c71a08ab2c 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
@@ -2399,6 +2399,48 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
|
return (this.getHandle().getDragonFight() == null) ? null : new CraftDragonBattle(this.getHandle().getDragonFight());
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ public float getLocalDifficultyAt(Location location) {
|
|
+ return getHandle().getCurrentDifficultyAt(io.papermc.paper.util.MCUtil.toBlockPosition(location)).getEffectiveDifficulty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration) {
|
|
+ sendBlockHighlight(location, duration, "", 0x6400FF00);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, int argb) {
|
|
+ sendBlockHighlight(location, duration, "", argb);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, String text) {
|
|
+ sendBlockHighlight(location, duration, text, 0x6400FF00);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, String text, int argb) {
|
|
+ net.minecraft.network.protocol.game.DebugPackets.sendGameTestAddMarker(getHandle(), io.papermc.paper.util.MCUtil.toBlockPosition(location), text, argb, duration);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, org.bukkit.Color color, int transparency) {
|
|
+ sendBlockHighlight(location, duration, "", color, transparency);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, String text, org.bukkit.Color color, int transparency) {
|
|
+ if (transparency < 0 || transparency > 255) throw new IllegalArgumentException("transparency is outside of 0-255 range");
|
|
+ sendBlockHighlight(location, duration, text, transparency << 24 | color.asRGB());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clearBlockHighlights() {
|
|
+ net.minecraft.network.protocol.game.DebugPackets.sendGameTestClearPacket(getHandle());
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public Collection<GeneratedStructure> getStructures(int x, int z) {
|
|
return this.getStructures(x, z, struct -> true);
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
index a7524d3853d5b67b6385d2b74832b9267503dfe6..b2d60b214b58d9a5fadf3629e5ebc358c904d1c6 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
@@ -176,6 +176,14 @@ public class Main {
|
|
.describedAs("Jar file");
|
|
// Paper end
|
|
|
|
+ // Purpur Start
|
|
+ acceptsAll(asList("purpur", "purpur-settings"), "File for purpur settings")
|
|
+ .withRequiredArg()
|
|
+ .ofType(File.class)
|
|
+ .defaultsTo(new File("purpur.yml"))
|
|
+ .describedAs("Yml file");
|
|
+ // Purpur end
|
|
+
|
|
// Paper start
|
|
acceptsAll(asList("server-name"), "Name of the server")
|
|
.withRequiredArg()
|
|
@@ -259,7 +267,7 @@ public class Main {
|
|
System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper
|
|
}
|
|
|
|
- if (Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) {
|
|
+ if (false && Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) { // Purpur
|
|
Date buildDate = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z").parse(Main.class.getPackage().getImplementationVendor()); // Paper
|
|
|
|
Calendar deadline = Calendar.getInstance();
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java
|
|
index 1a2a05160ba51d9c75f1ae6ae61d944d81428722..3beb26ad2ef0fded49a8da8c5dec64f9508c1995 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java
|
|
@@ -16,8 +16,15 @@ import org.bukkit.entity.Bee;
|
|
|
|
public class CraftBeehive extends CraftBlockEntityState<BeehiveBlockEntity> implements Beehive {
|
|
|
|
+ private final List<org.purpurmc.purpur.entity.StoredEntity<Bee>> storage = new ArrayList<>(); // Purpur
|
|
+
|
|
public CraftBeehive(World world, BeehiveBlockEntity tileEntity) {
|
|
super(world, tileEntity);
|
|
+ // Purpur start - load bees to be able to modify them individually
|
|
+ for(BeehiveBlockEntity.BeeData data : tileEntity.getStored()) {
|
|
+ storage.add(new org.purpurmc.purpur.entity.PurpurStoredBee(data, this));
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
|
|
protected CraftBeehive(CraftBeehive state, Location location) {
|
|
@@ -75,15 +82,54 @@ public class CraftBeehive extends CraftBlockEntityState<BeehiveBlockEntity> impl
|
|
bees.add((Bee) bee.getBukkitEntity());
|
|
}
|
|
}
|
|
-
|
|
+ storage.clear(); // Purpur
|
|
return bees;
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public Bee releaseEntity(org.purpurmc.purpur.entity.StoredEntity<Bee> entity) {
|
|
+ ensureNoWorldGeneration();
|
|
+
|
|
+ if(!getEntities().contains(entity)) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ if(isPlaced()) {
|
|
+ BeehiveBlockEntity beehive = ((BeehiveBlockEntity) this.getTileEntityFromWorld());
|
|
+ BeehiveBlockEntity.BeeData data = ((org.purpurmc.purpur.entity.PurpurStoredBee) entity).getHandle();
|
|
+
|
|
+ List<Entity> list = beehive.releaseBee(getHandle(), data, BeeReleaseStatus.BEE_RELEASED, true);
|
|
+
|
|
+ if (list.size() == 1) {
|
|
+ storage.remove(entity);
|
|
+
|
|
+ return (Bee) list.get(0).getBukkitEntity();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<org.purpurmc.purpur.entity.StoredEntity<Bee>> getEntities() {
|
|
+ return new ArrayList<>(storage);
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public void addEntity(Bee entity) {
|
|
Preconditions.checkArgument(entity != null, "Entity must not be null");
|
|
|
|
- this.getSnapshot().addOccupant(((CraftBee) entity).getHandle());
|
|
+ int length = this.getSnapshot().getStored().size(); // Purpur
|
|
+ getSnapshot().addOccupant(((CraftBee) entity).getHandle());
|
|
+
|
|
+ // Purpur start - check if new bee was added, and if yes, add to stored bees
|
|
+ List<BeehiveBlockEntity.BeeData> storedBeeData = this.getSnapshot().getStored();
|
|
+ if(length < storedBeeData.size()) {
|
|
+ storage.add(new org.purpurmc.purpur.entity.PurpurStoredBee(storedBeeData.getLast(), this));
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
|
|
@Override
|
|
@@ -100,6 +146,7 @@ public class CraftBeehive extends CraftBlockEntityState<BeehiveBlockEntity> impl
|
|
@Override
|
|
public void clearEntities() {
|
|
getSnapshot().clearBees();
|
|
+ storage.clear(); // Purpur
|
|
}
|
|
// Paper end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java b/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java
|
|
index c1759aeb3e6ad0e4eb66cba3da1b120dd1dce812..1a91bc2e422db0eba65694ac046f1b362c6b0cd6 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java
|
|
@@ -73,7 +73,7 @@ public class CraftConduit extends CraftBlockEntityState<ConduitBlockEntity> impl
|
|
public int getRange() {
|
|
this.ensureNoWorldGeneration();
|
|
ConduitBlockEntity conduit = (ConduitBlockEntity) this.getTileEntityFromWorld();
|
|
- return (conduit != null) ? ConduitBlockEntity.getRange(conduit.effectBlocks) : 0;
|
|
+ return (conduit != null) ? ConduitBlockEntity.getRange(conduit.effectBlocks, this.world.getHandle()) : 0; // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java
|
|
index 4e56018b64d11f76c8da43fd8f85c6de72204e36..9607675e6c5bff2183c4420d11fc63eeb5747fb6 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java
|
|
@@ -21,7 +21,12 @@ public class CraftConsoleCommandSender extends ServerCommandSender implements Co
|
|
|
|
@Override
|
|
public void sendMessage(String message) {
|
|
- this.sendRawMessage(message);
|
|
+ // Purpur start
|
|
+ String[] parts = message.split("\n");
|
|
+ for (String part : parts) {
|
|
+ this.sendRawMessage(part);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
|
|
@Override
|
|
@@ -91,7 +96,7 @@ public class CraftConsoleCommandSender extends ServerCommandSender implements Co
|
|
// Paper start
|
|
@Override
|
|
public void sendMessage(final net.kyori.adventure.identity.Identity identity, final net.kyori.adventure.text.Component message, final net.kyori.adventure.audience.MessageType type) {
|
|
- this.sendRawMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message));
|
|
+ this.sendMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message)); // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java
|
|
index d657fd2c507a5b215aeab0a5f3e9c2ee892a27c8..985e9ec21c60a1f47973bd5fc53b96a6f9b7d04a 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java
|
|
@@ -21,12 +21,12 @@ public class CraftEndermite extends CraftMonster implements Endermite {
|
|
|
|
@Override
|
|
public boolean isPlayerSpawned() {
|
|
- return false;
|
|
+ return getHandle().isPlayerSpawned(); // Purpur
|
|
}
|
|
|
|
@Override
|
|
public void setPlayerSpawned(boolean playerSpawned) {
|
|
- // Nop
|
|
+ getHandle().setPlayerSpawned(playerSpawned); // Purpur
|
|
}
|
|
// Paper start
|
|
@Override
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
index 179886dcbda29c5cdb7dbd43e44951ae38d9df96..cc7d5aeb2044019aabad93dd79a16178c7483037 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
@@ -87,6 +87,23 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
|
this.entityType = CraftEntityType.minecraftToBukkit(entity.getType());
|
|
}
|
|
|
|
+ // Purpur start - API for any mob to burn daylight
|
|
+ @Override
|
|
+ public boolean isImmuneToFire() {
|
|
+ return getHandle().fireImmune();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setImmuneToFire(Boolean fireImmune) {
|
|
+ getHandle().immuneToFire = fireImmune;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isInDaylight() {
|
|
+ return getHandle().isSunBurnTick();
|
|
+ }
|
|
+ // Purpur end - API for any mob to burn daylight
|
|
+
|
|
public static <T extends Entity> CraftEntity getEntity(CraftServer server, T entity) {
|
|
Preconditions.checkArgument(entity != null, "Unknown entity");
|
|
|
|
@@ -246,6 +263,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
|
boolean ignorePassengers = flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS);
|
|
// Don't allow teleporting between worlds while keeping passengers
|
|
if (flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS) && this.entity.isVehicle() && location.getWorld() != this.getWorld()) {
|
|
+ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, cause).callEvent()) // Purpur
|
|
return false;
|
|
}
|
|
|
|
@@ -1311,4 +1329,27 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
|
}
|
|
}
|
|
// Paper end - broadcast hurt animation
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public org.bukkit.entity.Player getRider() {
|
|
+ net.minecraft.world.entity.player.Player rider = getHandle().getRider();
|
|
+ return rider != null ? (org.bukkit.entity.Player) rider.getBukkitEntity() : null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasRider() {
|
|
+ return getHandle().getRider() != null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isRidable() {
|
|
+ return getHandle().isRidable();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isRidableInWater() {
|
|
+ return !getHandle().dismountsUnderwater();
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
|
index 4312290ad970f71e1dc25b707ab312c597a481a9..e0cbf2e2c17c87af23495e6365ff9378f7c861da 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
|
@@ -273,6 +273,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
|
@Override
|
|
public void recalculatePermissions() {
|
|
this.perm.recalculatePermissions();
|
|
+ getHandle().canPortalInstant = hasPermission("purpur.portal.instant"); // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java
|
|
index 63cae1a2e95d8da17c45c4404a8dd0ca6a413c39..966587c2788b5c93be83259ddc962a89cde7cbaa 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java
|
|
@@ -27,4 +27,17 @@ public class CraftIronGolem extends CraftGolem implements IronGolem {
|
|
public void setPlayerCreated(boolean playerCreated) {
|
|
this.getHandle().setPlayerCreated(playerCreated);
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ @org.jetbrains.annotations.Nullable
|
|
+ public java.util.UUID getSummoner() {
|
|
+ return getHandle().getSummoner();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner) {
|
|
+ getHandle().setSummoner(summoner);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
|
|
index 30d62ee4d5cd2ddacb8783b5bbbf475d592b3e02..5c1cda88080850314dac196dbe71ff12e48a8aca 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
|
|
@@ -151,4 +151,51 @@ public class CraftItem extends CraftEntity implements Item {
|
|
public String toString() {
|
|
return "CraftItem";
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public void setImmuneToCactus(boolean immuneToCactus) {
|
|
+ this.getHandle().immuneToCactus = immuneToCactus;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isImmuneToCactus() {
|
|
+ return this.getHandle().immuneToCactus;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setImmuneToExplosion(boolean immuneToExplosion) {
|
|
+ this.getHandle().immuneToExplosion = immuneToExplosion;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isImmuneToExplosion() {
|
|
+ return this.getHandle().immuneToExplosion;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setImmuneToFire(@org.jetbrains.annotations.Nullable Boolean immuneToFire) {
|
|
+ this.getHandle().immuneToFire = (immuneToFire != null && immuneToFire);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setImmuneToFire(boolean immuneToFire) {
|
|
+ this.setImmuneToFire((Boolean) immuneToFire);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isImmuneToFire() {
|
|
+ return this.getHandle().immuneToFire;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setImmuneToLightning(boolean immuneToLightning) {
|
|
+ this.getHandle().immuneToLightning = immuneToLightning;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isImmuneToLightning() {
|
|
+ return this.getHandle().immuneToLightning;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
|
index d0c409f4efad289e3e325f44b500fc72589d89d4..051ffc663317fe5a4fafe0750c89fafdece4d316 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
|
@@ -523,7 +523,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
|
net.minecraft.server.level.ServerPlayer entityPlayer = killer == null ? null : ((CraftPlayer) killer).getHandle();
|
|
getHandle().lastHurtByPlayer = entityPlayer;
|
|
getHandle().lastHurtByMob = entityPlayer;
|
|
- getHandle().lastHurtByPlayerTime = entityPlayer == null ? 0 : 100; // 100 value taken from EntityLiving#damageEntity
|
|
+ getHandle().lastHurtByPlayerTime = entityPlayer == null ? 0 : getHandle().level().purpurConfig.mobLastHurtByPlayerTime; // 100 value taken from EntityLiving#damageEntity // Purpur
|
|
}
|
|
// Paper end
|
|
|
|
@@ -1211,4 +1211,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
|
return this.getHandle().canUseSlot(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot));
|
|
}
|
|
// Paper end - Expose canUseSlot
|
|
+
|
|
+ // Purpur start - API for any mob to burn daylight
|
|
+ @Override
|
|
+ public boolean shouldBurnInDay() {
|
|
+ return this.getHandle().shouldBurnInDay();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setShouldBurnInDay(final boolean shouldBurnInDay) {
|
|
+ this.getHandle().setShouldBurnInDay(shouldBurnInDay);
|
|
+ }
|
|
+ // Purpur end - API for any mob to burn daylight
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java
|
|
index 351f42842b780d053cd2e5bad9ae299449141b10..4860574e7fad7a9527dda599703c573c5b4b234b 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java
|
|
@@ -90,4 +90,16 @@ public class CraftLlama extends CraftChestedHorse implements Llama, com.destroys
|
|
return this.getHandle().caravanTail == null ? null : (Llama) this.getHandle().caravanTail.getBukkitEntity();
|
|
}
|
|
// Paper end
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean shouldJoinCaravan() {
|
|
+ return getHandle().shouldJoinCaravan;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setShouldJoinCaravan(boolean shouldJoinCaravan) {
|
|
+ getHandle().shouldJoinCaravan = shouldJoinCaravan;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
index 2c7ec674f55b3178b9dcba7f2bc1ff5efccb50ea..48ad261eec1b74fad5a4fc1516b75fd2aaecd528 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
@@ -583,10 +583,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|
|
|
@Override
|
|
public void setPlayerListName(String name) {
|
|
+ // Purpur start
|
|
+ setPlayerListName(name, false);
|
|
+ }
|
|
+ public void setPlayerListName(String name, boolean useMM) {
|
|
+ // Purpur end
|
|
if (name == null) {
|
|
name = this.getName();
|
|
}
|
|
- this.getHandle().listName = name.equals(this.getName()) ? null : CraftChatMessage.fromStringOrNull(name);
|
|
+ this.getHandle().listName = name.equals(this.getName()) ? null : useMM ? io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(name)) : CraftChatMessage.fromStringOrNull(name); // Purpur
|
|
if (this.getHandle().connection == null) return; // Paper - Updates are possible before the player has fully joined
|
|
for (ServerPlayer player : (List<ServerPlayer>) this.server.getHandle().players) {
|
|
if (player.getBukkitEntity().canSee(this)) {
|
|
@@ -1445,6 +1450,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|
// Paper start - Teleport passenger API
|
|
// Don't allow teleporting between worlds while keeping passengers
|
|
if (ignorePassengers && entity.isVehicle() && location.getWorld() != this.getWorld()) {
|
|
+ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, cause).callEvent()) // Purpur start
|
|
return false;
|
|
}
|
|
|
|
@@ -1466,6 +1472,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|
}
|
|
|
|
if (entity.isVehicle() && !ignorePassengers) { // Paper - Teleport API
|
|
+ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, cause).callEvent()) // Purpur start
|
|
return false;
|
|
}
|
|
|
|
@@ -2779,6 +2786,28 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|
return this.getHandle().getAbilities().walkingSpeed * 2f;
|
|
}
|
|
|
|
+ // Purpur start - OfflinePlayer API
|
|
+ @Override
|
|
+ public boolean teleportOffline(@NotNull Location destination) {
|
|
+ return this.teleport(destination);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean teleportOffline(Location destination, PlayerTeleportEvent.TeleportCause cause) {
|
|
+ return this.teleport(destination, cause);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public java.util.concurrent.CompletableFuture<Boolean> teleportOfflineAsync(@NotNull Location destination) {
|
|
+ return this.teleportAsync(destination);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public java.util.concurrent.CompletableFuture<Boolean> teleportOfflineAsync(@NotNull Location destination, PlayerTeleportEvent.TeleportCause cause) {
|
|
+ return this.teleportAsync(destination, cause);
|
|
+ }
|
|
+ // Purpur end - OfflinePlayer API
|
|
+
|
|
private void validateSpeed(float value) {
|
|
Preconditions.checkArgument(value <= 1f && value >= -1f, "Speed value (%s) need to be between -1f and 1f", value);
|
|
}
|
|
@@ -3590,4 +3619,70 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|
this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundEntityEventPacket(((CraftEntity) target).getHandle(), effect.getData()));
|
|
}
|
|
// Paper end - entity effect API
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ 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();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration) {
|
|
+ sendBlockHighlight(location, duration, "", 0x6400FF00);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, int argb) {
|
|
+ sendBlockHighlight(location, duration, "", argb);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, String text) {
|
|
+ sendBlockHighlight(location, duration, text, 0x6400FF00);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, String text, int argb) {
|
|
+ if (this.getHandle().connection == null) return;
|
|
+ this.getHandle().connection.send(new net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket(new net.minecraft.network.protocol.common.custom.GameTestAddMarkerDebugPayload(io.papermc.paper.util.MCUtil.toBlockPosition(location), argb, text, duration)));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, org.bukkit.Color color, int transparency) {
|
|
+ sendBlockHighlight(location, duration, "", color, transparency);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendBlockHighlight(Location location, int duration, String text, org.bukkit.Color color, int transparency) {
|
|
+ if (transparency < 0 || transparency > 255) throw new IllegalArgumentException("transparency is outside of 0-255 range");
|
|
+ sendBlockHighlight(location, duration, text, transparency << 24 | color.asRGB());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clearBlockHighlights() {
|
|
+ if (this.getHandle().connection == null) return;
|
|
+ this.getHandle().connection.send(new net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket(new net.minecraft.network.protocol.common.custom.GameTestClearMarkersDebugPayload()));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void sendDeathScreen(net.kyori.adventure.text.Component message) {
|
|
+ if (this.getHandle().connection == null) return;
|
|
+ this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundPlayerCombatKillPacket(getEntityId(), io.papermc.paper.adventure.PaperAdventure.asVanilla(message)));
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java
|
|
index 4ce2373ff71c3c1b8951646e057587a3ab09e145..4f7f6cf6ca24406570d2d29dc63dc89401119961 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java
|
|
@@ -28,4 +28,17 @@ public class CraftSnowman extends CraftGolem implements Snowman, com.destroystok
|
|
public String toString() {
|
|
return "CraftSnowman";
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ @org.jetbrains.annotations.Nullable
|
|
+ public java.util.UUID getSummoner() {
|
|
+ return getHandle().getSummoner();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner) {
|
|
+ getHandle().setSummoner(summoner);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
|
index 8e895d6f84f7d84b219f2424909dd42e5f08dec4..53dcce0701d713c5dd097340a91b8be4806de4b8 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
|
@@ -375,4 +375,11 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
|
|
getHandle().getGossips().gossips.clear();
|
|
}
|
|
// Paper end
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isLobotomized() {
|
|
+ return getHandle().isLobotomized();
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java
|
|
index 7881c6253c1d652c0c0d54a9a8accdf0a1ff0f3e..da6ccb2a38df76770821a1a2203e54e722f541ca 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java
|
|
@@ -99,4 +99,17 @@ public class CraftWither extends CraftMonster implements Wither, com.destroystok
|
|
this.getHandle().makeInvulnerable();
|
|
}
|
|
// Paper end
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ @org.jetbrains.annotations.Nullable
|
|
+ public java.util.UUID getSummoner() {
|
|
+ return getHandle().getSummoner();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner) {
|
|
+ getHandle().setSummoner(summoner);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java
|
|
index ecd33b4add46acbe4e4f8879c0601220423d66ca..1506a8c0fa490726eb4a4ae14f3aa194dc81d9ab 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java
|
|
@@ -146,4 +146,16 @@ public class CraftWolf extends CraftTameableAnimal implements Wolf {
|
|
return this.getKey().hashCode();
|
|
}
|
|
}
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean isRabid() {
|
|
+ return getHandle().isRabid();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setRabid(boolean isRabid) {
|
|
+ getHandle().setRabid(isRabid);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
index deba03eb37012c638e08e20cd1c98e9db190c790..1f22e7cf584bf7361f3ca078b9935a096d1acba6 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
@@ -602,6 +602,15 @@ public class CraftEventFactory {
|
|
// Paper end
|
|
craftServer.getPluginManager().callEvent(event);
|
|
|
|
+ // Purpur start
|
|
+ if (who != null) {
|
|
+ switch (action) {
|
|
+ case LEFT_CLICK_BLOCK, LEFT_CLICK_AIR -> who.processClick(InteractionHand.MAIN_HAND);
|
|
+ case RIGHT_CLICK_BLOCK, RIGHT_CLICK_AIR -> who.processClick(InteractionHand.OFF_HAND);
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
return event;
|
|
}
|
|
|
|
@@ -1131,7 +1140,7 @@ public class CraftEventFactory {
|
|
return CraftEventFactory.callEntityDamageEvent(source.getDirectBlock(), source.getDirectBlockState(), entity, DamageCause.LAVA, bukkitDamageSource, modifiers, modifierFunctions, cancelled);
|
|
} else if (source.getDirectBlock() != null) {
|
|
DamageCause cause;
|
|
- if (source.is(DamageTypes.CACTUS) || source.is(DamageTypes.SWEET_BERRY_BUSH) || source.is(DamageTypes.STALAGMITE) || source.is(DamageTypes.FALLING_STALACTITE) || source.is(DamageTypes.FALLING_ANVIL)) {
|
|
+ if (source.is(DamageTypes.CACTUS) || source.is(DamageTypes.SWEET_BERRY_BUSH) || source.is(DamageTypes.STALAGMITE) || source.is(DamageTypes.FALLING_STALACTITE) || source.is(DamageTypes.FALLING_ANVIL) || source.isStonecutter()) { // Purpur
|
|
cause = DamageCause.CONTACT;
|
|
} else if (source.is(DamageTypes.HOT_FLOOR)) {
|
|
cause = DamageCause.HOT_FLOOR;
|
|
@@ -1191,6 +1200,7 @@ public class CraftEventFactory {
|
|
EntityDamageEvent event;
|
|
if (damager != null) {
|
|
event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions, critical);
|
|
+ damager.processClick(InteractionHand.MAIN_HAND); // Purpur
|
|
} else {
|
|
event = new EntityDamageEvent(damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions);
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
|
|
index 6d3f9d5dab6c9a2860ae31cae24310aa2d62da7c..4f29c579f94efe59a8c78520d75676fc4875e2f0 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
|
|
@@ -145,8 +145,19 @@ public class CraftContainer extends AbstractContainerMenu {
|
|
case PLAYER:
|
|
case CHEST:
|
|
case ENDER_CHEST:
|
|
+ // Purpur start
|
|
+ this.delegate = new ChestMenu(org.purpurmc.purpur.PurpurConfig.enderChestSixRows ? net.minecraft.world.inventory.MenuType.GENERIC_9x6 : net.minecraft.world.inventory.MenuType.GENERIC_9x3, windowId, bottom, top, top.getContainerSize() / 9);
|
|
+ break;
|
|
case BARREL:
|
|
- this.delegate = new ChestMenu(net.minecraft.world.inventory.MenuType.GENERIC_9x3, windowId, bottom, top, top.getContainerSize() / 9);
|
|
+ this.delegate = new ChestMenu(switch (org.purpurmc.purpur.PurpurConfig.barrelRows) {
|
|
+ case 6 -> net.minecraft.world.inventory.MenuType.GENERIC_9x6;
|
|
+ case 5 -> net.minecraft.world.inventory.MenuType.GENERIC_9x5;
|
|
+ case 4 -> net.minecraft.world.inventory.MenuType.GENERIC_9x4;
|
|
+ case 2 -> net.minecraft.world.inventory.MenuType.GENERIC_9x2;
|
|
+ case 1 -> net.minecraft.world.inventory.MenuType.GENERIC_9x1;
|
|
+ default -> net.minecraft.world.inventory.MenuType.GENERIC_9x3;
|
|
+ }, windowId, bottom, top, top.getContainerSize() / 9);
|
|
+ // Purpur end
|
|
break;
|
|
case DISPENSER:
|
|
case DROPPER:
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
|
index af1ae3dacb628da23f7d2988c6e76d3fb2d64103..4ee2d501f882279b48edb4b8bf0824587c276bf6 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
|
@@ -84,7 +84,7 @@ public class CraftInventory implements Inventory {
|
|
|
|
@Override
|
|
public void setContents(ItemStack[] items) {
|
|
- Preconditions.checkArgument(items.length <= this.getSize(), "Invalid inventory size (%s); expected %s or less", items.length, this.getSize());
|
|
+ // Preconditions.checkArgument(items.length <= this.getSize(), "Invalid inventory size (%s); expected %s or less", items.length, this.getSize()); // Purpur
|
|
|
|
for (int i = 0; i < this.getSize(); i++) {
|
|
if (i >= items.length) {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java
|
|
index 792cb6adf0c7a6335cc5985fce8bed2e0f1149af..5734c5caffda79383ae30df20c3defb51b87f39e 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java
|
|
@@ -19,6 +19,10 @@ public class CraftInventoryAnvil extends CraftResultInventory implements AnvilIn
|
|
private int repairCost;
|
|
private int repairCostAmount;
|
|
private int maximumRepairCost;
|
|
+ // Purpur start - Anvil API
|
|
+ private boolean bypassCost;
|
|
+ private boolean canDoUnsafeEnchants;
|
|
+ // Purpur end - Anvil API
|
|
|
|
public CraftInventoryAnvil(Location location, Container inventory, Container resultInventory) {
|
|
super(inventory, resultInventory);
|
|
@@ -27,6 +31,10 @@ public class CraftInventoryAnvil extends CraftResultInventory implements AnvilIn
|
|
this.repairCost = CraftInventoryAnvil.DEFAULT_REPAIR_COST;
|
|
this.repairCostAmount = CraftInventoryAnvil.DEFAULT_REPAIR_COST_AMOUNT;
|
|
this.maximumRepairCost = CraftInventoryAnvil.DEFAULT_MAXIMUM_REPAIR_COST;
|
|
+ // Purpur start - Anvil API
|
|
+ this.bypassCost = false;
|
|
+ this.canDoUnsafeEnchants = false;
|
|
+ // Purpur end - Anvil API
|
|
}
|
|
|
|
@Override
|
|
@@ -113,4 +121,30 @@ public class CraftInventoryAnvil extends CraftResultInventory implements AnvilIn
|
|
consumer.accept(cav);
|
|
}
|
|
}
|
|
+
|
|
+ // Purpur start - Anvil API
|
|
+ @Override
|
|
+ public boolean canBypassCost() {
|
|
+ this.syncWithArbitraryViewValue((cav) -> this.bypassCost = cav.canBypassCost());
|
|
+ return this.bypassCost;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setBypassCost(boolean bypassCost) {
|
|
+ this.bypassCost = bypassCost;
|
|
+ this.syncViews((cav) -> cav.setBypassCost(bypassCost));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canDoUnsafeEnchants() {
|
|
+ this.syncWithArbitraryViewValue((cav) -> this.canDoUnsafeEnchants = cav.canDoUnsafeEnchants());
|
|
+ return this.canDoUnsafeEnchants;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setDoUnsafeEnchants(boolean canDoUnsafeEnchants) {
|
|
+ this.canDoUnsafeEnchants = canDoUnsafeEnchants;
|
|
+ this.syncViews((cav) -> cav.setDoUnsafeEnchants(canDoUnsafeEnchants));
|
|
+ }
|
|
+ // Purpur end - Anvil API
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
|
index 756c73a401437566258813946fa10c7caa8f2469..2b6f9fce59178525b1211f2133645a7991a146dd 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
|
@@ -526,4 +526,285 @@ public final class CraftItemStack extends ItemStack {
|
|
return this.pdcView;
|
|
}
|
|
// Paper end - pdc
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public String getDisplayName() {
|
|
+ return getItemMeta().getDisplayName();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setDisplayName(String name) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ itemMeta.setDisplayName(name);
|
|
+ setItemMeta(itemMeta);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasDisplayName() {
|
|
+ return hasItemMeta() && getItemMeta().hasDisplayName();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public String getLocalizedName() {
|
|
+ return getItemMeta().getLocalizedName();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setLocalizedName(String name) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ itemMeta.setLocalizedName(name);
|
|
+ setItemMeta(itemMeta);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasLocalizedName() {
|
|
+ return hasItemMeta() && getItemMeta().hasLocalizedName();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasLore() {
|
|
+ return hasItemMeta() && getItemMeta().hasLore();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasEnchant(Enchantment ench) {
|
|
+ return hasItemMeta() && getItemMeta().hasEnchant(ench);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getEnchantLevel(Enchantment ench) {
|
|
+ return getItemMeta().getEnchantLevel(ench);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Map<Enchantment, Integer> getEnchants() {
|
|
+ return getItemMeta().getEnchants();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addEnchant(Enchantment ench, int level, boolean ignoreLevelRestriction) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ boolean result = itemMeta.addEnchant(ench, level, ignoreLevelRestriction);
|
|
+ setItemMeta(itemMeta);
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeEnchant(Enchantment ench) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ boolean result = itemMeta.removeEnchant(ench);
|
|
+ setItemMeta(itemMeta);
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasEnchants() {
|
|
+ return hasItemMeta() && getItemMeta().hasEnchants();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasConflictingEnchant(Enchantment ench) {
|
|
+ return hasItemMeta() && getItemMeta().hasConflictingEnchant(ench);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setCustomModelData(Integer data) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ itemMeta.setCustomModelData(data);
|
|
+ setItemMeta(itemMeta);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getCustomModelData() {
|
|
+ return getItemMeta().getCustomModelData();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasCustomModelData() {
|
|
+ return hasItemMeta() && getItemMeta().hasCustomModelData();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasBlockData() {
|
|
+ return hasItemMeta() && ((org.bukkit.inventory.meta.BlockDataMeta) getItemMeta()).hasBlockData();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public org.bukkit.block.data.BlockData getBlockData(Material material) {
|
|
+ return ((org.bukkit.inventory.meta.BlockDataMeta) getItemMeta()).getBlockData(material);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setBlockData(org.bukkit.block.data.BlockData blockData) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ ((org.bukkit.inventory.meta.BlockDataMeta) itemMeta).setBlockData(blockData);
|
|
+ setItemMeta(itemMeta);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getRepairCost() {
|
|
+ return ((org.bukkit.inventory.meta.Repairable) getItemMeta()).getRepairCost();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setRepairCost(int cost) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ ((org.bukkit.inventory.meta.Repairable) itemMeta).setRepairCost(cost);
|
|
+ setItemMeta(itemMeta);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasRepairCost() {
|
|
+ return hasItemMeta() && ((org.bukkit.inventory.meta.Repairable) getItemMeta()).hasRepairCost();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isUnbreakable() {
|
|
+ return hasItemMeta() && getItemMeta().isUnbreakable();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setUnbreakable(boolean unbreakable) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ itemMeta.setUnbreakable(unbreakable);
|
|
+ setItemMeta(itemMeta);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasAttributeModifiers() {
|
|
+ return hasItemMeta() && getItemMeta().hasAttributeModifiers();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public com.google.common.collect.Multimap<org.bukkit.attribute.Attribute, org.bukkit.attribute.AttributeModifier> getAttributeModifiers() {
|
|
+ return getItemMeta().getAttributeModifiers();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public com.google.common.collect.Multimap<org.bukkit.attribute.Attribute, org.bukkit.attribute.AttributeModifier> getAttributeModifiers(org.bukkit.inventory.EquipmentSlot slot) {
|
|
+ return getItemMeta().getAttributeModifiers(slot);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public java.util.Collection<org.bukkit.attribute.AttributeModifier> getAttributeModifiers(org.bukkit.attribute.Attribute attribute) {
|
|
+ return getItemMeta().getAttributeModifiers(attribute);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAttributeModifier(org.bukkit.attribute.Attribute attribute, org.bukkit.attribute.AttributeModifier modifier) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ boolean result = itemMeta.addAttributeModifier(attribute, modifier);
|
|
+ setItemMeta(itemMeta);
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setAttributeModifiers(com.google.common.collect.Multimap<org.bukkit.attribute.Attribute, org.bukkit.attribute.AttributeModifier> attributeModifiers) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ itemMeta.setAttributeModifiers(attributeModifiers);
|
|
+ setItemMeta(itemMeta);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAttributeModifier(org.bukkit.attribute.Attribute attribute) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ boolean result = itemMeta.removeAttributeModifier(attribute);
|
|
+ setItemMeta(itemMeta);
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAttributeModifier(org.bukkit.inventory.EquipmentSlot slot) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ boolean result = itemMeta.removeAttributeModifier(slot);
|
|
+ setItemMeta(itemMeta);
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAttributeModifier(org.bukkit.attribute.Attribute attribute, org.bukkit.attribute.AttributeModifier modifier) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ boolean result = itemMeta.removeAttributeModifier(attribute, modifier);
|
|
+ setItemMeta(itemMeta);
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasDamage() {
|
|
+ return hasItemMeta() && ((org.bukkit.inventory.meta.Damageable) getItemMeta()).hasDamage();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getDamage() {
|
|
+ return ((org.bukkit.inventory.meta.Damageable) getItemMeta()).getDamage();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setDamage(int damage) {
|
|
+ ItemMeta itemMeta = getItemMeta();
|
|
+ ((org.bukkit.inventory.meta.Damageable) itemMeta).setDamage(damage);
|
|
+ setItemMeta(itemMeta);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void repair() {
|
|
+ repair(1);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean damage() {
|
|
+ return damage(1);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void repair(int amount) {
|
|
+ damage(-amount);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean damage(int amount) {
|
|
+ return damage(amount, false);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean damage(int amount, boolean ignoreUnbreaking) {
|
|
+ org.bukkit.inventory.meta.Damageable damageable = (org.bukkit.inventory.meta.Damageable) getItemMeta();
|
|
+ if (amount > 0) {
|
|
+ int unbreaking = getEnchantLevel(Enchantment.UNBREAKING);
|
|
+ int reduce = 0;
|
|
+ for (int i = 0; unbreaking > 0 && i < amount; ++i) {
|
|
+ if (reduceDamage(java.util.concurrent.ThreadLocalRandom.current(), unbreaking)) {
|
|
+ ++reduce;
|
|
+ }
|
|
+ }
|
|
+ amount -= reduce;
|
|
+ if (amount <= 0) {
|
|
+ return isBroke(damageable.getDamage());
|
|
+ }
|
|
+ }
|
|
+ int damage = damageable.getDamage() + amount;
|
|
+ damageable.setDamage(damage);
|
|
+ setItemMeta((ItemMeta) damageable);
|
|
+ return isBroke(damage);
|
|
+ }
|
|
+
|
|
+ private boolean isBroke(int damage) {
|
|
+ if (damage > getType().getMaxDurability()) {
|
|
+ if (getAmount() > 0) {
|
|
+ // ensure it "breaks"
|
|
+ setAmount(0);
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ private boolean reduceDamage(java.util.Random random, int unbreaking) {
|
|
+ if (getType().isArmor()) {
|
|
+ return random.nextFloat() < 0.6F;
|
|
+ }
|
|
+ return random.nextInt(unbreaking + 1) > 0;
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java b/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java
|
|
index f86c95a13dff012de5db3e41ac261e9e8d44d9f3..1db0b790d824e419bb5fb6ab1f3003e120f9763b 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java
|
|
@@ -75,4 +75,26 @@ public class CraftAnvilView extends CraftInventoryView<AnvilMenu, AnvilInventory
|
|
this.setMaximumRepairCost(legacy.getMaximumRepairCost());
|
|
}
|
|
}
|
|
+
|
|
+ // Purpur start - Anvil API
|
|
+ @Override
|
|
+ public boolean canBypassCost() {
|
|
+ return this.container.bypassCost;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setBypassCost(boolean bypassCost) {
|
|
+ this.container.bypassCost = bypassCost;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canDoUnsafeEnchants() {
|
|
+ return this.container.canDoUnsafeEnchants;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setDoUnsafeEnchants(boolean canDoUnsafeEnchants) {
|
|
+ this.container.canDoUnsafeEnchants = canDoUnsafeEnchants;
|
|
+ }
|
|
+ // Purpur end - Anvil API
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java
|
|
index 51ae8eddadc87b143b93521a3cef374f1e3a24dc..a7b45602d9d86aec235eef06d252fb6225f17f6e 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java
|
|
@@ -265,6 +265,7 @@ public final class CraftLegacy {
|
|
}
|
|
|
|
static {
|
|
+ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressInitLegacyMaterialError) // Purpur
|
|
LOGGER.warn("Initializing Legacy Material Support. Unless you have legacy plugins and/or data this is a bug!"); // Paper - Improve logging and errors; doesn't need to be an error
|
|
if (MinecraftServer.getServer() != null && MinecraftServer.getServer().isDebugging()) {
|
|
new Exception().printStackTrace();
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java
|
|
index db8d8e2a07296d62c3097f02b03319e2e1ba9394..e5c30847297e056782084d81fb9300f98d4a8f75 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java
|
|
@@ -708,4 +708,32 @@ public class MaterialRerouting {
|
|
meta.setCanPlaceOn(materials);
|
|
}
|
|
// Paper end
|
|
+ // Purpur start
|
|
+ // Method added post 1.13, no-op (https://github.com/PurpurMC/Purpur/pull/570)
|
|
+ public static void addFuel(Server server, Material material, int burnTime) {
|
|
+ server.addFuel(material, burnTime);
|
|
+ }
|
|
+
|
|
+ // Method added post 1.13, no-op (https://github.com/PurpurMC/Purpur/pull/570)
|
|
+ public static void removeFuel(Server server, Material material) {
|
|
+ server.removeFuel(material);
|
|
+ }
|
|
+
|
|
+ // Method added post 1.13, no-op (https://github.com/PurpurMC/Purpur/pull/570)
|
|
+ @RerouteStatic("org/bukkit/Bukkit")
|
|
+ public static void addFuel(Material material, int burnTime) {
|
|
+ Bukkit.addFuel(material, burnTime);
|
|
+ }
|
|
+
|
|
+ // Method added post 1.13, no-op (https://github.com/PurpurMC/Purpur/pull/570)
|
|
+ @RerouteStatic("org/bukkit/Bukkit")
|
|
+ public static void removeFuel(Material material) {
|
|
+ Bukkit.removeFuel(material);
|
|
+ }
|
|
+
|
|
+ // Method added post 1.13, no-op (https://github.com/PurpurMC/Purpur/commit/607d909efba516893072b782c0393c53d048210e)
|
|
+ public static BlockData getBlockData(ItemStack itemStack, Material material) {
|
|
+ return itemStack.getBlockData(MaterialRerouting.transformToBlockType(material));
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java
|
|
index 0cbbd915631904fe8c6effefb92895422b33eff6..aef19cfbecb4ddfc8dc71c4f3b2a011364c12dc2 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java
|
|
@@ -47,4 +47,10 @@ public class CraftMapRenderer extends MapRenderer {
|
|
}
|
|
}
|
|
|
|
+ // Purpur - start
|
|
+ @Override
|
|
+ public boolean isExplorerMap() {
|
|
+ return this.worldMap.isExplorerMap;
|
|
+ }
|
|
+ // Purpur - end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
|
index 6fef86e47e37eab6721cfd67d494afb25a2ded68..c914e1e13c4f64f24efa5f825e58efb69632bfa6 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
|
@@ -491,7 +491,7 @@ public class CraftScheduler implements BukkitScheduler {
|
|
this.parsePending();
|
|
} else {
|
|
// this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(this.currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass())); // Paper
|
|
- task.getOwner().getLogger().log(Level.SEVERE, "Unexpected Async Task in the Sync Scheduler. Report this to Paper"); // Paper
|
|
+ task.getOwner().getLogger().log(Level.SEVERE, "Unexpected Async Task in the Sync Scheduler. Report this to Purpur"); // Paper // Purpur
|
|
// We don't need to parse pending
|
|
// (async tasks must live with race-conditions if they attempt to cancel between these few lines of code)
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
|
index 83020837e29ee627b1081daddb4bdee147b95af3..9bd91ddb964ff4d10a3a87ee50849ddf3c4d22e8 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
|
@@ -505,7 +505,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
|
// Paper start
|
|
@Override
|
|
public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() {
|
|
- return new com.destroystokyo.paper.PaperVersionFetcher();
|
|
+ return new com.destroystokyo.paper.PaperVersionFetcher(); // Pufferfish // Purpur
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
|
index 774556a62eb240da42e84db4502e2ed43495be17..99597258e8e88cd9e2c901c4ac3ff7faeeabee2b 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
|
@@ -11,7 +11,7 @@ public final class Versioning {
|
|
public static String getBukkitVersion() {
|
|
String result = "Unknown-Version";
|
|
|
|
- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties");
|
|
+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/org.purpurmc.purpur/purpur-api/pom.properties"); // Pufferfish // Purpur
|
|
Properties properties = new Properties();
|
|
|
|
if (stream != null) {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java
|
|
index 52649f82351ab4f675c3cc3cd6640956b0f76b91..eb51c88c7a0658190d3a8bfd5d18dca79d85fba0 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java
|
|
@@ -23,7 +23,15 @@ public final class CommandPermissions {
|
|
DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "kick", "Allows the user to kick players", PermissionDefault.OP, commands);
|
|
DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "stop", "Allows the user to stop the server", PermissionDefault.OP, commands);
|
|
DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "list", "Allows the user to list all online players", PermissionDefault.OP, commands);
|
|
- DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "gamemode", "Allows the user to change the gamemode of another player", PermissionDefault.OP, commands);
|
|
+ // Purpur start
|
|
+ Permission gamemodeVanilla = DefaultPermissions.registerPermission(PREFIX + "gamemode", "Allows the user to change the gamemode", PermissionDefault.OP, commands);
|
|
+ for (net.minecraft.world.level.GameType gametype : net.minecraft.world.level.GameType.values()) {
|
|
+ Permission gamemodeSelf = DefaultPermissions.registerPermission(PREFIX + "gamemode." + gametype.getName(), "Allows the user to set " + gametype.getName() + " gamemode for self", PermissionDefault.OP);
|
|
+ Permission gamemodeOther = DefaultPermissions.registerPermission(PREFIX + "gamemode." + gametype.getName() + ".other", "Allows the user to set " + gametype.getName() + " gamemode for other players", PermissionDefault.OP);
|
|
+ gamemodeSelf.addParent(gamemodeOther, true);
|
|
+ gamemodeVanilla.addParent(gamemodeSelf, true);
|
|
+ }
|
|
+ // Purpur end
|
|
DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "experience", "Allows the user to give themselves or others arbitrary values of experience", PermissionDefault.OP, commands); // Paper - wrong permission; redirects are de-redirected and the root literal name is used, so xp -> experience
|
|
DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "defaultgamemode", "Allows the user to change the default gamemode of the server", PermissionDefault.OP, commands);
|
|
DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "seed", "Allows the user to view the seed of the world", PermissionDefault.OP, commands);
|
|
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..95cd1156766895546ef5574b33a60806bff08fa2
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
|
|
@@ -0,0 +1,606 @@
|
|
+package org.purpurmc.purpur;
|
|
+
|
|
+import com.google.common.base.Throwables;
|
|
+import com.google.common.collect.ImmutableMap;
|
|
+import com.mojang.datafixers.util.Pair;
|
|
+import net.kyori.adventure.bossbar.BossBar;
|
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
+import net.minecraft.core.Registry;
|
|
+import net.minecraft.core.registries.BuiltInRegistries;
|
|
+import net.minecraft.core.registries.Registries;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.world.effect.MobEffect;
|
|
+import net.minecraft.world.effect.MobEffectInstance;
|
|
+import net.minecraft.world.entity.EntityDimensions;
|
|
+import net.minecraft.world.entity.EntityType;
|
|
+import net.minecraft.world.food.FoodProperties;
|
|
+import net.minecraft.world.food.Foods;
|
|
+import net.minecraft.world.item.enchantment.Enchantment;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import net.minecraft.world.level.block.Blocks;
|
|
+import net.minecraft.world.level.block.state.BlockBehaviour;
|
|
+import org.bukkit.Bukkit;
|
|
+import org.bukkit.command.Command;
|
|
+import org.bukkit.configuration.ConfigurationSection;
|
|
+import org.bukkit.configuration.InvalidConfigurationException;
|
|
+import org.bukkit.configuration.file.YamlConfiguration;
|
|
+import org.purpurmc.purpur.command.PurpurCommand;
|
|
+import org.purpurmc.purpur.task.TPSBarTask;
|
|
+
|
|
+import java.io.File;
|
|
+import java.io.IOException;
|
|
+import java.lang.reflect.InvocationTargetException;
|
|
+import java.lang.reflect.Method;
|
|
+import java.lang.reflect.Modifier;
|
|
+import java.util.ArrayList;
|
|
+import java.util.Collections;
|
|
+import java.util.HashMap;
|
|
+import java.util.HashSet;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Set;
|
|
+import java.util.logging.Level;
|
|
+
|
|
+@SuppressWarnings("unused")
|
|
+public class PurpurConfig {
|
|
+ private static final String HEADER = "This is the main configuration file for Purpur.\n"
|
|
+ + "As you can see, there's tons to configure. Some options may impact gameplay, so use\n"
|
|
+ + "with caution, and make sure you know what each option does before configuring.\n"
|
|
+ + "\n"
|
|
+ + "If you need help with the configuration or have any questions related to Purpur,\n"
|
|
+ + "join us in our Discord guild.\n"
|
|
+ + "\n"
|
|
+ + "Website: https://purpurmc.org \n"
|
|
+ + "Docs: https://purpurmc.org/docs \n";
|
|
+ private static File CONFIG_FILE;
|
|
+ public static YamlConfiguration config;
|
|
+
|
|
+ private static Map<String, Command> commands;
|
|
+
|
|
+ public static int version;
|
|
+ static boolean verbose;
|
|
+
|
|
+ public static void init(File configFile) {
|
|
+ CONFIG_FILE = configFile;
|
|
+ config = new YamlConfiguration();
|
|
+ try {
|
|
+ config.load(CONFIG_FILE);
|
|
+ } catch (IOException ignore) {
|
|
+ } catch (InvalidConfigurationException ex) {
|
|
+ Bukkit.getLogger().log(Level.SEVERE, "Could not load purpur.yml, please correct your syntax errors", ex);
|
|
+ throw Throwables.propagate(ex);
|
|
+ }
|
|
+ config.options().header(HEADER);
|
|
+ config.options().copyDefaults(true);
|
|
+ verbose = getBoolean("verbose", false);
|
|
+
|
|
+ commands = new HashMap<>();
|
|
+ commands.put("purpur", new PurpurCommand("purpur"));
|
|
+
|
|
+ version = getInt("config-version", 37);
|
|
+ set("config-version", 37);
|
|
+
|
|
+ readConfig(PurpurConfig.class, null);
|
|
+
|
|
+ Block.BLOCK_STATE_REGISTRY.forEach(BlockBehaviour.BlockStateBase::initCache);
|
|
+ }
|
|
+
|
|
+ protected static void log(String s) {
|
|
+ if (verbose) {
|
|
+ log(Level.INFO, s);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ protected static void log(Level level, String s) {
|
|
+ Bukkit.getLogger().log(level, s);
|
|
+ }
|
|
+
|
|
+ public static void registerCommands() {
|
|
+ for (Map.Entry<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();
|
|
+ }
|
|
+
|
|
+ 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 boolean afkBroadcastUseDisplayName = false;
|
|
+ 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";
|
|
+ public static String ramCommandOutput = "<green>Ram Usage: <used>/<xmx> (<percent>)";
|
|
+ public static String rambarCommandOutput = "<green>Rambar toggled <onoff> for <target>";
|
|
+ public static String tpsbarCommandOutput = "<green>Tpsbar toggled <onoff> for <target>";
|
|
+ public static String dontRunWithScissors = "<red><italic>Don't run with scissors!";
|
|
+ public static String uptimeCommandOutput = "<green>Server uptime is <uptime>";
|
|
+ public static String unverifiedUsername = "default";
|
|
+ public static String sleepSkippingNight = "default";
|
|
+ public static String sleepingPlayersPercent = "default";
|
|
+ public static String sleepNotPossible = "default";
|
|
+ private static void messages() {
|
|
+ cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob);
|
|
+ afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway);
|
|
+ afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack);
|
|
+ afkBroadcastUseDisplayName = getBoolean("settings.messages.afk-broadcast-use-display-name", afkBroadcastUseDisplayName);
|
|
+ afkTabListPrefix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix)));
|
|
+ afkTabListSuffix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix)));
|
|
+ creditsCommandOutput = getString("settings.messages.credits-command-output", creditsCommandOutput);
|
|
+ demoCommandOutput = getString("settings.messages.demo-command-output", demoCommandOutput);
|
|
+ pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput);
|
|
+ ramCommandOutput = getString("settings.messages.ram-command-output", ramCommandOutput);
|
|
+ rambarCommandOutput = getString("settings.messages.rambar-command-output", rambarCommandOutput);
|
|
+ tpsbarCommandOutput = getString("settings.messages.tpsbar-command-output", tpsbarCommandOutput);
|
|
+ dontRunWithScissors = getString("settings.messages.dont-run-with-scissors", dontRunWithScissors);
|
|
+ uptimeCommandOutput = getString("settings.messages.uptime-command-output", uptimeCommandOutput);
|
|
+ unverifiedUsername = getString("settings.messages.unverified-username", unverifiedUsername);
|
|
+ sleepSkippingNight = getString("settings.messages.sleep-skipping-night", sleepSkippingNight);
|
|
+ sleepingPlayersPercent = getString("settings.messages.sleeping-players-percent", sleepingPlayersPercent);
|
|
+ sleepNotPossible = getString("settings.messages.sleep-not-possible", sleepNotPossible);
|
|
+ }
|
|
+
|
|
+ public static String deathMsgRunWithScissors = "<player> slipped and fell on their shears";
|
|
+ public static String deathMsgStonecutter = "<player> has sawed themself in half";
|
|
+ private static void deathMessages() {
|
|
+ deathMsgRunWithScissors = getString("settings.messages.death-message.run-with-scissors", deathMsgRunWithScissors);
|
|
+ deathMsgStonecutter = getString("settings.messages.death-message.stonecutter", deathMsgStonecutter);
|
|
+ }
|
|
+
|
|
+ public static boolean advancementOnlyBroadcastToAffectedPlayer = false;
|
|
+ public static boolean deathMessageOnlyBroadcastToAffectedPlayer = false;
|
|
+ private static void broadcastSettings() {
|
|
+ if (version < 13) {
|
|
+ boolean oldValue = getBoolean("settings.advancement.only-broadcast-to-affected-player", false);
|
|
+ set("settings.broadcasts.advancement.only-broadcast-to-affected-player", oldValue);
|
|
+ set("settings.advancement.only-broadcast-to-affected-player", null);
|
|
+ }
|
|
+ advancementOnlyBroadcastToAffectedPlayer = getBoolean("settings.broadcasts.advancement.only-broadcast-to-affected-player", advancementOnlyBroadcastToAffectedPlayer);
|
|
+ deathMessageOnlyBroadcastToAffectedPlayer = getBoolean("settings.broadcasts.death.only-broadcast-to-affected-player", deathMessageOnlyBroadcastToAffectedPlayer);
|
|
+ }
|
|
+
|
|
+ public static String serverModName = io.papermc.paper.ServerBuildInfo.buildInfo().brandName();
|
|
+ private static void serverModName() {
|
|
+ serverModName = getString("settings.server-mod-name", serverModName);
|
|
+ }
|
|
+
|
|
+ public static double laggingThreshold = 19.0D;
|
|
+ private static void tickLoopSettings() {
|
|
+ laggingThreshold = getDouble("settings.lagging-threshold", laggingThreshold);
|
|
+ }
|
|
+
|
|
+ public static boolean useAlternateKeepAlive = false;
|
|
+ private static void useAlternateKeepAlive() {
|
|
+ useAlternateKeepAlive = getBoolean("settings.use-alternate-keepalive", useAlternateKeepAlive);
|
|
+ }
|
|
+
|
|
+ public static boolean disableGiveCommandDrops = false;
|
|
+ private static void disableGiveCommandDrops() {
|
|
+ disableGiveCommandDrops = getBoolean("settings.disable-give-dropping", disableGiveCommandDrops);
|
|
+ }
|
|
+
|
|
+ public static String commandRamBarTitle = "<gray>Ram<yellow>:</yellow> <used>/<xmx> (<percent>)";
|
|
+ public static BossBar.Overlay commandRamBarProgressOverlay = BossBar.Overlay.NOTCHED_20;
|
|
+ public static BossBar.Color commandRamBarProgressColorGood = BossBar.Color.GREEN;
|
|
+ public static BossBar.Color commandRamBarProgressColorMedium = BossBar.Color.YELLOW;
|
|
+ public static BossBar.Color commandRamBarProgressColorLow = BossBar.Color.RED;
|
|
+ public static String commandRamBarTextColorGood = "<gradient:#55ff55:#00aa00><text></gradient>";
|
|
+ public static String commandRamBarTextColorMedium = "<gradient:#ffff55:#ffaa00><text></gradient>";
|
|
+ public static String commandRamBarTextColorLow = "<gradient:#ff5555:#aa0000><text></gradient>";
|
|
+ public static int commandRamBarTickInterval = 20;
|
|
+ public static String commandTPSBarTitle = "<gray>TPS<yellow>:</yellow> <tps> MSPT<yellow>:</yellow> <mspt> Ping<yellow>:</yellow> <ping>ms";
|
|
+ public static BossBar.Overlay commandTPSBarProgressOverlay = BossBar.Overlay.NOTCHED_20;
|
|
+ public static TPSBarTask.FillMode commandTPSBarProgressFillMode = TPSBarTask.FillMode.MSPT;
|
|
+ public static BossBar.Color commandTPSBarProgressColorGood = BossBar.Color.GREEN;
|
|
+ public static BossBar.Color commandTPSBarProgressColorMedium = BossBar.Color.YELLOW;
|
|
+ public static BossBar.Color commandTPSBarProgressColorLow = BossBar.Color.RED;
|
|
+ public static String commandTPSBarTextColorGood = "<gradient:#55ff55:#00aa00><text></gradient>";
|
|
+ public static String commandTPSBarTextColorMedium = "<gradient:#ffff55:#ffaa00><text></gradient>";
|
|
+ public static String commandTPSBarTextColorLow = "<gradient:#ff5555:#aa0000><text></gradient>";
|
|
+ public static int commandTPSBarTickInterval = 20;
|
|
+ public static String commandCompassBarTitle = "S \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 SW \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 W \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 NW \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 N \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 NE \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 E \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 SE \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 S \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 SW \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 W \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 NW \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 N \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 NE \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 E \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 SE \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 ";
|
|
+ public static BossBar.Overlay commandCompassBarProgressOverlay = BossBar.Overlay.PROGRESS;
|
|
+ public static BossBar.Color commandCompassBarProgressColor = BossBar.Color.BLUE;
|
|
+ public static float commandCompassBarProgressPercent = 1.0F;
|
|
+ public static int commandCompassBarTickInterval = 5;
|
|
+ public static boolean commandGamemodeRequiresPermission = false;
|
|
+ public static boolean hideHiddenPlayersFromEntitySelector = false;
|
|
+ public static String uptimeFormat = "<days><hours><minutes><seconds>";
|
|
+ public static String uptimeDay = "%02d day, ";
|
|
+ public static String uptimeDays = "%02d days, ";
|
|
+ public static String uptimeHour = "%02d hour, ";
|
|
+ public static String uptimeHours = "%02d hours, ";
|
|
+ public static String uptimeMinute = "%02d minute, and ";
|
|
+ public static String uptimeMinutes = "%02d minutes, and ";
|
|
+ public static String uptimeSecond = "%02d second";
|
|
+ public static String uptimeSeconds = "%02d seconds";
|
|
+ private static void commandSettings() {
|
|
+ commandRamBarTitle = getString("settings.command.rambar.title", commandRamBarTitle);
|
|
+ commandRamBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.rambar.overlay", commandRamBarProgressOverlay.name()));
|
|
+ commandRamBarProgressColorGood = BossBar.Color.valueOf(getString("settings.command.rambar.progress-color.good", commandRamBarProgressColorGood.name()));
|
|
+ commandRamBarProgressColorMedium = BossBar.Color.valueOf(getString("settings.command.rambar.progress-color.medium", commandRamBarProgressColorMedium.name()));
|
|
+ commandRamBarProgressColorLow = BossBar.Color.valueOf(getString("settings.command.rambar.progress-color.low", commandRamBarProgressColorLow.name()));
|
|
+ commandRamBarTextColorGood = getString("settings.command.rambar.text-color.good", commandRamBarTextColorGood);
|
|
+ commandRamBarTextColorMedium = getString("settings.command.rambar.text-color.medium", commandRamBarTextColorMedium);
|
|
+ commandRamBarTextColorLow = getString("settings.command.rambar.text-color.low", commandRamBarTextColorLow);
|
|
+ commandRamBarTickInterval = getInt("settings.command.rambar.tick-interval", commandRamBarTickInterval);
|
|
+
|
|
+ commandTPSBarTitle = getString("settings.command.tpsbar.title", commandTPSBarTitle);
|
|
+ commandTPSBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.tpsbar.overlay", commandTPSBarProgressOverlay.name()));
|
|
+ commandTPSBarProgressFillMode = TPSBarTask.FillMode.valueOf(getString("settings.command.tpsbar.fill-mode", commandTPSBarProgressFillMode.name()));
|
|
+ commandTPSBarProgressColorGood = BossBar.Color.valueOf(getString("settings.command.tpsbar.progress-color.good", commandTPSBarProgressColorGood.name()));
|
|
+ commandTPSBarProgressColorMedium = BossBar.Color.valueOf(getString("settings.command.tpsbar.progress-color.medium", commandTPSBarProgressColorMedium.name()));
|
|
+ commandTPSBarProgressColorLow = BossBar.Color.valueOf(getString("settings.command.tpsbar.progress-color.low", commandTPSBarProgressColorLow.name()));
|
|
+ commandTPSBarTextColorGood = getString("settings.command.tpsbar.text-color.good", commandTPSBarTextColorGood);
|
|
+ commandTPSBarTextColorMedium = getString("settings.command.tpsbar.text-color.medium", commandTPSBarTextColorMedium);
|
|
+ commandTPSBarTextColorLow = getString("settings.command.tpsbar.text-color.low", commandTPSBarTextColorLow);
|
|
+ commandTPSBarTickInterval = getInt("settings.command.tpsbar.tick-interval", commandTPSBarTickInterval);
|
|
+
|
|
+ commandCompassBarTitle = getString("settings.command.compass.title", commandCompassBarTitle);
|
|
+ commandCompassBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.compass.overlay", commandCompassBarProgressOverlay.name()));
|
|
+ commandCompassBarProgressColor = BossBar.Color.valueOf(getString("settings.command.compass.progress-color", commandCompassBarProgressColor.name()));
|
|
+ commandCompassBarProgressPercent = (float) getDouble("settings.command.compass.percent", commandCompassBarProgressPercent);
|
|
+ commandCompassBarTickInterval = getInt("settings.command.compass.tick-interval", commandCompassBarTickInterval);
|
|
+
|
|
+ commandGamemodeRequiresPermission = getBoolean("settings.command.gamemode.requires-specific-permission", commandGamemodeRequiresPermission);
|
|
+ hideHiddenPlayersFromEntitySelector = getBoolean("settings.command.hide-hidden-players-from-entity-selector", hideHiddenPlayersFromEntitySelector);
|
|
+ uptimeFormat = getString("settings.command.uptime.format", uptimeFormat);
|
|
+ uptimeDay = getString("settings.command.uptime.day", uptimeDay);
|
|
+ uptimeDays = getString("settings.command.uptime.days", uptimeDays);
|
|
+ uptimeHour = getString("settings.command.uptime.hour", uptimeHour);
|
|
+ uptimeHours = getString("settings.command.uptime.hours", uptimeHours);
|
|
+ uptimeMinute = getString("settings.command.uptime.minute", uptimeMinute);
|
|
+ uptimeMinutes = getString("settings.command.uptime.minutes", uptimeMinutes);
|
|
+ uptimeSecond = getString("settings.command.uptime.second", uptimeSecond);
|
|
+ uptimeSeconds = getString("settings.command.uptime.seconds", uptimeSeconds);
|
|
+ }
|
|
+
|
|
+ public static int barrelRows = 3;
|
|
+ public static boolean enderChestSixRows = false;
|
|
+ public static boolean enderChestPermissionRows = false;
|
|
+ public static boolean cryingObsidianValidForPortalFrame = false;
|
|
+ public static int beeInsideBeeHive = 3;
|
|
+ public static boolean anvilCumulativeCost = true;
|
|
+ public static int lightningRodRange = 128;
|
|
+ public static Set<Enchantment> grindstoneIgnoredEnchants = new HashSet<>();
|
|
+ public static boolean grindstoneRemoveAttributes = false;
|
|
+ public static boolean grindstoneRemoveDisplay = false;
|
|
+ public static int caveVinesMaxGrowthAge = 25;
|
|
+ public static int kelpMaxGrowthAge = 25;
|
|
+ public static int twistingVinesMaxGrowthAge = 25;
|
|
+ public static int weepingVinesMaxGrowthAge = 25;
|
|
+ public static boolean magmaBlockReverseBubbleColumnFlow = false;
|
|
+ public static boolean soulSandBlockReverseBubbleColumnFlow = false;
|
|
+ private static void blockSettings() {
|
|
+ if (version < 3) {
|
|
+ boolean oldValue = getBoolean("settings.barrel.packed-barrels", true);
|
|
+ set("settings.blocks.barrel.six-rows", oldValue);
|
|
+ set("settings.packed-barrels", null);
|
|
+ oldValue = getBoolean("settings.large-ender-chests", true);
|
|
+ set("settings.blocks.ender_chest.six-rows", oldValue);
|
|
+ set("settings.large-ender-chests", null);
|
|
+ }
|
|
+ if (version < 20) {
|
|
+ boolean oldValue = getBoolean("settings.blocks.barrel.six-rows", false);
|
|
+ set("settings.blocks.barrel.rows", oldValue ? 6 : 3);
|
|
+ set("settings.blocks.barrel.six-rows", null);
|
|
+ }
|
|
+ barrelRows = getInt("settings.blocks.barrel.rows", barrelRows);
|
|
+ if (barrelRows < 1 || barrelRows > 6) {
|
|
+ Bukkit.getLogger().severe("settings.blocks.barrel.rows must be 1-6, resetting to default");
|
|
+ barrelRows = 3;
|
|
+ }
|
|
+ org.bukkit.event.inventory.InventoryType.BARREL.setDefaultSize(switch (barrelRows) {
|
|
+ case 6 -> 54;
|
|
+ case 5 -> 45;
|
|
+ case 4 -> 36;
|
|
+ case 2 -> 18;
|
|
+ case 1 -> 9;
|
|
+ default -> 27;
|
|
+ });
|
|
+ enderChestSixRows = getBoolean("settings.blocks.ender_chest.six-rows", enderChestSixRows);
|
|
+ org.bukkit.event.inventory.InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27);
|
|
+ enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows);
|
|
+ cryingObsidianValidForPortalFrame = getBoolean("settings.blocks.crying_obsidian.valid-for-portal-frame", cryingObsidianValidForPortalFrame);
|
|
+ beeInsideBeeHive = getInt("settings.blocks.beehive.max-bees-inside", beeInsideBeeHive);
|
|
+ anvilCumulativeCost = getBoolean("settings.blocks.anvil.cumulative-cost", anvilCumulativeCost);
|
|
+ lightningRodRange = getInt("settings.blocks.lightning_rod.range", lightningRodRange);
|
|
+ ArrayList<String> defaultCurses = new ArrayList<>(){{
|
|
+ add("minecraft:binding_curse");
|
|
+ add("minecraft:vanishing_curse");
|
|
+ }};
|
|
+ if (version < 24 && !getBoolean("settings.blocks.grindstone.ignore-curses", true)) {
|
|
+ defaultCurses.clear();
|
|
+ }
|
|
+ getList("settings.blocks.grindstone.ignored-enchants", defaultCurses).forEach(key -> {
|
|
+ Registry<Enchantment> registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.ENCHANTMENT);
|
|
+ Enchantment enchantment = registry.getValue(ResourceLocation.parse(key.toString()));
|
|
+ if (enchantment == null) return;
|
|
+ grindstoneIgnoredEnchants.add(enchantment);
|
|
+ });
|
|
+ grindstoneRemoveAttributes = getBoolean("settings.blocks.grindstone.remove-attributes", grindstoneRemoveAttributes);
|
|
+ grindstoneRemoveDisplay = getBoolean("settings.blocks.grindstone.remove-name-and-lore", grindstoneRemoveDisplay);
|
|
+ caveVinesMaxGrowthAge = getInt("settings.blocks.cave_vines.max-growth-age", caveVinesMaxGrowthAge);
|
|
+ if (caveVinesMaxGrowthAge > 25) {
|
|
+ caveVinesMaxGrowthAge = 25;
|
|
+ log(Level.WARNING, "blocks.cave_vines.max-growth-age is set to above maximum allowed value of 25");
|
|
+ log(Level.WARNING, "Using value of 25 to prevent issues");
|
|
+ }
|
|
+ kelpMaxGrowthAge = getInt("settings.blocks.kelp.max-growth-age", kelpMaxGrowthAge);
|
|
+ if (kelpMaxGrowthAge > 25) {
|
|
+ kelpMaxGrowthAge = 25;
|
|
+ log(Level.WARNING, "blocks.kelp.max-growth-age is set to above maximum allowed value of 25");
|
|
+ log(Level.WARNING, "Using value of 25 to prevent issues");
|
|
+ }
|
|
+ twistingVinesMaxGrowthAge = getInt("settings.blocks.twisting_vines.max-growth-age", twistingVinesMaxGrowthAge);
|
|
+ if (twistingVinesMaxGrowthAge > 25) {
|
|
+ twistingVinesMaxGrowthAge = 25;
|
|
+ log(Level.WARNING, "blocks.twisting_vines.max-growth-age is set to above maximum allowed value of 25");
|
|
+ log(Level.WARNING, "Using value of 25 to prevent issues");
|
|
+ }
|
|
+ weepingVinesMaxGrowthAge = getInt("settings.blocks.weeping_vines.max-growth-age", weepingVinesMaxGrowthAge);
|
|
+ if (weepingVinesMaxGrowthAge > 25) {
|
|
+ weepingVinesMaxGrowthAge = 25;
|
|
+ log(Level.WARNING, "blocks.weeping_vines.max-growth-age is set to above maximum allowed value of 25");
|
|
+ log(Level.WARNING, "Using value of 25 to prevent issues");
|
|
+ }
|
|
+ magmaBlockReverseBubbleColumnFlow = getBoolean("settings.blocks.magma-block.reverse-bubble-column-flow", magmaBlockReverseBubbleColumnFlow);
|
|
+ soulSandBlockReverseBubbleColumnFlow = getBoolean("settings.blocks.soul-sand.reverse-bubble-column-flow", soulSandBlockReverseBubbleColumnFlow);
|
|
+ }
|
|
+
|
|
+ public static boolean allowInapplicableEnchants = false;
|
|
+ public static boolean allowIncompatibleEnchants = false;
|
|
+ public static boolean allowHigherEnchantsLevels = false;
|
|
+ public static boolean allowUnsafeEnchantCommand = false;
|
|
+ public static boolean replaceIncompatibleEnchants = false;
|
|
+ public static boolean clampEnchantLevels = true;
|
|
+ private static void enchantmentSettings() {
|
|
+ if (version < 30) {
|
|
+ boolean oldValue = getBoolean("settings.enchantment.allow-unsafe-enchants", false);
|
|
+ set("settings.enchantment.anvil.allow-unsafe-enchants", oldValue);
|
|
+ set("settings.enchantment.anvil.allow-inapplicable-enchants", true);
|
|
+ set("settings.enchantment.anvil.allow-incompatible-enchants", true);
|
|
+ set("settings.enchantment.anvil.allow-higher-enchants-levels", true);
|
|
+ set("settings.enchantment.allow-unsafe-enchants", null);
|
|
+ }
|
|
+ if (version < 37) {
|
|
+ boolean allowUnsafeEnchants = getBoolean("settings.enchantment.anvil.allow-unsafe-enchants", false);
|
|
+ if (!allowUnsafeEnchants) {
|
|
+ set("settings.enchantment.anvil.allow-inapplicable-enchants", false);
|
|
+ set("settings.enchantment.anvil.allow-incompatible-enchants", false);
|
|
+ set("settings.enchantment.anvil.allow-higher-enchants-levels", false);
|
|
+ }
|
|
+ set("settings.enchantment.anvil.allow-unsafe-enchants", null);
|
|
+ }
|
|
+ allowInapplicableEnchants = getBoolean("settings.enchantment.anvil.allow-inapplicable-enchants", allowInapplicableEnchants);
|
|
+ allowIncompatibleEnchants = getBoolean("settings.enchantment.anvil.allow-incompatible-enchants", allowIncompatibleEnchants);
|
|
+ allowHigherEnchantsLevels = getBoolean("settings.enchantment.anvil.allow-higher-enchants-levels", allowHigherEnchantsLevels);
|
|
+ allowUnsafeEnchantCommand = getBoolean("settings.enchantment.allow-unsafe-enchant-command", allowUnsafeEnchantCommand);
|
|
+ replaceIncompatibleEnchants = getBoolean("settings.enchantment.anvil.replace-incompatible-enchants", replaceIncompatibleEnchants);
|
|
+ clampEnchantLevels = getBoolean("settings.enchantment.clamp-levels", clampEnchantLevels);
|
|
+ }
|
|
+
|
|
+ public static boolean endermanShortHeight = false;
|
|
+ private static void entitySettings() {
|
|
+ endermanShortHeight = getBoolean("settings.entity.enderman.short-height", endermanShortHeight);
|
|
+ if (endermanShortHeight) EntityType.ENDERMAN.setDimensions(EntityDimensions.scalable(0.6F, 1.9F));
|
|
+ }
|
|
+
|
|
+ public static boolean allowWaterPlacementInTheEnd = true;
|
|
+ private static void allowWaterPlacementInEnd() {
|
|
+ allowWaterPlacementInTheEnd = getBoolean("settings.allow-water-placement-in-the-end", allowWaterPlacementInTheEnd);
|
|
+ }
|
|
+
|
|
+ public static boolean beeCountPayload = false;
|
|
+ private static void beeCountPayload() {
|
|
+ beeCountPayload = getBoolean("settings.bee-count-payload", beeCountPayload);
|
|
+ }
|
|
+
|
|
+ public static boolean loggerSuppressInitLegacyMaterialError = false;
|
|
+ public static boolean loggerSuppressIgnoredAdvancementWarnings = false;
|
|
+ public static boolean loggerSuppressUnrecognizedRecipeErrors = false;
|
|
+ public static boolean loggerSuppressSetBlockFarChunk = false;
|
|
+ public static boolean loggerSuppressLibraryLoader = false;
|
|
+ private static void loggerSettings() {
|
|
+ loggerSuppressInitLegacyMaterialError = getBoolean("settings.logger.suppress-init-legacy-material-errors", loggerSuppressInitLegacyMaterialError);
|
|
+ loggerSuppressIgnoredAdvancementWarnings = getBoolean("settings.logger.suppress-ignored-advancement-warnings", loggerSuppressIgnoredAdvancementWarnings);
|
|
+ loggerSuppressUnrecognizedRecipeErrors = getBoolean("settings.logger.suppress-unrecognized-recipe-errors", loggerSuppressUnrecognizedRecipeErrors);
|
|
+ loggerSuppressSetBlockFarChunk = getBoolean("settings.logger.suppress-setblock-in-far-chunk-errors", loggerSuppressSetBlockFarChunk);
|
|
+ loggerSuppressLibraryLoader = getBoolean("settings.logger.suppress-library-loader", loggerSuppressLibraryLoader);
|
|
+ org.bukkit.plugin.java.JavaPluginLoader.SuppressLibraryLoaderLogger = loggerSuppressLibraryLoader;
|
|
+ }
|
|
+
|
|
+ public static boolean tpsCatchup = true;
|
|
+ private static void tpsCatchup() {
|
|
+ tpsCatchup = getBoolean("settings.tps-catchup", tpsCatchup);
|
|
+ }
|
|
+
|
|
+ public static boolean useUPnP = false;
|
|
+ public static boolean maxJoinsPerSecond = false;
|
|
+ public static boolean kickForOutOfOrderChat = true;
|
|
+ private static void networkSettings() {
|
|
+ useUPnP = getBoolean("settings.network.upnp-port-forwarding", useUPnP);
|
|
+ maxJoinsPerSecond = getBoolean("settings.network.max-joins-per-second", maxJoinsPerSecond);
|
|
+ kickForOutOfOrderChat = getBoolean("settings.network.kick-for-out-of-order-chat", kickForOutOfOrderChat);
|
|
+ }
|
|
+
|
|
+ public static java.util.regex.Pattern usernameValidCharactersPattern;
|
|
+ private static void usernameValidationSettings() {
|
|
+ String defaultPattern = "^[a-zA-Z0-9_.]*$";
|
|
+ String setPattern = getString("settings.username-valid-characters", defaultPattern);
|
|
+ usernameValidCharactersPattern = java.util.regex.Pattern.compile(setPattern == null || setPattern.isBlank() ? defaultPattern : setPattern);
|
|
+ }
|
|
+
|
|
+ public static boolean fixProjectileLootingTransfer = false;
|
|
+ private static void fixProjectileLootingTransfer() {
|
|
+ fixProjectileLootingTransfer = getBoolean("settings.fix-projectile-looting-transfer", fixProjectileLootingTransfer);
|
|
+ }
|
|
+
|
|
+ public static boolean clampAttributes = true;
|
|
+ private static void clampAttributes() {
|
|
+ clampAttributes = getBoolean("settings.clamp-attributes", clampAttributes);
|
|
+ }
|
|
+
|
|
+ public static boolean limitArmor = true;
|
|
+ private static void limitArmor() {
|
|
+ limitArmor = getBoolean("settings.limit-armor", limitArmor);
|
|
+ }
|
|
+
|
|
+ private static void blastResistanceSettings() {
|
|
+ getMap("settings.blast-resistance-overrides", Collections.emptyMap()).forEach((blockId, value) -> {
|
|
+ Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId));
|
|
+ if (block == Blocks.AIR) {
|
|
+ log(Level.SEVERE, "Invalid block for `settings.blast-resistance-overrides`: " + blockId);
|
|
+ return;
|
|
+ }
|
|
+ if (!(value instanceof Number blastResistance)) {
|
|
+ log(Level.SEVERE, "Invalid blast resistance for `settings.blast-resistance-overrides." + blockId + "`: " + value);
|
|
+ return;
|
|
+ }
|
|
+ block.explosionResistance = blastResistance.floatValue();
|
|
+ });
|
|
+ }
|
|
+ private static void blockFallMultiplierSettings() {
|
|
+ getMap("settings.block-fall-multipliers", Map.ofEntries(
|
|
+ Map.entry("minecraft:hay_block", Map.of("damage", 0.2F)),
|
|
+ Map.entry("minecraft:white_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:light_gray_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:gray_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:black_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:brown_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:pink_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:red_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:orange_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:yellow_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:green_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:lime_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:cyan_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:light_blue_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:blue_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:purple_bed", Map.of("distance", 0.5F)),
|
|
+ Map.entry("minecraft:magenta_bed", Map.of("distance", 0.5F))
|
|
+ )).forEach((blockId, value) -> {
|
|
+ Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId));
|
|
+ if (block == Blocks.AIR) {
|
|
+ log(Level.SEVERE, "Invalid block for `settings.block-fall-multipliers`: " + blockId);
|
|
+ return;
|
|
+ }
|
|
+ if (!(value instanceof Map<?, ?> map)) {
|
|
+ log(Level.SEVERE, "Invalid fall multiplier for `settings.block-fall-multipliers." + blockId + "`: " + value
|
|
+ + ", expected a map with keys `damage` and `distance` to floats.");
|
|
+ return;
|
|
+ }
|
|
+ Object rawFallDamageMultiplier = map.get("damage");
|
|
+ if (rawFallDamageMultiplier == null) rawFallDamageMultiplier = 1F;
|
|
+ if (!(rawFallDamageMultiplier instanceof Number fallDamageMultiplier)) {
|
|
+ log(Level.SEVERE, "Invalid multiplier for `settings.block-fall-multipliers." + blockId + ".damage`: " + map.get("damage"));
|
|
+ return;
|
|
+ }
|
|
+ Object rawFallDistanceMultiplier = map.get("distance");
|
|
+ if (rawFallDistanceMultiplier == null) rawFallDistanceMultiplier = 1F;
|
|
+ if (!(rawFallDistanceMultiplier instanceof Number fallDistanceMultiplier)) {
|
|
+ log(Level.SEVERE, "Invalid multiplier for `settings.block-fall-multipliers." + blockId + ".distance`: " + map.get("distance"));
|
|
+ return;
|
|
+ }
|
|
+ block.fallDamageMultiplier = fallDamageMultiplier.floatValue();
|
|
+ block.fallDistanceMultiplier = fallDistanceMultiplier.floatValue();
|
|
+ });
|
|
+ }
|
|
+
|
|
+ public static boolean playerDeathsAlwaysShowItem = false;
|
|
+ private static void playerDeathsAlwaysShowItem() {
|
|
+ playerDeathsAlwaysShowItem = getBoolean("settings.player-deaths-always-show-item", playerDeathsAlwaysShowItem);
|
|
+ }
|
|
+
|
|
+ public static boolean registerMinecraftDebugCommands = false;
|
|
+ private static void registerMinecraftDebugCommands() {
|
|
+ registerMinecraftDebugCommands = getBoolean("settings.register-minecraft-debug-commands", registerMinecraftDebugCommands);
|
|
+ }
|
|
+
|
|
+ public static List<String> startupCommands = new ArrayList<>();
|
|
+ private static void startupCommands() {
|
|
+ startupCommands.clear();
|
|
+ getList("settings.startup-commands", new ArrayList<String>()).forEach(line -> {
|
|
+ String command = line.toString();
|
|
+ if (command.startsWith("/")) {
|
|
+ command = command.substring(1);
|
|
+ }
|
|
+ startupCommands.add(command);
|
|
+ });
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..742a46ef95a5e46e9c338cedcecaf008a7108c58
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
|
|
@@ -0,0 +1,3419 @@
|
|
+package org.purpurmc.purpur;
|
|
+
|
|
+import net.minecraft.core.registries.BuiltInRegistries;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.util.Mth;
|
|
+import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.world.entity.EntityType;
|
|
+import net.minecraft.world.entity.monster.Shulker;
|
|
+import net.minecraft.world.item.DyeColor;
|
|
+import net.minecraft.world.item.Item;
|
|
+import net.minecraft.world.item.Items;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import net.minecraft.world.level.block.Blocks;
|
|
+import net.minecraft.world.level.block.state.properties.Tilt;
|
|
+import org.purpurmc.purpur.tool.Flattenable;
|
|
+import org.purpurmc.purpur.tool.Strippable;
|
|
+import org.purpurmc.purpur.tool.Tillable;
|
|
+import org.purpurmc.purpur.tool.Waxable;
|
|
+import org.purpurmc.purpur.tool.Weatherable;
|
|
+import org.apache.commons.lang.BooleanUtils;
|
|
+import org.bukkit.ChatColor;
|
|
+import org.bukkit.World;
|
|
+import org.bukkit.configuration.ConfigurationSection;
|
|
+import java.util.ArrayList;
|
|
+import java.util.HashMap;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.function.Predicate;
|
|
+import java.util.logging.Level;
|
|
+import static org.purpurmc.purpur.PurpurConfig.log;
|
|
+
|
|
+@SuppressWarnings("unused")
|
|
+public class PurpurWorldConfig {
|
|
+
|
|
+ private final String worldName;
|
|
+ private final World.Environment environment;
|
|
+
|
|
+ public PurpurWorldConfig(String worldName, World.Environment environment) {
|
|
+ this.worldName = worldName;
|
|
+ this.environment = environment;
|
|
+ init();
|
|
+ }
|
|
+
|
|
+ public void init() {
|
|
+ log("-------- World Settings For [" + worldName + "] --------");
|
|
+ PurpurConfig.readConfig(PurpurWorldConfig.class, this);
|
|
+ }
|
|
+
|
|
+ private void set(String path, Object val) {
|
|
+ PurpurConfig.config.addDefault("world-settings.default." + path, val);
|
|
+ PurpurConfig.config.set("world-settings.default." + path, val);
|
|
+ if (PurpurConfig.config.get("world-settings." + worldName + "." + path) != null) {
|
|
+ PurpurConfig.config.addDefault("world-settings." + worldName + "." + path, val);
|
|
+ PurpurConfig.config.set("world-settings." + worldName + "." + path, val);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private ConfigurationSection getConfigurationSection(String path) {
|
|
+ ConfigurationSection section = PurpurConfig.config.getConfigurationSection("world-settings." + worldName + "." + path);
|
|
+ return section != null ? section : PurpurConfig.config.getConfigurationSection("world-settings.default." + path);
|
|
+ }
|
|
+
|
|
+ private String getString(String path, String def) {
|
|
+ PurpurConfig.config.addDefault("world-settings.default." + path, def);
|
|
+ return PurpurConfig.config.getString("world-settings." + worldName + "." + path, PurpurConfig.config.getString("world-settings.default." + path));
|
|
+ }
|
|
+
|
|
+ private boolean getBoolean(String path, boolean def) {
|
|
+ PurpurConfig.config.addDefault("world-settings.default." + path, def);
|
|
+ return PurpurConfig.config.getBoolean("world-settings." + worldName + "." + path, PurpurConfig.config.getBoolean("world-settings.default." + path));
|
|
+ }
|
|
+
|
|
+ private boolean getBoolean(String path, Predicate<Boolean> predicate) {
|
|
+ String val = getString(path, "default").toLowerCase();
|
|
+ Boolean bool = BooleanUtils.toBooleanObject(val, "true", "false", "default");
|
|
+ return predicate.test(bool);
|
|
+ }
|
|
+
|
|
+ private double getDouble(String path, double def) {
|
|
+ PurpurConfig.config.addDefault("world-settings.default." + path, def);
|
|
+ return PurpurConfig.config.getDouble("world-settings." + worldName + "." + path, PurpurConfig.config.getDouble("world-settings.default." + path));
|
|
+ }
|
|
+
|
|
+ private int getInt(String path, int def) {
|
|
+ PurpurConfig.config.addDefault("world-settings.default." + path, def);
|
|
+ return PurpurConfig.config.getInt("world-settings." + worldName + "." + path, PurpurConfig.config.getInt("world-settings.default." + path));
|
|
+ }
|
|
+
|
|
+ private <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;
|
|
+ }
|
|
+
|
|
+ public float armorstandStepHeight = 0.0F;
|
|
+ public boolean armorstandSetNameVisible = false;
|
|
+ public boolean armorstandFixNametags = false;
|
|
+ public boolean armorstandMovement = true;
|
|
+ public boolean armorstandWaterMovement = true;
|
|
+ public boolean armorstandWaterFence = true;
|
|
+ public boolean armorstandPlaceWithArms = false;
|
|
+ private void armorstandSettings() {
|
|
+ armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight);
|
|
+ armorstandSetNameVisible = getBoolean("gameplay-mechanics.armorstand.set-name-visible-when-placing-with-custom-name", armorstandSetNameVisible);
|
|
+ armorstandFixNametags = getBoolean("gameplay-mechanics.armorstand.fix-nametags", armorstandFixNametags);
|
|
+ armorstandMovement = getBoolean("gameplay-mechanics.armorstand.can-movement-tick", armorstandMovement);
|
|
+ armorstandWaterMovement = getBoolean("gameplay-mechanics.armorstand.can-move-in-water", armorstandWaterMovement);
|
|
+ armorstandWaterFence = getBoolean("gameplay-mechanics.armorstand.can-move-in-water-over-fence", armorstandWaterFence);
|
|
+ armorstandPlaceWithArms = getBoolean("gameplay-mechanics.armorstand.place-with-arms-visible", armorstandPlaceWithArms);
|
|
+ }
|
|
+
|
|
+ public boolean arrowMovementResetsDespawnCounter = true;
|
|
+ private void arrowSettings() {
|
|
+ arrowMovementResetsDespawnCounter = getBoolean("gameplay-mechanics.arrow.movement-resets-despawn-counter", arrowMovementResetsDespawnCounter);
|
|
+ }
|
|
+
|
|
+ public boolean useBetterMending = false;
|
|
+ public boolean alwaysTameInCreative = false;
|
|
+ public boolean boatEjectPlayersOnLand = false;
|
|
+ public boolean boatsDoFallDamage = false;
|
|
+ public boolean disableDropsOnCrammingDeath = false;
|
|
+ public double tridentLoyaltyVoidReturnHeight = 0.0D;
|
|
+ public boolean entitiesCanUsePortals = true;
|
|
+ public int raidCooldownSeconds = 0;
|
|
+ public int animalBreedingCooldownSeconds = 0;
|
|
+ public boolean persistentDroppableEntityDisplayNames = true;
|
|
+ public boolean entitiesPickUpLootBypassMobGriefing = false;
|
|
+ public boolean fireballsBypassMobGriefing = false;
|
|
+ public boolean projectilesBypassMobGriefing = false;
|
|
+ public boolean noteBlockIgnoreAbove = false;
|
|
+ public boolean imposeTeleportRestrictionsOnGateways = false;
|
|
+ public boolean imposeTeleportRestrictionsOnNetherPortals = false;
|
|
+ public boolean imposeTeleportRestrictionsOnEndPortals = false;
|
|
+ public boolean tickFluids = true;
|
|
+ public double mobsBlindnessMultiplier = 1;
|
|
+ public boolean mobsIgnoreRails = false;
|
|
+ public boolean rainStopsAfterSleep = true;
|
|
+ public boolean thunderStopsAfterSleep = true;
|
|
+ public boolean persistentTileEntityLore = false;
|
|
+ public boolean persistentTileEntityDisplayName = true;
|
|
+ public int mobLastHurtByPlayerTime = 100;
|
|
+ public boolean milkClearsBeneficialEffects = true;
|
|
+ public boolean disableOxidationProximityPenalty = false;
|
|
+ private void miscGameplayMechanicsSettings() {
|
|
+ useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending);
|
|
+ alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative);
|
|
+ boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand);
|
|
+ boatsDoFallDamage = getBoolean("gameplay-mechanics.boat.do-fall-damage", boatsDoFallDamage);
|
|
+ disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath);
|
|
+ tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight);
|
|
+ entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals);
|
|
+ raidCooldownSeconds = getInt("gameplay-mechanics.raid-cooldown-seconds", raidCooldownSeconds);
|
|
+ animalBreedingCooldownSeconds = getInt("gameplay-mechanics.animal-breeding-cooldown-seconds", animalBreedingCooldownSeconds);
|
|
+ persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames);
|
|
+ entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing);
|
|
+ fireballsBypassMobGriefing = getBoolean("gameplay-mechanics.fireballs-bypass-mob-griefing", fireballsBypassMobGriefing);
|
|
+ projectilesBypassMobGriefing = getBoolean("gameplay-mechanics.projectiles-bypass-mob-griefing", projectilesBypassMobGriefing);
|
|
+ noteBlockIgnoreAbove = getBoolean("gameplay-mechanics.note-block-ignore-above", noteBlockIgnoreAbove);
|
|
+ imposeTeleportRestrictionsOnGateways = getBoolean("gameplay-mechanics.impose-teleport-restrictions-on-gateways", imposeTeleportRestrictionsOnGateways);
|
|
+ imposeTeleportRestrictionsOnNetherPortals = getBoolean("gameplay-mechanics.impose-teleport-restrictions-on-nether-portals", imposeTeleportRestrictionsOnNetherPortals);
|
|
+ imposeTeleportRestrictionsOnEndPortals = getBoolean("gameplay-mechanics.impose-teleport-restrictions-on-end-portals", imposeTeleportRestrictionsOnEndPortals);
|
|
+ tickFluids = getBoolean("gameplay-mechanics.tick-fluids", tickFluids);
|
|
+ mobsBlindnessMultiplier = getDouble("gameplay-mechanics.entity-blindness-multiplier", mobsBlindnessMultiplier);
|
|
+ mobsIgnoreRails = getBoolean("gameplay-mechanics.mobs-ignore-rails", mobsIgnoreRails);
|
|
+ rainStopsAfterSleep = getBoolean("gameplay-mechanics.rain-stops-after-sleep", rainStopsAfterSleep);
|
|
+ thunderStopsAfterSleep = getBoolean("gameplay-mechanics.thunder-stops-after-sleep", thunderStopsAfterSleep);
|
|
+ if (PurpurConfig.version < 35) {
|
|
+ boolean oldVal = getBoolean("gameplay-mechanics.persistent-tileentity-display-names-and-lore", persistentTileEntityLore);
|
|
+ set("gameplay-mechanics.persistent-tileentity-display-names-and-lore", null);
|
|
+ set("gameplay-mechanics.persistent-tileentity-lore", oldVal);
|
|
+ set("gameplay-mechanics.persistent-tileentity-display-name", !oldVal);
|
|
+ }
|
|
+ persistentTileEntityLore = getBoolean("gameplay-mechanics.persistent-tileentity-lore", persistentTileEntityLore);
|
|
+ persistentTileEntityDisplayName = getBoolean("gameplay-mechanics.persistent-tileentity-display-name", persistentTileEntityDisplayName);
|
|
+ mobLastHurtByPlayerTime = getInt("gameplay-mechanics.mob-last-hurt-by-player-time", mobLastHurtByPlayerTime);
|
|
+ milkClearsBeneficialEffects = getBoolean("gameplay-mechanics.milk-clears-beneficial-effects", milkClearsBeneficialEffects);
|
|
+ disableOxidationProximityPenalty = getBoolean("gameplay-mechanics.disable-oxidation-proximity-penalty", disableOxidationProximityPenalty);
|
|
+ }
|
|
+
|
|
+ public int daytimeTicks = 12000;
|
|
+ public int nighttimeTicks = 12000;
|
|
+ private void daytimeCycleSettings() {
|
|
+ daytimeTicks = getInt("gameplay-mechanics.daylight-cycle-ticks.daytime", daytimeTicks);
|
|
+ nighttimeTicks = getInt("gameplay-mechanics.daylight-cycle-ticks.nighttime", nighttimeTicks);
|
|
+ }
|
|
+
|
|
+ public int drowningAirTicks = 300;
|
|
+ public int drowningDamageInterval = 20;
|
|
+ public double damageFromDrowning = 2.0F;
|
|
+ private void drowningSettings() {
|
|
+ drowningAirTicks = getInt("gameplay-mechanics.drowning.air-ticks", drowningAirTicks);
|
|
+ drowningDamageInterval = getInt("gameplay-mechanics.drowning.ticks-per-damage", drowningDamageInterval);
|
|
+ damageFromDrowning = getDouble("gameplay-mechanics.drowning.damage-from-drowning", damageFromDrowning);
|
|
+ }
|
|
+
|
|
+ public int elytraDamagePerSecond = 1;
|
|
+ public double elytraDamageMultiplyBySpeed = 0;
|
|
+ public int elytraDamagePerFireworkBoost = 0;
|
|
+ public int elytraDamagePerTridentBoost = 0;
|
|
+ public boolean elytraKineticDamage = true;
|
|
+ private void elytraSettings() {
|
|
+ elytraDamagePerSecond = getInt("gameplay-mechanics.elytra.damage-per-second", elytraDamagePerSecond);
|
|
+ elytraDamageMultiplyBySpeed = getDouble("gameplay-mechanics.elytra.damage-multiplied-by-speed", elytraDamageMultiplyBySpeed);
|
|
+ elytraDamagePerFireworkBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.firework", elytraDamagePerFireworkBoost);
|
|
+ elytraDamagePerTridentBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.trident", elytraDamagePerTridentBoost);
|
|
+ elytraKineticDamage = getBoolean("gameplay-mechanics.elytra.kinetic-damage", elytraKineticDamage);
|
|
+ }
|
|
+
|
|
+ public int entityLifeSpan = 0;
|
|
+ public float entityLeftHandedChance = 0.05f;
|
|
+ public boolean entitySharedRandom = true;
|
|
+ private void entitySettings() {
|
|
+ entityLifeSpan = getInt("gameplay-mechanics.entity-lifespan", entityLifeSpan);
|
|
+ entityLeftHandedChance = (float) getDouble("gameplay-mechanics.entity-left-handed-chance", entityLeftHandedChance);
|
|
+ entitySharedRandom = getBoolean("settings.entity.shared-random", entitySharedRandom);
|
|
+ }
|
|
+
|
|
+ public boolean infinityWorksWithoutArrows = false;
|
|
+ private void infinityArrowsSettings() {
|
|
+ infinityWorksWithoutArrows = getBoolean("gameplay-mechanics.infinity-bow.works-without-arrows", infinityWorksWithoutArrows);
|
|
+ }
|
|
+
|
|
+ public boolean explosionClampRadius = true;
|
|
+ private void explosionSettings() {
|
|
+ explosionClampRadius = getBoolean("gameplay-mechanics.clamp-explosion-radius", explosionClampRadius);
|
|
+ }
|
|
+
|
|
+ public List<Item> itemImmuneToCactus = new ArrayList<>();
|
|
+ public List<Item> itemImmuneToExplosion = new ArrayList<>();
|
|
+ public List<Item> itemImmuneToFire = new ArrayList<>();
|
|
+ public List<Item> itemImmuneToLightning = new ArrayList<>();
|
|
+ public boolean dontRunWithScissors = false;
|
|
+ public boolean ignoreScissorsInWater = false;
|
|
+ public boolean ignoreScissorsInLava = false;
|
|
+ public double scissorsRunningDamage = 1D;
|
|
+ public float enderPearlDamage = 5.0F;
|
|
+ public int enderPearlCooldown = 20;
|
|
+ public int enderPearlCooldownCreative = 20;
|
|
+ public float enderPearlEndermiteChance = 0.05F;
|
|
+ public int glowBerriesEatGlowDuration = 0;
|
|
+ public boolean shulkerBoxItemDropContentsWhenDestroyed = true;
|
|
+ public boolean compassItemShowsBossBar = false;
|
|
+ public boolean snowballExtinguishesFire = false;
|
|
+ public boolean snowballExtinguishesCandles = false;
|
|
+ public boolean snowballExtinguishesCampfires = false;
|
|
+ private void itemSettings() {
|
|
+ itemImmuneToCactus.clear();
|
|
+ getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> {
|
|
+ if (key.toString().equals("*")) {
|
|
+ BuiltInRegistries.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToCactus.add(item));
|
|
+ return;
|
|
+ }
|
|
+ Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(key.toString()));
|
|
+ if (item != Items.AIR) itemImmuneToCactus.add(item);
|
|
+ });
|
|
+ itemImmuneToExplosion.clear();
|
|
+ getList("gameplay-mechanics.item.immune.explosion", new ArrayList<>()).forEach(key -> {
|
|
+ if (key.toString().equals("*")) {
|
|
+ BuiltInRegistries.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToExplosion.add(item));
|
|
+ return;
|
|
+ }
|
|
+ Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(key.toString()));
|
|
+ if (item != Items.AIR) itemImmuneToExplosion.add(item);
|
|
+ });
|
|
+ itemImmuneToFire.clear();
|
|
+ getList("gameplay-mechanics.item.immune.fire", new ArrayList<>()).forEach(key -> {
|
|
+ if (key.toString().equals("*")) {
|
|
+ BuiltInRegistries.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToFire.add(item));
|
|
+ return;
|
|
+ }
|
|
+ Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(key.toString()));
|
|
+ if (item != Items.AIR) itemImmuneToFire.add(item);
|
|
+ });
|
|
+ itemImmuneToLightning.clear();
|
|
+ getList("gameplay-mechanics.item.immune.lightning", new ArrayList<>()).forEach(key -> {
|
|
+ if (key.toString().equals("*")) {
|
|
+ BuiltInRegistries.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToLightning.add(item));
|
|
+ return;
|
|
+ }
|
|
+ Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(key.toString()));
|
|
+ if (item != Items.AIR) itemImmuneToLightning.add(item);
|
|
+ });
|
|
+ dontRunWithScissors = getBoolean("gameplay-mechanics.item.shears.damage-if-sprinting", dontRunWithScissors);
|
|
+ ignoreScissorsInWater = getBoolean("gameplay-mechanics.item.shears.ignore-in-water", ignoreScissorsInWater);
|
|
+ ignoreScissorsInLava = getBoolean("gameplay-mechanics.item.shears.ignore-in-lava", ignoreScissorsInLava);
|
|
+ scissorsRunningDamage = getDouble("gameplay-mechanics.item.shears.sprinting-damage", scissorsRunningDamage);
|
|
+ enderPearlDamage = (float) getDouble("gameplay-mechanics.item.ender-pearl.damage", enderPearlDamage);
|
|
+ enderPearlCooldown = getInt("gameplay-mechanics.item.ender-pearl.cooldown", enderPearlCooldown);
|
|
+ enderPearlCooldownCreative = getInt("gameplay-mechanics.item.ender-pearl.creative-cooldown", enderPearlCooldownCreative);
|
|
+ enderPearlEndermiteChance = (float) getDouble("gameplay-mechanics.item.ender-pearl.endermite-spawn-chance", enderPearlEndermiteChance);
|
|
+ glowBerriesEatGlowDuration = getInt("gameplay-mechanics.item.glow_berries.eat-glow-duration", glowBerriesEatGlowDuration);
|
|
+ shulkerBoxItemDropContentsWhenDestroyed = getBoolean("gameplay-mechanics.item.shulker_box.drop-contents-when-destroyed", shulkerBoxItemDropContentsWhenDestroyed);
|
|
+ compassItemShowsBossBar = getBoolean("gameplay-mechanics.item.compass.holding-shows-bossbar", compassItemShowsBossBar);
|
|
+ snowballExtinguishesFire = getBoolean("gameplay-mechanics.item.snowball.extinguish.fire", snowballExtinguishesFire);
|
|
+ snowballExtinguishesCandles = getBoolean("gameplay-mechanics.item.snowball.extinguish.candles", snowballExtinguishesCandles);
|
|
+ snowballExtinguishesCampfires = getBoolean("gameplay-mechanics.item.snowball.extinguish.campfires", snowballExtinguishesCampfires);
|
|
+ }
|
|
+
|
|
+ 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<>();
|
|
+ public double poweredRailBoostModifier = 0.06;
|
|
+ private void minecartSettings() {
|
|
+ if (PurpurConfig.version < 12) {
|
|
+ boolean oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.place-anywhere", minecartPlaceAnywhere);
|
|
+ set("gameplay-mechanics.controllable-minecarts.place-anywhere", null);
|
|
+ set("gameplay-mechanics.minecart.place-anywhere", oldBool);
|
|
+ oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.enabled", minecartControllable);
|
|
+ set("gameplay-mechanics.controllable-minecarts.enabled", null);
|
|
+ set("gameplay-mechanics.minecart.controllable.enabled", oldBool);
|
|
+ double oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.step-height", minecartControllableStepHeight);
|
|
+ set("gameplay-mechanics.controllable-minecarts.step-height", null);
|
|
+ set("gameplay-mechanics.minecart.controllable.step-height", oldDouble);
|
|
+ oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.hop-boost", minecartControllableHopBoost);
|
|
+ set("gameplay-mechanics.controllable-minecarts.hop-boost", null);
|
|
+ set("gameplay-mechanics.minecart.controllable.hop-boost", oldDouble);
|
|
+ oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.fall-damage", minecartControllableFallDamage);
|
|
+ set("gameplay-mechanics.controllable-minecarts.fall-damage", null);
|
|
+ set("gameplay-mechanics.minecart.controllable.fall-damage", oldBool);
|
|
+ oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.base-speed", minecartControllableBaseSpeed);
|
|
+ set("gameplay-mechanics.controllable-minecarts.base-speed", null);
|
|
+ set("gameplay-mechanics.minecart.controllable.base-speed", oldDouble);
|
|
+ ConfigurationSection section = getConfigurationSection("gameplay-mechanics.controllable-minecarts.block-speed");
|
|
+ if (section != null) {
|
|
+ for (String key : section.getKeys(false)) {
|
|
+ if ("grass-block".equals(key)) key = "grass_block"; // oopsie
|
|
+ oldDouble = section.getDouble(key, minecartControllableBaseSpeed);
|
|
+ set("gameplay-mechanics.controllable-minecarts.block-speed." + key, null);
|
|
+ set("gameplay-mechanics.minecart.controllable.block-speed." + key, oldDouble);
|
|
+ }
|
|
+ set("gameplay-mechanics.controllable-minecarts.block-speed", null);
|
|
+ }
|
|
+ set("gameplay-mechanics.controllable-minecarts", null);
|
|
+ }
|
|
+
|
|
+ minecartMaxSpeed = getDouble("gameplay-mechanics.minecart.max-speed", minecartMaxSpeed);
|
|
+ minecartPlaceAnywhere = getBoolean("gameplay-mechanics.minecart.place-anywhere", minecartPlaceAnywhere);
|
|
+ minecartControllable = getBoolean("gameplay-mechanics.minecart.controllable.enabled", minecartControllable);
|
|
+ minecartControllableStepHeight = (float) getDouble("gameplay-mechanics.minecart.controllable.step-height", minecartControllableStepHeight);
|
|
+ minecartControllableHopBoost = getDouble("gameplay-mechanics.minecart.controllable.hop-boost", minecartControllableHopBoost);
|
|
+ minecartControllableFallDamage = getBoolean("gameplay-mechanics.minecart.controllable.fall-damage", minecartControllableFallDamage);
|
|
+ minecartControllableBaseSpeed = getDouble("gameplay-mechanics.minecart.controllable.base-speed", minecartControllableBaseSpeed);
|
|
+ ConfigurationSection section = getConfigurationSection("gameplay-mechanics.minecart.controllable.block-speed");
|
|
+ if (section != null) {
|
|
+ for (String key : section.getKeys(false)) {
|
|
+ Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(key));
|
|
+ if (block != Blocks.AIR) {
|
|
+ minecartControllableBlockSpeeds.put(block, section.getDouble(key, minecartControllableBaseSpeed));
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ set("gameplay-mechanics.minecart.controllable.block-speed.grass_block", 0.3D);
|
|
+ set("gameplay-mechanics.minecart.controllable.block-speed.stone", 0.5D);
|
|
+ }
|
|
+ poweredRailBoostModifier = getDouble("gameplay-mechanics.minecart.powered-rail.boost-modifier", poweredRailBoostModifier);
|
|
+ }
|
|
+
|
|
+ public float entityHealthRegenAmount = 1.0F;
|
|
+ public float entityMinimalHealthPoison = 1.0F;
|
|
+ public float entityPoisonDegenerationAmount = 1.0F;
|
|
+ public float entityWitherDegenerationAmount = 1.0F;
|
|
+ public float humanHungerExhaustionAmount = 0.005F;
|
|
+ public float humanSaturationRegenAmount = 1.0F;
|
|
+ private void mobEffectSettings() {
|
|
+ entityHealthRegenAmount = (float) getDouble("gameplay-mechanics.mob-effects.health-regen-amount", entityHealthRegenAmount);
|
|
+ entityMinimalHealthPoison = (float) getDouble("gameplay-mechanics.mob-effects.minimal-health-poison-amount", entityMinimalHealthPoison);
|
|
+ entityPoisonDegenerationAmount = (float) getDouble("gameplay-mechanics.mob-effects.poison-degeneration-amount", entityPoisonDegenerationAmount);
|
|
+ entityWitherDegenerationAmount = (float) getDouble("gameplay-mechanics.mob-effects.wither-degeneration-amount", entityWitherDegenerationAmount);
|
|
+ humanHungerExhaustionAmount = (float) getDouble("gameplay-mechanics.mob-effects.hunger-exhaustion-amount", humanHungerExhaustionAmount);
|
|
+ humanSaturationRegenAmount = (float) getDouble("gameplay-mechanics.mob-effects.saturation-regen-amount", humanSaturationRegenAmount);
|
|
+ }
|
|
+
|
|
+ public boolean catSpawning;
|
|
+ public boolean patrolSpawning;
|
|
+ public boolean phantomSpawning;
|
|
+ public boolean villagerTraderSpawning;
|
|
+ public boolean villageSiegeSpawning;
|
|
+ public boolean mobSpawningIgnoreCreativePlayers = false;
|
|
+ private void mobSpawnerSettings() {
|
|
+ // values of "default" or null will default to true only if the world environment is normal (aka overworld)
|
|
+ Predicate<Boolean> predicate = (bool) -> (bool != null && bool) || (bool == null && environment == World.Environment.NORMAL);
|
|
+ catSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-cats", predicate);
|
|
+ patrolSpawning = getBoolean("gameplay-mechanics.mob-spawning.raid-patrols", predicate);
|
|
+ phantomSpawning = getBoolean("gameplay-mechanics.mob-spawning.phantoms", predicate);
|
|
+ villagerTraderSpawning = getBoolean("gameplay-mechanics.mob-spawning.wandering-traders", predicate);
|
|
+ villageSiegeSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-sieges", predicate);
|
|
+ mobSpawningIgnoreCreativePlayers = getBoolean("gameplay-mechanics.mob-spawning.ignore-creative-players", mobSpawningIgnoreCreativePlayers);
|
|
+ }
|
|
+
|
|
+ public boolean disableObserverClocks = false;
|
|
+ private void observerSettings() {
|
|
+ disableObserverClocks = getBoolean("blocks.observer.disable-clock", disableObserverClocks);
|
|
+ }
|
|
+
|
|
+ public int playerNetheriteFireResistanceDuration = 0;
|
|
+ public int playerNetheriteFireResistanceAmplifier = 0;
|
|
+ public boolean playerNetheriteFireResistanceAmbient = false;
|
|
+ public boolean playerNetheriteFireResistanceShowParticles = false;
|
|
+ public boolean playerNetheriteFireResistanceShowIcon = true;
|
|
+ private void playerNetheriteFireResistance() {
|
|
+ playerNetheriteFireResistanceDuration = getInt("gameplay-mechanics.player.netherite-fire-resistance.duration", playerNetheriteFireResistanceDuration);
|
|
+ playerNetheriteFireResistanceAmplifier = getInt("gameplay-mechanics.player.netherite-fire-resistance.amplifier", playerNetheriteFireResistanceAmplifier);
|
|
+ playerNetheriteFireResistanceAmbient = getBoolean("gameplay-mechanics.player.netherite-fire-resistance.ambient", playerNetheriteFireResistanceAmbient);
|
|
+ playerNetheriteFireResistanceShowParticles = getBoolean("gameplay-mechanics.player.netherite-fire-resistance.show-particles", playerNetheriteFireResistanceShowParticles);
|
|
+ playerNetheriteFireResistanceShowIcon = getBoolean("gameplay-mechanics.player.netherite-fire-resistance.show-icon", playerNetheriteFireResistanceShowIcon);
|
|
+ }
|
|
+
|
|
+ public boolean idleTimeoutKick = true;
|
|
+ public boolean idleTimeoutTickNearbyEntities = true;
|
|
+ public boolean idleTimeoutCountAsSleeping = false;
|
|
+ public boolean idleTimeoutUpdateTabList = false;
|
|
+ public boolean idleTimeoutTargetPlayer = true;
|
|
+ public String playerDeathExpDropEquation = "expLevel * 7";
|
|
+ public int playerDeathExpDropMax = 100;
|
|
+ public boolean teleportIfOutsideBorder = false;
|
|
+ public boolean teleportOnNetherCeilingDamage = false;
|
|
+ public boolean totemOfUndyingWorksInInventory = false;
|
|
+ public boolean playerFixStuckPortal = false;
|
|
+ public boolean creativeOnePunch = false;
|
|
+ public boolean playerSleepNearMonsters = false;
|
|
+ public boolean playersSkipNight = true;
|
|
+ public double playerCriticalDamageMultiplier = 1.5D;
|
|
+ public int playerBurpDelay = 10;
|
|
+ public boolean playerBurpWhenFull = false;
|
|
+ public boolean playerRidableInWater = false;
|
|
+ public boolean playerRemoveBindingWithWeakness = false;
|
|
+ public int shiftRightClickRepairsMendingPoints = 0;
|
|
+ public int playerExpPickupDelay = 2;
|
|
+ public boolean playerVoidTrading = false;
|
|
+ private void playerSettings() {
|
|
+ if (PurpurConfig.version < 19) {
|
|
+ boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer);
|
|
+ set("gameplay-mechanics.player.idle-timeout.mods-target", null);
|
|
+ set("gameplay-mechanics.player.idle-timeout.mobs-target", oldVal);
|
|
+ }
|
|
+ idleTimeoutKick = System.getenv("PURPUR_FORCE_IDLE_KICK") == null ? getBoolean("gameplay-mechanics.player.idle-timeout.kick-if-idle", idleTimeoutKick) : Boolean.parseBoolean(System.getenv("PURPUR_FORCE_IDLE_KICK"));
|
|
+ idleTimeoutTickNearbyEntities = getBoolean("gameplay-mechanics.player.idle-timeout.tick-nearby-entities", idleTimeoutTickNearbyEntities);
|
|
+ idleTimeoutCountAsSleeping = getBoolean("gameplay-mechanics.player.idle-timeout.count-as-sleeping", idleTimeoutCountAsSleeping);
|
|
+ idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList);
|
|
+ idleTimeoutTargetPlayer = getBoolean("gameplay-mechanics.player.idle-timeout.mobs-target", idleTimeoutTargetPlayer);
|
|
+ playerDeathExpDropEquation = getString("gameplay-mechanics.player.exp-dropped-on-death.equation", playerDeathExpDropEquation);
|
|
+ playerDeathExpDropMax = getInt("gameplay-mechanics.player.exp-dropped-on-death.maximum", playerDeathExpDropMax);
|
|
+ teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder);
|
|
+ teleportOnNetherCeilingDamage = getBoolean("gameplay-mechanics.player.teleport-on-nether-ceiling-damage", teleportOnNetherCeilingDamage);
|
|
+ totemOfUndyingWorksInInventory = getBoolean("gameplay-mechanics.player.totem-of-undying-works-in-inventory", totemOfUndyingWorksInInventory);
|
|
+ playerFixStuckPortal = getBoolean("gameplay-mechanics.player.fix-stuck-in-portal", playerFixStuckPortal);
|
|
+ creativeOnePunch = getBoolean("gameplay-mechanics.player.one-punch-in-creative", creativeOnePunch);
|
|
+ playerSleepNearMonsters = getBoolean("gameplay-mechanics.player.sleep-ignore-nearby-mobs", playerSleepNearMonsters);
|
|
+ playersSkipNight = getBoolean("gameplay-mechanics.player.can-skip-night", playersSkipNight);
|
|
+ playerCriticalDamageMultiplier = getDouble("gameplay-mechanics.player.critical-damage-multiplier", playerCriticalDamageMultiplier);
|
|
+ playerBurpDelay = getInt("gameplay-mechanics.player.burp-delay", playerBurpDelay);
|
|
+ playerBurpWhenFull = getBoolean("gameplay-mechanics.player.burp-when-full", playerBurpWhenFull);
|
|
+ playerRidableInWater = getBoolean("gameplay-mechanics.player.ridable-in-water", playerRidableInWater);
|
|
+ playerRemoveBindingWithWeakness = getBoolean("gameplay-mechanics.player.curse-of-binding.remove-with-weakness", playerRemoveBindingWithWeakness);
|
|
+ shiftRightClickRepairsMendingPoints = getInt("gameplay-mechanics.player.shift-right-click-repairs-mending-points", shiftRightClickRepairsMendingPoints);
|
|
+ playerExpPickupDelay = getInt("gameplay-mechanics.player.exp-pickup-delay-ticks", playerExpPickupDelay);
|
|
+ playerVoidTrading = getBoolean("gameplay-mechanics.player.allow-void-trading", playerVoidTrading);
|
|
+ }
|
|
+
|
|
+ public boolean silkTouchEnabled = false;
|
|
+ public String silkTouchSpawnerName = "<reset><white>Monster 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 = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(key.toString()));
|
|
+ if (item != Items.AIR) silkTouchTools.add(item);
|
|
+ });
|
|
+ }
|
|
+
|
|
+ public double bowProjectileOffset = 1.0D;
|
|
+ public double crossbowProjectileOffset = 1.0D;
|
|
+ public double eggProjectileOffset = 1.0D;
|
|
+ public double enderPearlProjectileOffset = 1.0D;
|
|
+ public double throwablePotionProjectileOffset = 1.0D;
|
|
+ public double tridentProjectileOffset = 1.0D;
|
|
+ public double snowballProjectileOffset = 1.0D;
|
|
+ private void projectileOffsetSettings() {
|
|
+ bowProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.bow", bowProjectileOffset);
|
|
+ crossbowProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.crossbow", crossbowProjectileOffset);
|
|
+ eggProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.egg", eggProjectileOffset);
|
|
+ enderPearlProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.ender-pearl", enderPearlProjectileOffset);
|
|
+ throwablePotionProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.throwable-potion", throwablePotionProjectileOffset);
|
|
+ tridentProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.trident", tridentProjectileOffset);
|
|
+ snowballProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.snowball", snowballProjectileOffset);
|
|
+ }
|
|
+
|
|
+ public int snowballDamage = -1;
|
|
+ private void snowballSettings() {
|
|
+ snowballDamage = getInt("gameplay-mechanics.projectile-damage.snowball", snowballDamage);
|
|
+ }
|
|
+
|
|
+ public Map<Block, Strippable> axeStrippables = new HashMap<>();
|
|
+ public Map<Block, Waxable> axeWaxables = new HashMap<>();
|
|
+ public Map<Block, Weatherable> axeWeatherables = new HashMap<>();
|
|
+ public Map<Block, Tillable> hoeTillables = new HashMap<>();
|
|
+ public Map<Block, Flattenable> shovelFlattenables = new HashMap<>();
|
|
+ public boolean hoeReplantsCrops = false;
|
|
+ public boolean hoeReplantsNetherWarts = false;
|
|
+ private void toolSettings() {
|
|
+ axeStrippables.clear();
|
|
+ axeWaxables.clear();
|
|
+ axeWeatherables.clear();
|
|
+ hoeTillables.clear();
|
|
+ shovelFlattenables.clear();
|
|
+ if (PurpurConfig.version < 18) {
|
|
+ ConfigurationSection section = PurpurConfig.config.getConfigurationSection("world-settings." + worldName + ".tools.hoe.tilling");
|
|
+ if (section != null) {
|
|
+ PurpurConfig.config.set("world-settings." + worldName + ".tools.hoe.tillables", section);
|
|
+ PurpurConfig.config.set("world-settings." + worldName + ".tools.hoe.tilling", null);
|
|
+ }
|
|
+ section = PurpurConfig.config.getConfigurationSection("world-settings.default.tools.hoe.tilling");
|
|
+ if (section != null) {
|
|
+ PurpurConfig.config.set("world-settings.default.tools.hoe.tillables", section);
|
|
+ PurpurConfig.config.set("world-settings.default.tools.hoe.tilling", null);
|
|
+ }
|
|
+ }
|
|
+ if (PurpurConfig.version < 29) {
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:mangrove_log", Map.of("into", "minecraft:stripped_mangrove_log", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:mangrove_wood", Map.of("into", "minecraft:stripped_mangrove_wood", "drops", new HashMap<String, Double>()));
|
|
+ }
|
|
+ if (PurpurConfig.version < 32) {
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:cherry_log", Map.of("into", "minecraft:stripped_cherry_log", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:cherry_wood", Map.of("into", "minecraft:stripped_cherry_wood", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:bamboo_block", Map.of("into", "minecraft:stripped_bamboo_block", "drops", new HashMap<String, Double>()));
|
|
+ }
|
|
+ if (PurpurConfig.version < 33) {
|
|
+ getList("gameplay-mechanics.shovel-turns-block-to-grass-path", new ArrayList<String>(){{
|
|
+ add("minecraft:coarse_dirt");
|
|
+ add("minecraft:dirt");
|
|
+ add("minecraft:grass_block");
|
|
+ add("minecraft:mycelium");
|
|
+ add("minecraft:podzol");
|
|
+ add("minecraft:rooted_dirt");
|
|
+ }}).forEach(key -> {
|
|
+ PurpurConfig.config.set("world-settings.default.tools.shovel.flattenables." + key.toString(), Map.of("into", "minecraft:dirt_path", "drops", new HashMap<String, Double>()));
|
|
+ });
|
|
+ set("gameplay-mechanics.shovel-turns-block-to-grass-path", null);
|
|
+ }
|
|
+ if (PurpurConfig.version < 34) {
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_chiseled_copper", Map.of("into", "minecraft:chiseled_copper", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_chiseled_copper", Map.of("into", "minecraft:exposed_chiseled_copper", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_chiseled_copper", Map.of("into", "minecraft:weathered_chiseled_copper", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_chiseled_copper", Map.of("into", "minecraft:oxidized_chiseled_copper", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_copper_door", Map.of("into", "minecraft:copper_door", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_copper_door", Map.of("into", "minecraft:exposed_copper_door", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_copper_door", Map.of("into", "minecraft:weathered_copper_door", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_copper_door", Map.of("into", "minecraft:oxidized_copper_door", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_copper_trapdoor", Map.of("into", "minecraft:copper_trapdoor", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_copper_trapdoor", Map.of("into", "minecraft:exposed_copper_trapdoor", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_copper_trapdoor", Map.of("into", "minecraft:weathered_copper_trapdoor", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_copper_trapdoor", Map.of("into", "minecraft:oxidized_copper_trapdoor", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_copper_grate", Map.of("into", "minecraft:copper_grate", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_copper_grate", Map.of("into", "minecraft:exposed_copper_grate", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_copper_grate", Map.of("into", "minecraft:weathered_copper_grate", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_copper_grate", Map.of("into", "minecraft:oxidized_copper_grate", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_copper_bulb", Map.of("into", "minecraft:copper_bulb", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_copper_bulb", Map.of("into", "minecraft:exposed_copper_bulb", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_copper_bulb", Map.of("into", "minecraft:weathered_copper_bulb", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_copper_bulb", Map.of("into", "minecraft:oxidized_copper_bulb", "drops", new HashMap<String, Double>()));
|
|
+
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_chiseled_copper", Map.of("into", "minecraft:chiseled_copper", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_chiseled_copper", Map.of("into", "minecraft:exposed_chiseled_copper", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_chiseled_copper", Map.of("into", "minecraft:weathered_chiseled_copper", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_cut_copper_stairs", Map.of("into", "minecraft:weathered_cut_copper_stairs", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_copper_door", Map.of("into", "minecraft:copper_door", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_copper_door", Map.of("into", "minecraft:exposed_copper_door", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_copper_door", Map.of("into", "minecraft:weathered_copper_door", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_copper_trapdoor", Map.of("into", "minecraft:copper_trapdoor", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_copper_trapdoor", Map.of("into", "minecraft:exposed_copper_trapdoor", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_copper_trapdoor", Map.of("into", "minecraft:weathered_copper_trapdoor", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_copper_grate", Map.of("into", "minecraft:copper_grate", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_copper_grate", Map.of("into", "minecraft:exposed_copper_grate", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_copper_grate", Map.of("into", "minecraft:weathered_copper_grate", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_copper_bulb", Map.of("into", "minecraft:copper_bulb", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_copper_bulb", Map.of("into", "minecraft:exposed_copper_bulb", "drops", new HashMap<String, Double>()));
|
|
+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_copper_bulb", Map.of("into", "minecraft:weathered_copper_bulb", "drops", new HashMap<String, Double>()));
|
|
+ }
|
|
+ getMap("tools.axe.strippables", Map.ofEntries(
|
|
+ Map.entry("minecraft:oak_wood", Map.of("into", "minecraft:stripped_oak_wood", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:oak_log", Map.of("into", "minecraft:stripped_oak_log", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:dark_oak_wood", Map.of("into", "minecraft:stripped_dark_oak_wood", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:dark_oak_log", Map.of("into", "minecraft:stripped_dark_oak_log", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:acacia_wood", Map.of("into", "minecraft:stripped_acacia_wood", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:acacia_log", Map.of("into", "minecraft:stripped_acacia_log", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:birch_wood", Map.of("into", "minecraft:stripped_birch_wood", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:birch_log", Map.of("into", "minecraft:stripped_birch_log", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:jungle_wood", Map.of("into", "minecraft:stripped_jungle_wood", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:jungle_log", Map.of("into", "minecraft:stripped_jungle_log", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:spruce_wood", Map.of("into", "minecraft:stripped_spruce_wood", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:spruce_log", Map.of("into", "minecraft:stripped_spruce_log", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:mangrove_wood", Map.of("into", "minecraft:stripped_mangrove_wood", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:mangrove_log", Map.of("into", "minecraft:stripped_mangrove_log", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:cherry_log", Map.of("into", "minecraft:stripped_cherry_log", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:cherry_wood", Map.of("into", "minecraft:stripped_cherry_wood", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:bamboo_block", Map.of("into", "minecraft:stripped_bamboo_block", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:warped_stem", Map.of("into", "minecraft:stripped_warped_stem", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:warped_hyphae", Map.of("into", "minecraft:stripped_warped_hyphae", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:crimson_stem", Map.of("into", "minecraft:stripped_crimson_stem", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:crimson_hyphae", Map.of("into", "minecraft:stripped_crimson_hyphae", "drops", new HashMap<String, Double>())))
|
|
+ ).forEach((blockId, obj) -> {
|
|
+ Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId));
|
|
+ if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.strippables`: " + blockId); return; }
|
|
+ if (!(obj instanceof Map<?, ?> map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.strippables." + blockId + "`"); return; }
|
|
+ String intoId = (String) map.get("into");
|
|
+ Block into = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(intoId));
|
|
+ if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.strippables." + blockId + ".into`: " + intoId); return; }
|
|
+ Object dropsObj = map.get("drops");
|
|
+ if (!(dropsObj instanceof Map<?, ?> dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.strippables." + blockId + ".drops`"); return; }
|
|
+ Map<Item, Double> drops = new HashMap<>();
|
|
+ dropsMap.forEach((itemId, chance) -> {
|
|
+ Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(itemId.toString()));
|
|
+ if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.axe.strippables." + blockId + ".drops`: " + itemId); return; }
|
|
+ drops.put(item, (double) chance);
|
|
+ });
|
|
+ axeStrippables.put(block, new Strippable(into, drops));
|
|
+ });
|
|
+ getMap("tools.axe.waxables", Map.ofEntries(
|
|
+ Map.entry("minecraft:waxed_copper_block", Map.of("into", "minecraft:copper_block", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_exposed_copper", Map.of("into", "minecraft:exposed_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_weathered_copper", Map.of("into", "minecraft:weathered_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_oxidized_copper", Map.of("into", "minecraft:oxidized_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_cut_copper", Map.of("into", "minecraft:cut_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_exposed_cut_copper", Map.of("into", "minecraft:exposed_cut_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_weathered_cut_copper", Map.of("into", "minecraft:weathered_cut_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_oxidized_cut_copper", Map.of("into", "minecraft:oxidized_cut_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_cut_copper_slab", Map.of("into", "minecraft:cut_copper_slab", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_exposed_cut_copper_slab", Map.of("into", "minecraft:exposed_cut_copper_slab", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_weathered_cut_copper_slab", Map.of("into", "minecraft:weathered_cut_copper_slab", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_oxidized_cut_copper_slab", Map.of("into", "minecraft:oxidized_cut_copper_slab", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_cut_copper_stairs", Map.of("into", "minecraft:cut_copper_stairs", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_exposed_cut_copper_stairs", Map.of("into", "minecraft:exposed_cut_copper_stairs", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_weathered_cut_copper_stairs", Map.of("into", "minecraft:weathered_cut_copper_stairs", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_oxidized_cut_copper_stairs", Map.of("into", "minecraft:oxidized_cut_copper_stairs", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_chiseled_copper", Map.of("into", "minecraft:chiseled_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_exposed_chiseled_copper", Map.of("into", "minecraft:exposed_chiseled_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_weathered_chiseled_copper", Map.of("into", "minecraft:weathered_chiseled_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_oxidized_chiseled_copper", Map.of("into", "minecraft:oxidized_chiseled_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_copper_door", Map.of("into", "minecraft:copper_door", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_exposed_copper_door", Map.of("into", "minecraft:exposed_copper_door", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_weathered_copper_door", Map.of("into", "minecraft:weathered_copper_door", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_oxidized_copper_door", Map.of("into", "minecraft:oxidized_copper_door", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_copper_trapdoor", Map.of("into", "minecraft:copper_trapdoor", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_exposed_copper_trapdoor", Map.of("into", "minecraft:exposed_copper_trapdoor", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_weathered_copper_trapdoor", Map.of("into", "minecraft:weathered_copper_trapdoor", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_oxidized_copper_trapdoor", Map.of("into", "minecraft:oxidized_copper_trapdoor", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_copper_grate", Map.of("into", "minecraft:copper_grate", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_exposed_copper_grate", Map.of("into", "minecraft:exposed_copper_grate", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_weathered_copper_grate", Map.of("into", "minecraft:weathered_copper_grate", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_oxidized_copper_grate", Map.of("into", "minecraft:oxidized_copper_grate", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_copper_bulb", Map.of("into", "minecraft:copper_bulb", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_exposed_copper_bulb", Map.of("into", "minecraft:exposed_copper_bulb", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_weathered_copper_bulb", Map.of("into", "minecraft:weathered_copper_bulb", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:waxed_oxidized_copper_bulb", Map.of("into", "minecraft:oxidized_copper_bulb", "drops", new HashMap<String, Double>())))
|
|
+ ).forEach((blockId, obj) -> {
|
|
+ Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId));
|
|
+ if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.waxables`: " + blockId); return; }
|
|
+ if (!(obj instanceof Map<?, ?> map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.waxables." + blockId + "`"); return; }
|
|
+ String intoId = (String) map.get("into");
|
|
+ Block into = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(intoId));
|
|
+ if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.waxables." + blockId + ".into`: " + intoId); return; }
|
|
+ Object dropsObj = map.get("drops");
|
|
+ if (!(dropsObj instanceof Map<?, ?> dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.waxables." + blockId + ".drops`"); return; }
|
|
+ Map<Item, Double> drops = new HashMap<>();
|
|
+ dropsMap.forEach((itemId, chance) -> {
|
|
+ Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(itemId.toString()));
|
|
+ if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.axe.waxables." + blockId + ".drops`: " + itemId); return; }
|
|
+ drops.put(item, (double) chance);
|
|
+ });
|
|
+ axeWaxables.put(block, new Waxable(into, drops));
|
|
+ });
|
|
+ getMap("tools.axe.weatherables", Map.ofEntries(
|
|
+ Map.entry("minecraft:exposed_copper", Map.of("into", "minecraft:copper_block", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:weathered_copper", Map.of("into", "minecraft:exposed_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:oxidized_copper", Map.of("into", "minecraft:weathered_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:exposed_cut_copper", Map.of("into", "minecraft:cut_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:weathered_cut_copper", Map.of("into", "minecraft:exposed_cut_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:oxidized_cut_copper", Map.of("into", "minecraft:weathered_cut_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:exposed_chiseled_copper", Map.of("into", "minecraft:chiseled_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:weathered_chiseled_copper", Map.of("into", "minecraft:exposed_chiseled_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:oxidized_chiseled_copper", Map.of("into", "minecraft:weathered_chiseled_copper", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:exposed_cut_copper_slab", Map.of("into", "minecraft:cut_copper_slab", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:weathered_cut_copper_slab", Map.of("into", "minecraft:exposed_cut_copper_slab", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:oxidized_cut_copper_slab", Map.of("into", "minecraft:weathered_cut_copper_slab", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:exposed_cut_copper_stairs", Map.of("into", "minecraft:cut_copper_stairs", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:weathered_cut_copper_stairs", Map.of("into", "minecraft:exposed_cut_copper_stairs", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:oxidized_cut_copper_stairs", Map.of("into", "minecraft:weathered_cut_copper_stairs", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:exposed_copper_door", Map.of("into", "minecraft:copper_door", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:weathered_copper_door", Map.of("into", "minecraft:exposed_copper_door", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:oxidized_copper_door", Map.of("into", "minecraft:weathered_copper_door", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:exposed_copper_trapdoor", Map.of("into", "minecraft:copper_trapdoor", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:weathered_copper_trapdoor", Map.of("into", "minecraft:exposed_copper_trapdoor", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:oxidized_copper_trapdoor", Map.of("into", "minecraft:weathered_copper_trapdoor", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:exposed_copper_grate", Map.of("into", "minecraft:copper_grate", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:weathered_copper_grate", Map.of("into", "minecraft:exposed_copper_grate", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:oxidized_copper_grate", Map.of("into", "minecraft:weathered_copper_grate", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:exposed_copper_bulb", Map.of("into", "minecraft:copper_bulb", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:weathered_copper_bulb", Map.of("into", "minecraft:exposed_copper_bulb", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:oxidized_copper_bulb", Map.of("into", "minecraft:weathered_copper_bulb", "drops", new HashMap<String, Double>())))
|
|
+ ).forEach((blockId, obj) -> {
|
|
+ Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId));
|
|
+ if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.weatherables`: " + blockId); return; }
|
|
+ if (!(obj instanceof Map<?, ?> map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.weatherables." + blockId + "`"); return; }
|
|
+ String intoId = (String) map.get("into");
|
|
+ Block into = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(intoId));
|
|
+ if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.weatherables." + blockId + ".into`: " + intoId); return; }
|
|
+ Object dropsObj = map.get("drops");
|
|
+ if (!(dropsObj instanceof Map<?, ?> dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.weatherables." + blockId + ".drops`"); return; }
|
|
+ Map<Item, Double> drops = new HashMap<>();
|
|
+ dropsMap.forEach((itemId, chance) -> {
|
|
+ Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(itemId.toString()));
|
|
+ if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.axe.weatherables." + blockId + ".drops`: " + itemId); return; }
|
|
+ drops.put(item, (double) chance);
|
|
+ });
|
|
+ axeWeatherables.put(block, new Weatherable(into, drops));
|
|
+ });
|
|
+ getMap("tools.hoe.tillables", Map.ofEntries(
|
|
+ Map.entry("minecraft:grass_block", Map.of("condition", "air_above", "into", "minecraft:farmland", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:dirt_path", Map.of("condition", "air_above", "into", "minecraft:farmland", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:dirt", Map.of("condition", "air_above", "into", "minecraft:farmland", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:coarse_dirt", Map.of("condition", "air_above", "into", "minecraft:dirt", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:rooted_dirt", Map.of("condition", "always", "into", "minecraft:dirt", "drops", Map.of("minecraft:hanging_roots", 1.0D))))
|
|
+ ).forEach((blockId, obj) -> {
|
|
+ Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId));
|
|
+ if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.hoe.tillables`: " + blockId); return; }
|
|
+ if (!(obj instanceof Map<?, ?> map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.hoe.tillables." + blockId + "`"); return; }
|
|
+ String conditionId = (String) map.get("condition");
|
|
+ Tillable.Condition condition = Tillable.Condition.get(conditionId);
|
|
+ if (condition == null) { PurpurConfig.log(Level.SEVERE, "Invalid condition for `tools.hoe.tillables." + blockId + ".condition`: " + conditionId); return; }
|
|
+ String intoId = (String) map.get("into");
|
|
+ Block into = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(intoId));
|
|
+ if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.hoe.tillables." + blockId + ".into`: " + intoId); return; }
|
|
+ Object dropsObj = map.get("drops");
|
|
+ if (!(dropsObj instanceof Map<?, ?> dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.hoe.tillables." + blockId + ".drops`"); return; }
|
|
+ Map<Item, Double> drops = new HashMap<>();
|
|
+ dropsMap.forEach((itemId, chance) -> {
|
|
+ Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(itemId.toString()));
|
|
+ if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.hoe.tillables." + blockId + ".drops`: " + itemId); return; }
|
|
+ drops.put(item, (double) chance);
|
|
+ });
|
|
+ hoeTillables.put(block, new Tillable(condition, into, drops));
|
|
+ });
|
|
+ getMap("tools.shovel.flattenables", Map.ofEntries(
|
|
+ Map.entry("minecraft:grass_block", Map.of("into", "minecraft:dirt_path", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:dirt", Map.of("into", "minecraft:dirt_path", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:podzol", Map.of("into", "minecraft:dirt_path", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:coarse_dirt", Map.of("into", "minecraft:dirt_path", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:mycelium", Map.of("into", "minecraft:dirt_path", "drops", new HashMap<String, Double>())),
|
|
+ Map.entry("minecraft:rooted_dirt", Map.of("into", "minecraft:dirt_path", "drops", new HashMap<String, Double>())))
|
|
+ ).forEach((blockId, obj) -> {
|
|
+ Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId));
|
|
+ if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.shovel.flattenables`: " + blockId); return; }
|
|
+ if (!(obj instanceof Map<?, ?> map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.shovel.flattenables." + blockId + "`"); return; }
|
|
+ String intoId = (String) map.get("into");
|
|
+ Block into = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(intoId));
|
|
+ if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.shovel.flattenables." + blockId + ".into`: " + intoId); return; }
|
|
+ Object dropsObj = map.get("drops");
|
|
+ if (!(dropsObj instanceof Map<?, ?> dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.shovel.flattenables." + blockId + ".drops`"); return; }
|
|
+ Map<Item, Double> drops = new HashMap<>();
|
|
+ dropsMap.forEach((itemId, chance) -> {
|
|
+ Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(itemId.toString()));
|
|
+ if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.shovel.flattenables." + blockId + ".drops`: " + itemId); return; }
|
|
+ drops.put(item, (double) chance);
|
|
+ });
|
|
+ shovelFlattenables.put(block, new Flattenable(into, drops));
|
|
+ });
|
|
+ hoeReplantsCrops = getBoolean("tools.hoe.replant-crops", hoeReplantsCrops);
|
|
+ hoeReplantsNetherWarts = getBoolean("tools.hoe.replant-nether-warts", hoeReplantsNetherWarts);
|
|
+ }
|
|
+
|
|
+ public boolean anvilAllowColors = false;
|
|
+ public boolean anvilColorsUseMiniMessage;
|
|
+ public int anvilRepairIngotsAmount = 0;
|
|
+ public int anvilDamageObsidianAmount = 0;
|
|
+ private void anvilSettings() {
|
|
+ anvilAllowColors = getBoolean("blocks.anvil.allow-colors", anvilAllowColors);
|
|
+ anvilColorsUseMiniMessage = getBoolean("blocks.anvil.use-mini-message", anvilColorsUseMiniMessage);
|
|
+ anvilRepairIngotsAmount = getInt("blocks.anvil.iron-ingots-used-for-repair", anvilRepairIngotsAmount);
|
|
+ anvilDamageObsidianAmount = getInt("blocks.anvil.obsidian-used-for-damage", anvilDamageObsidianAmount);
|
|
+ }
|
|
+
|
|
+ public double azaleaGrowthChance = 0.0D;
|
|
+ private void azaleaSettings() {
|
|
+ azaleaGrowthChance = getDouble("blocks.azalea.growth-chance", azaleaGrowthChance);
|
|
+ }
|
|
+
|
|
+ public int beaconLevelOne = 20;
|
|
+ public int beaconLevelTwo = 30;
|
|
+ public int beaconLevelThree = 40;
|
|
+ public int beaconLevelFour = 50;
|
|
+ public boolean beaconAllowEffectsWithTintedGlass = false;
|
|
+ private void beaconSettings() {
|
|
+ beaconLevelOne = getInt("blocks.beacon.effect-range.level-1", beaconLevelOne);
|
|
+ beaconLevelTwo = getInt("blocks.beacon.effect-range.level-2", beaconLevelTwo);
|
|
+ beaconLevelThree = getInt("blocks.beacon.effect-range.level-3", beaconLevelThree);
|
|
+ beaconLevelFour = getInt("blocks.beacon.effect-range.level-4", beaconLevelFour);
|
|
+ beaconAllowEffectsWithTintedGlass = getBoolean("blocks.beacon.allow-effects-with-tinted-glass", beaconAllowEffectsWithTintedGlass);
|
|
+ }
|
|
+
|
|
+ public boolean bedExplode = true;
|
|
+ public boolean bedExplodeOnVillagerSleep = false;
|
|
+ public double bedExplosionPower = 5.0D;
|
|
+ public boolean bedExplosionFire = true;
|
|
+ public net.minecraft.world.level.Level.ExplosionInteraction bedExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK;
|
|
+ private void bedSettings() {
|
|
+ if (PurpurConfig.version < 31) {
|
|
+ if ("DESTROY".equals(getString("blocks.bed.explosion-effect", bedExplosionEffect.name()))) {
|
|
+ set("blocks.bed.explosion-effect", "BLOCK");
|
|
+ }
|
|
+ }
|
|
+ bedExplode = getBoolean("blocks.bed.explode", bedExplode);
|
|
+ bedExplodeOnVillagerSleep = getBoolean("blocks.bed.explode-on-villager-sleep", bedExplodeOnVillagerSleep);
|
|
+ bedExplosionPower = getDouble("blocks.bed.explosion-power", bedExplosionPower);
|
|
+ bedExplosionFire = getBoolean("blocks.bed.explosion-fire", bedExplosionFire);
|
|
+ try {
|
|
+ bedExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.valueOf(getString("blocks.bed.explosion-effect", bedExplosionEffect.name()));
|
|
+ } catch (IllegalArgumentException e) {
|
|
+ log(Level.SEVERE, "Unknown value for `blocks.bed.explosion-effect`! Using default of `BLOCK`");
|
|
+ bedExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public Map<Tilt, Integer> bigDripleafTiltDelay = new HashMap<>();
|
|
+ private void bigDripleafSettings() {
|
|
+ bigDripleafTiltDelay.clear();
|
|
+ getMap("blocks.big_dripleaf.tilt-delay", Map.ofEntries(
|
|
+ Map.entry("UNSTABLE", 10),
|
|
+ Map.entry("PARTIAL", 10),
|
|
+ Map.entry("FULL", 100))
|
|
+ ).forEach((tilt, delay) -> {
|
|
+ try {
|
|
+ bigDripleafTiltDelay.put(Tilt.valueOf(tilt), (int) delay);
|
|
+ } catch (IllegalArgumentException e) {
|
|
+ PurpurConfig.log(Level.SEVERE, "Invalid big_dripleaf tilt key: " + tilt);
|
|
+ }
|
|
+ });
|
|
+ }
|
|
+
|
|
+ public boolean cactusBreaksFromSolidNeighbors = true;
|
|
+ public boolean cactusAffectedByBonemeal = false;
|
|
+ private void cactusSettings() {
|
|
+ cactusBreaksFromSolidNeighbors = getBoolean("blocks.cactus.breaks-from-solid-neighbors", cactusBreaksFromSolidNeighbors);
|
|
+ cactusAffectedByBonemeal = getBoolean("blocks.cactus.affected-by-bonemeal", cactusAffectedByBonemeal);
|
|
+ }
|
|
+
|
|
+ public boolean sugarCanAffectedByBonemeal = false;
|
|
+ private void sugarCaneSettings() {
|
|
+ sugarCanAffectedByBonemeal = getBoolean("blocks.sugar_cane.affected-by-bonemeal", sugarCanAffectedByBonemeal);
|
|
+ }
|
|
+
|
|
+ public boolean netherWartAffectedByBonemeal = false;
|
|
+ private void netherWartSettings() {
|
|
+ netherWartAffectedByBonemeal = getBoolean("blocks.nether_wart.affected-by-bonemeal", netherWartAffectedByBonemeal);
|
|
+ }
|
|
+
|
|
+ public boolean campFireLitWhenPlaced = true;
|
|
+ private void campFireSettings() {
|
|
+ campFireLitWhenPlaced = getBoolean("blocks.campfire.lit-when-placed", campFireLitWhenPlaced);
|
|
+ }
|
|
+
|
|
+ public boolean chestOpenWithBlockOnTop = false;
|
|
+ private void chestSettings() {
|
|
+ chestOpenWithBlockOnTop = getBoolean("blocks.chest.open-with-solid-block-on-top", chestOpenWithBlockOnTop);
|
|
+ }
|
|
+
|
|
+ public boolean composterBulkProcess = false;
|
|
+ private void composterSettings() {
|
|
+ composterBulkProcess = getBoolean("blocks.composter.sneak-to-bulk-process", composterBulkProcess);
|
|
+ }
|
|
+
|
|
+ public boolean coralDieOutsideWater = true;
|
|
+ private void coralSettings() {
|
|
+ coralDieOutsideWater = getBoolean("blocks.coral.die-outside-water", coralDieOutsideWater);
|
|
+ }
|
|
+
|
|
+ public boolean dispenserApplyCursedArmor = true;
|
|
+ public boolean dispenserPlaceAnvils = false;
|
|
+ private void dispenserSettings() {
|
|
+ dispenserApplyCursedArmor = getBoolean("blocks.dispenser.apply-cursed-to-armor-slots", dispenserApplyCursedArmor);
|
|
+ dispenserPlaceAnvils = getBoolean("blocks.dispenser.place-anvils", dispenserPlaceAnvils);
|
|
+ }
|
|
+
|
|
+ public List<Block> doorRequiresRedstone = new ArrayList<>();
|
|
+ private void doorSettings() {
|
|
+ getList("blocks.door.requires-redstone", new ArrayList<String>()).forEach(key -> {
|
|
+ Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(key.toString()));
|
|
+ if (!block.defaultBlockState().isAir()) {
|
|
+ doorRequiresRedstone.add(block);
|
|
+ }
|
|
+ });
|
|
+ }
|
|
+
|
|
+ public boolean dragonEggTeleport = true;
|
|
+ private void dragonEggSettings() {
|
|
+ dragonEggTeleport = getBoolean("blocks.dragon_egg.teleport", dragonEggTeleport);
|
|
+ }
|
|
+
|
|
+ public boolean baselessEndCrystalExplode = true;
|
|
+ public double baselessEndCrystalExplosionPower = 6.0D;
|
|
+ public boolean baselessEndCrystalExplosionFire = false;
|
|
+ public net.minecraft.world.level.Level.ExplosionInteraction baselessEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK;
|
|
+ public boolean basedEndCrystalExplode = true;
|
|
+ public double basedEndCrystalExplosionPower = 6.0D;
|
|
+ public boolean basedEndCrystalExplosionFire = false;
|
|
+ public net.minecraft.world.level.Level.ExplosionInteraction basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK;
|
|
+ public int endCrystalCramming = 0;
|
|
+ public boolean endCrystalPlaceAnywhere = false;
|
|
+ private void endCrystalSettings() {
|
|
+ if (PurpurConfig.version < 31) {
|
|
+ if ("DESTROY".equals(getString("blocks.end-crystal.baseless.explosion-effect", baselessEndCrystalExplosionEffect.name()))) {
|
|
+ set("blocks.end-crystal.baseless.explosion-effect", "BLOCK");
|
|
+ }
|
|
+ if ("DESTROY".equals(getString("blocks.end-crystal.base.explosion-effect", basedEndCrystalExplosionEffect.name()))) {
|
|
+ set("blocks.end-crystal.base.explosion-effect", "BLOCK");
|
|
+ }
|
|
+ }
|
|
+ baselessEndCrystalExplode = getBoolean("blocks.end-crystal.baseless.explode", baselessEndCrystalExplode);
|
|
+ baselessEndCrystalExplosionPower = getDouble("blocks.end-crystal.baseless.explosion-power", baselessEndCrystalExplosionPower);
|
|
+ baselessEndCrystalExplosionFire = getBoolean("blocks.end-crystal.baseless.explosion-fire", baselessEndCrystalExplosionFire);
|
|
+ try {
|
|
+ baselessEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.valueOf(getString("blocks.end-crystal.baseless.explosion-effect", baselessEndCrystalExplosionEffect.name()));
|
|
+ } catch (IllegalArgumentException e) {
|
|
+ log(Level.SEVERE, "Unknown value for `blocks.end-crystal.baseless.explosion-effect`! Using default of `BLOCK`");
|
|
+ baselessEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK;
|
|
+ }
|
|
+ basedEndCrystalExplode = getBoolean("blocks.end-crystal.base.explode", basedEndCrystalExplode);
|
|
+ basedEndCrystalExplosionPower = getDouble("blocks.end-crystal.base.explosion-power", basedEndCrystalExplosionPower);
|
|
+ basedEndCrystalExplosionFire = getBoolean("blocks.end-crystal.base.explosion-fire", basedEndCrystalExplosionFire);
|
|
+ try {
|
|
+ basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.valueOf(getString("blocks.end-crystal.base.explosion-effect", basedEndCrystalExplosionEffect.name()));
|
|
+ } catch (IllegalArgumentException e) {
|
|
+ log(Level.SEVERE, "Unknown value for `blocks.end-crystal.base.explosion-effect`! Using default of `BLOCK`");
|
|
+ basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK;
|
|
+ }
|
|
+ endCrystalCramming = getInt("blocks.end-crystal.cramming-amount", endCrystalCramming);
|
|
+ endCrystalPlaceAnywhere = getBoolean("gameplay-mechanics.item.end-crystal.place-anywhere", endCrystalPlaceAnywhere);
|
|
+ }
|
|
+
|
|
+ public boolean farmlandBypassMobGriefing = false;
|
|
+ public boolean farmlandGetsMoistFromBelow = false;
|
|
+ public boolean farmlandAlpha = false;
|
|
+ public boolean farmlandTramplingDisabled = false;
|
|
+ public boolean farmlandTramplingOnlyPlayers = false;
|
|
+ public boolean farmlandTramplingFeatherFalling = false;
|
|
+ public double farmlandTrampleHeight = -1D;
|
|
+ private void farmlandSettings() {
|
|
+ farmlandBypassMobGriefing = getBoolean("blocks.farmland.bypass-mob-griefing", farmlandBypassMobGriefing);
|
|
+ farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow);
|
|
+ farmlandAlpha = getBoolean("blocks.farmland.use-alpha-farmland", farmlandAlpha);
|
|
+ farmlandTramplingDisabled = getBoolean("blocks.farmland.disable-trampling", farmlandTramplingDisabled);
|
|
+ farmlandTramplingOnlyPlayers = getBoolean("blocks.farmland.only-players-trample", farmlandTramplingOnlyPlayers);
|
|
+ farmlandTramplingFeatherFalling = getBoolean("blocks.farmland.feather-fall-distance-affects-trampling", farmlandTramplingFeatherFalling);
|
|
+ farmlandTrampleHeight = getDouble("blocks.farmland.trample-height", farmlandTrampleHeight);
|
|
+ }
|
|
+
|
|
+ public double floweringAzaleaGrowthChance = 0.0D;
|
|
+ private void floweringAzaleaSettings() {
|
|
+ floweringAzaleaGrowthChance = getDouble("blocks.flowering_azalea.growth-chance", floweringAzaleaGrowthChance);
|
|
+ }
|
|
+
|
|
+ public boolean furnaceUseLavaFromUnderneath = false;
|
|
+ private void furnaceSettings() {
|
|
+ if (PurpurConfig.version < 17) {
|
|
+ furnaceUseLavaFromUnderneath = getBoolean("blocks.furnace.infinite-fuel", furnaceUseLavaFromUnderneath);
|
|
+ boolean oldValue = getBoolean("blocks.furnace.infinite-fuel", furnaceUseLavaFromUnderneath);
|
|
+ set("blocks.furnace.infinite-fuel", null);
|
|
+ set("blocks.furnace.use-lava-from-underneath", oldValue);
|
|
+ }
|
|
+ furnaceUseLavaFromUnderneath = getBoolean("blocks.furnace.use-lava-from-underneath", furnaceUseLavaFromUnderneath);
|
|
+ }
|
|
+
|
|
+ public boolean mobsSpawnOnPackedIce = true;
|
|
+ public boolean mobsSpawnOnBlueIce = true;
|
|
+ public boolean snowOnBlueIce = true;
|
|
+ private void iceSettings() {
|
|
+ mobsSpawnOnPackedIce = getBoolean("blocks.packed_ice.allow-mob-spawns", mobsSpawnOnPackedIce);
|
|
+ mobsSpawnOnBlueIce = getBoolean("blocks.blue_ice.allow-mob-spawns", mobsSpawnOnBlueIce);
|
|
+ snowOnBlueIce = getBoolean("blocks.blue_ice.allow-snow-formation", snowOnBlueIce);
|
|
+ }
|
|
+
|
|
+ public int lavaInfiniteRequiredSources = 2;
|
|
+ public int lavaSpeedNether = 10;
|
|
+ public int lavaSpeedNotNether = 30;
|
|
+ private void lavaSettings() {
|
|
+ lavaInfiniteRequiredSources = getInt("blocks.lava.infinite-required-sources", lavaInfiniteRequiredSources);
|
|
+ lavaSpeedNether = getInt("blocks.lava.speed.nether", lavaSpeedNether);
|
|
+ lavaSpeedNotNether = getInt("blocks.lava.speed.not-nether", lavaSpeedNotNether);
|
|
+ }
|
|
+
|
|
+ public int pistonBlockPushLimit = 12;
|
|
+ private void pistonSettings() {
|
|
+ pistonBlockPushLimit = getInt("blocks.piston.block-push-limit", pistonBlockPushLimit);
|
|
+ }
|
|
+
|
|
+ public boolean magmaBlockDamageWhenSneaking = false;
|
|
+ private void magmaBlockSettings() {
|
|
+ magmaBlockDamageWhenSneaking = getBoolean("blocks.magma-block.damage-when-sneaking", magmaBlockDamageWhenSneaking);
|
|
+ }
|
|
+
|
|
+ public boolean powderSnowBypassMobGriefing = false;
|
|
+ private void powderSnowSettings() {
|
|
+ powderSnowBypassMobGriefing = getBoolean("blocks.powder_snow.bypass-mob-griefing", powderSnowBypassMobGriefing);
|
|
+ }
|
|
+
|
|
+ public int railActivationRange = 8;
|
|
+ private void railSettings() {
|
|
+ railActivationRange = getInt("blocks.powered-rail.activation-range", railActivationRange);
|
|
+ }
|
|
+
|
|
+ public boolean respawnAnchorExplode = true;
|
|
+ public double respawnAnchorExplosionPower = 5.0D;
|
|
+ public boolean respawnAnchorExplosionFire = true;
|
|
+ public net.minecraft.world.level.Level.ExplosionInteraction respawnAnchorExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK;
|
|
+ private void respawnAnchorSettings() {
|
|
+ if (PurpurConfig.version < 31) {
|
|
+ if ("DESTROY".equals(getString("blocks.respawn_anchor.explosion-effect", respawnAnchorExplosionEffect.name()))) {
|
|
+ set("blocks.respawn_anchor.explosion-effect", "BLOCK");
|
|
+ }
|
|
+ }
|
|
+ respawnAnchorExplode = getBoolean("blocks.respawn_anchor.explode", respawnAnchorExplode);
|
|
+ respawnAnchorExplosionPower = getDouble("blocks.respawn_anchor.explosion-power", respawnAnchorExplosionPower);
|
|
+ respawnAnchorExplosionFire = getBoolean("blocks.respawn_anchor.explosion-fire", respawnAnchorExplosionFire);
|
|
+ try {
|
|
+ respawnAnchorExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.valueOf(getString("blocks.respawn_anchor.explosion-effect", respawnAnchorExplosionEffect.name()));
|
|
+ } catch (IllegalArgumentException e) {
|
|
+ log(Level.SEVERE, "Unknown value for `blocks.respawn_anchor.explosion-effect`! Using default of `BLOCK`");
|
|
+ respawnAnchorExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public boolean sculkShriekerCanSummonDefault = false;
|
|
+ private void sculkShriekerSettings() {
|
|
+ sculkShriekerCanSummonDefault = getBoolean("blocks.sculk_shrieker.can-summon-default", sculkShriekerCanSummonDefault);
|
|
+ }
|
|
+
|
|
+ public boolean signAllowColors = false;
|
|
+ private void signSettings() {
|
|
+ signAllowColors = getBoolean("blocks.sign.allow-colors", signAllowColors);
|
|
+ }
|
|
+
|
|
+ public boolean slabHalfBreak = false;
|
|
+ private void slabSettings() {
|
|
+ slabHalfBreak = getBoolean("blocks.slab.break-individual-slabs-when-sneaking", slabHalfBreak);
|
|
+ }
|
|
+
|
|
+ public boolean spawnerDeactivateByRedstone = false;
|
|
+ public boolean spawnerFixMC238526 = false;
|
|
+ private void spawnerSettings() {
|
|
+ spawnerDeactivateByRedstone = getBoolean("blocks.spawner.deactivate-by-redstone", spawnerDeactivateByRedstone);
|
|
+ spawnerFixMC238526 = getBoolean("blocks.spawner.fix-mc-238526", spawnerFixMC238526);
|
|
+ }
|
|
+
|
|
+ public int spongeAbsorptionArea = 65;
|
|
+ public int spongeAbsorptionRadius = 6;
|
|
+ public boolean spongeAbsorbsLava = false;
|
|
+ public boolean spongeAbsorbsWaterFromMud = false;
|
|
+ private void spongeSettings() {
|
|
+ spongeAbsorptionArea = getInt("blocks.sponge.absorption.area", spongeAbsorptionArea);
|
|
+ spongeAbsorptionRadius = getInt("blocks.sponge.absorption.radius", spongeAbsorptionRadius);
|
|
+ spongeAbsorbsLava = getBoolean("blocks.sponge.absorbs-lava", spongeAbsorbsLava);
|
|
+ spongeAbsorbsWaterFromMud = getBoolean("blocks.sponge.absorbs-water-from-mud", spongeAbsorbsWaterFromMud);
|
|
+ }
|
|
+
|
|
+ public float stonecutterDamage = 0.0F;
|
|
+ private void stonecutterSettings() {
|
|
+ stonecutterDamage = (float) getDouble("blocks.stonecutter.damage", stonecutterDamage);
|
|
+ }
|
|
+
|
|
+ public boolean turtleEggsBreakFromExpOrbs = false;
|
|
+ public boolean turtleEggsBreakFromItems = false;
|
|
+ public boolean turtleEggsBreakFromMinecarts = false;
|
|
+ public boolean turtleEggsBypassMobGriefing = false;
|
|
+ public int turtleEggsRandomTickCrackChance = 500;
|
|
+ public boolean turtleEggsTramplingFeatherFalling = false;
|
|
+ private void turtleEggSettings() {
|
|
+ turtleEggsBreakFromExpOrbs = getBoolean("blocks.turtle_egg.break-from-exp-orbs", turtleEggsBreakFromExpOrbs);
|
|
+ turtleEggsBreakFromItems = getBoolean("blocks.turtle_egg.break-from-items", turtleEggsBreakFromItems);
|
|
+ turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts);
|
|
+ turtleEggsBypassMobGriefing = getBoolean("blocks.turtle_egg.bypass-mob-griefing", turtleEggsBypassMobGriefing);
|
|
+ turtleEggsRandomTickCrackChance = getInt("blocks.turtle_egg.random-tick-crack-chance", turtleEggsRandomTickCrackChance);
|
|
+ turtleEggsTramplingFeatherFalling = getBoolean("blocks.turtle_egg.feather-fall-distance-affects-trampling", turtleEggsTramplingFeatherFalling);
|
|
+ }
|
|
+
|
|
+ public int waterInfiniteRequiredSources = 2;
|
|
+ private void waterSources() {
|
|
+ waterInfiniteRequiredSources = getInt("blocks.water.infinite-required-sources", waterInfiniteRequiredSources);
|
|
+ }
|
|
+
|
|
+ public boolean babiesAreRidable = true;
|
|
+ public boolean untamedTamablesAreRidable = true;
|
|
+ public boolean useNightVisionWhenRiding = false;
|
|
+ public boolean useDismountsUnderwaterTag = true;
|
|
+ private void ridableSettings() {
|
|
+ babiesAreRidable = getBoolean("ridable-settings.babies-are-ridable", babiesAreRidable);
|
|
+ untamedTamablesAreRidable = getBoolean("ridable-settings.untamed-tamables-are-ridable", untamedTamablesAreRidable);
|
|
+ useNightVisionWhenRiding = getBoolean("ridable-settings.use-night-vision", useNightVisionWhenRiding);
|
|
+ useDismountsUnderwaterTag = getBoolean("ridable-settings.use-dismounts-underwater-tag", useDismountsUnderwaterTag);
|
|
+ }
|
|
+
|
|
+ public boolean allayRidable = false;
|
|
+ public boolean allayRidableInWater = true;
|
|
+ public boolean allayControllable = true;
|
|
+ public double allayMaxHealth = 20.0D;
|
|
+ public double allayScale = 1.0D;
|
|
+ private void allaySettings() {
|
|
+ allayRidable = getBoolean("mobs.allay.ridable", allayRidable);
|
|
+ allayRidableInWater = getBoolean("mobs.allay.ridable-in-water", allayRidableInWater);
|
|
+ allayControllable = getBoolean("mobs.allay.controllable", allayControllable);
|
|
+ allayMaxHealth = getDouble("mobs.allay.attributes.max_health", allayMaxHealth);
|
|
+ allayScale = Mth.clamp(getDouble("mobs.allay.attributes.scale", allayScale), 0.0625D, 16.0D);
|
|
+ }
|
|
+
|
|
+ public boolean armadilloRidable = false;
|
|
+ public boolean armadilloRidableInWater = true;
|
|
+ public boolean armadilloControllable = true;
|
|
+ public double armadilloMaxHealth = 12.0D;
|
|
+ public double armadilloScale = 1.0D;
|
|
+ public int armadilloBreedingTicks = 6000;
|
|
+ private void armadilloSettings() {
|
|
+ armadilloRidable = getBoolean("mobs.armadillo.ridable", armadilloRidable);
|
|
+ armadilloRidableInWater = getBoolean("mobs.armadillo.ridable-in-water", armadilloRidableInWater);
|
|
+ armadilloControllable = getBoolean("mobs.armadillo.controllable", armadilloControllable);
|
|
+ armadilloMaxHealth = getDouble("mobs.armadillo.attributes.max_health", armadilloMaxHealth);
|
|
+ armadilloScale = Mth.clamp(getDouble("mobs.armadillo.attributes.scale", armadilloScale), 0.0625D, 16.0D);
|
|
+ armadilloBreedingTicks = getInt("mobs.armadillo.breeding-delay-ticks", armadilloBreedingTicks);
|
|
+ }
|
|
+
|
|
+ public boolean axolotlRidable = false;
|
|
+ public boolean axolotlControllable = true;
|
|
+ public double axolotlMaxHealth = 14.0D;
|
|
+ public double axolotlScale = 1.0D;
|
|
+ public int axolotlBreedingTicks = 6000;
|
|
+ public boolean axolotlTakeDamageFromWater = false;
|
|
+ public boolean axolotlAlwaysDropExp = false;
|
|
+ private void axolotlSettings() {
|
|
+ axolotlRidable = getBoolean("mobs.axolotl.ridable", axolotlRidable);
|
|
+ axolotlControllable = getBoolean("mobs.axolotl.controllable", axolotlControllable);
|
|
+ axolotlMaxHealth = getDouble("mobs.axolotl.attributes.max_health", axolotlMaxHealth);
|
|
+ axolotlScale = Mth.clamp(getDouble("mobs.axolotl.attributes.scale", axolotlScale), 0.0625D, 16.0D);
|
|
+ axolotlBreedingTicks = getInt("mobs.axolotl.breeding-delay-ticks", axolotlBreedingTicks);
|
|
+ axolotlTakeDamageFromWater = getBoolean("mobs.axolotl.takes-damage-from-water", axolotlTakeDamageFromWater);
|
|
+ axolotlAlwaysDropExp = getBoolean("mobs.axolotl.always-drop-exp", axolotlAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean batRidable = false;
|
|
+ public boolean batRidableInWater = true;
|
|
+ public boolean batControllable = true;
|
|
+ public double batMaxY = 320D;
|
|
+ public double batMaxHealth = 6.0D;
|
|
+ public double batScale = 1.0D;
|
|
+ public double batFollowRange = 16.0D;
|
|
+ public double batKnockbackResistance = 0.0D;
|
|
+ public double batMovementSpeed = 0.6D;
|
|
+ public double batFlyingSpeed = 0.6D;
|
|
+ public double batArmor = 0.0D;
|
|
+ public double batArmorToughness = 0.0D;
|
|
+ public double batAttackKnockback = 0.0D;
|
|
+ public boolean batTakeDamageFromWater = false;
|
|
+ public boolean batAlwaysDropExp = false;
|
|
+ private void batSettings() {
|
|
+ batRidable = getBoolean("mobs.bat.ridable", batRidable);
|
|
+ batRidableInWater = getBoolean("mobs.bat.ridable-in-water", batRidableInWater);
|
|
+ batControllable = getBoolean("mobs.bat.controllable", batControllable);
|
|
+ batMaxY = getDouble("mobs.bat.ridable-max-y", batMaxY);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.bat.attributes.max-health", batMaxHealth);
|
|
+ set("mobs.bat.attributes.max-health", null);
|
|
+ set("mobs.bat.attributes.max_health", oldValue);
|
|
+ }
|
|
+ batMaxHealth = getDouble("mobs.bat.attributes.max_health", batMaxHealth);
|
|
+ batScale = Mth.clamp(getDouble("mobs.bat.attributes.scale", batScale), 0.0625D, 16.0D);
|
|
+ batFollowRange = getDouble("mobs.bat.attributes.follow_range", batFollowRange);
|
|
+ batKnockbackResistance = getDouble("mobs.bat.attributes.knockback_resistance", batKnockbackResistance);
|
|
+ batMovementSpeed = getDouble("mobs.bat.attributes.movement_speed", batMovementSpeed);
|
|
+ batFlyingSpeed = getDouble("mobs.bat.attributes.flying_speed", batFlyingSpeed);
|
|
+ batArmor = getDouble("mobs.bat.attributes.armor", batArmor);
|
|
+ batArmorToughness = getDouble("mobs.bat.attributes.armor_toughness", batArmorToughness);
|
|
+ batAttackKnockback = getDouble("mobs.bat.attributes.attack_knockback", batAttackKnockback);
|
|
+ batTakeDamageFromWater = getBoolean("mobs.bat.takes-damage-from-water", batTakeDamageFromWater);
|
|
+ batAlwaysDropExp = getBoolean("mobs.bat.always-drop-exp", batAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean beeRidable = false;
|
|
+ public boolean beeRidableInWater = true;
|
|
+ public boolean beeControllable = true;
|
|
+ public double beeMaxY = 320D;
|
|
+ public double beeMaxHealth = 10.0D;
|
|
+ public double beeScale = 1.0D;
|
|
+ public int beeBreedingTicks = 6000;
|
|
+ public boolean beeTakeDamageFromWater = false;
|
|
+ public boolean beeCanWorkAtNight = false;
|
|
+ public boolean beeCanWorkInRain = false;
|
|
+ public boolean beeAlwaysDropExp = false;
|
|
+ public boolean beeDiesAfterSting = true;
|
|
+ private void beeSettings() {
|
|
+ beeRidable = getBoolean("mobs.bee.ridable", beeRidable);
|
|
+ beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater);
|
|
+ beeControllable = getBoolean("mobs.bee.controllable", beeControllable);
|
|
+ beeMaxY = getDouble("mobs.bee.ridable-max-y", beeMaxY);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.bee.attributes.max-health", beeMaxHealth);
|
|
+ set("mobs.bee.attributes.max-health", null);
|
|
+ set("mobs.bee.attributes.max_health", oldValue);
|
|
+ }
|
|
+ beeMaxHealth = getDouble("mobs.bee.attributes.max_health", beeMaxHealth);
|
|
+ beeScale = Mth.clamp(getDouble("mobs.bee.attributes.scale", beeScale), 0.0625D, 16.0D);
|
|
+ beeBreedingTicks = getInt("mobs.bee.breeding-delay-ticks", beeBreedingTicks);
|
|
+ beeTakeDamageFromWater = getBoolean("mobs.bee.takes-damage-from-water", beeTakeDamageFromWater);
|
|
+ beeCanWorkAtNight = getBoolean("mobs.bee.can-work-at-night", beeCanWorkAtNight);
|
|
+ beeCanWorkInRain = getBoolean("mobs.bee.can-work-in-rain", beeCanWorkInRain);
|
|
+ beeAlwaysDropExp = getBoolean("mobs.bee.always-drop-exp", beeAlwaysDropExp);
|
|
+ beeDiesAfterSting = getBoolean("mobs.bee.dies-after-sting", beeDiesAfterSting);
|
|
+ }
|
|
+
|
|
+ public boolean blazeRidable = false;
|
|
+ public boolean blazeRidableInWater = true;
|
|
+ public boolean blazeControllable = true;
|
|
+ public double blazeMaxY = 320D;
|
|
+ public double blazeMaxHealth = 20.0D;
|
|
+ public double blazeScale = 1.0D;
|
|
+ public boolean blazeTakeDamageFromWater = true;
|
|
+ public boolean blazeAlwaysDropExp = false;
|
|
+ private void blazeSettings() {
|
|
+ blazeRidable = getBoolean("mobs.blaze.ridable", blazeRidable);
|
|
+ blazeRidableInWater = getBoolean("mobs.blaze.ridable-in-water", blazeRidableInWater);
|
|
+ blazeControllable = getBoolean("mobs.blaze.controllable", blazeControllable);
|
|
+ blazeMaxY = getDouble("mobs.blaze.ridable-max-y", blazeMaxY);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.blaze.attributes.max-health", blazeMaxHealth);
|
|
+ set("mobs.blaze.attributes.max-health", null);
|
|
+ set("mobs.blaze.attributes.max_health", oldValue);
|
|
+ }
|
|
+ blazeMaxHealth = getDouble("mobs.blaze.attributes.max_health", blazeMaxHealth);
|
|
+ blazeScale = Mth.clamp(getDouble("mobs.blaze.attributes.scale", blazeScale), 0.0625D, 16.0D);
|
|
+ blazeTakeDamageFromWater = getBoolean("mobs.blaze.takes-damage-from-water", blazeTakeDamageFromWater);
|
|
+ blazeAlwaysDropExp = getBoolean("mobs.blaze.always-drop-exp", blazeAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean boggedRidable = false;
|
|
+ public boolean boggedRidableInWater = true;
|
|
+ public boolean boggedControllable = true;
|
|
+ public double boggedMaxHealth = 16.0D;
|
|
+ public double boggedScale = 1.0D;
|
|
+ private void boggedSettings() {
|
|
+ boggedRidable = getBoolean("mobs.bogged.ridable", boggedRidable);
|
|
+ boggedRidableInWater = getBoolean("mobs.bogged.ridable-in-water", boggedRidableInWater);
|
|
+ boggedControllable = getBoolean("mobs.bogged.controllable", boggedControllable);
|
|
+ boggedMaxHealth = getDouble("mobs.bogged.attributes.max_health", boggedMaxHealth);
|
|
+ boggedScale = Mth.clamp(getDouble("mobs.bogged.attributes.scale", boggedScale), 0.0625D, 16.0D);
|
|
+ }
|
|
+
|
|
+ public boolean camelRidableInWater = false;
|
|
+ public double camelMaxHealthMin = 32.0D;
|
|
+ public double camelMaxHealthMax = 32.0D;
|
|
+ public double camelJumpStrengthMin = 0.42D;
|
|
+ public double camelJumpStrengthMax = 0.42D;
|
|
+ public double camelMovementSpeedMin = 0.09D;
|
|
+ public double camelMovementSpeedMax = 0.09D;
|
|
+ public int camelBreedingTicks = 6000;
|
|
+ private void camelSettings() {
|
|
+ camelRidableInWater = getBoolean("mobs.camel.ridable-in-water", camelRidableInWater);
|
|
+ camelMaxHealthMin = getDouble("mobs.camel.attributes.max_health.min", camelMaxHealthMin);
|
|
+ camelMaxHealthMax = getDouble("mobs.camel.attributes.max_health.max", camelMaxHealthMax);
|
|
+ camelJumpStrengthMin = getDouble("mobs.camel.attributes.jump_strength.min", camelJumpStrengthMin);
|
|
+ camelJumpStrengthMax = getDouble("mobs.camel.attributes.jump_strength.max", camelJumpStrengthMax);
|
|
+ camelMovementSpeedMin = getDouble("mobs.camel.attributes.movement_speed.min", camelMovementSpeedMin);
|
|
+ camelMovementSpeedMax = getDouble("mobs.camel.attributes.movement_speed.max", camelMovementSpeedMax);
|
|
+ camelBreedingTicks = getInt("mobs.camel.breeding-delay-ticks", camelBreedingTicks);
|
|
+ }
|
|
+
|
|
+ public boolean catRidable = false;
|
|
+ public boolean catRidableInWater = true;
|
|
+ public boolean catControllable = true;
|
|
+ public double catMaxHealth = 10.0D;
|
|
+ public double catScale = 1.0D;
|
|
+ public int catSpawnDelay = 1200;
|
|
+ public int catSpawnSwampHutScanRange = 16;
|
|
+ public int catSpawnVillageScanRange = 48;
|
|
+ public int catBreedingTicks = 6000;
|
|
+ public DyeColor catDefaultCollarColor = DyeColor.RED;
|
|
+ public boolean catTakeDamageFromWater = false;
|
|
+ public boolean catAlwaysDropExp = false;
|
|
+ private void catSettings() {
|
|
+ catRidable = getBoolean("mobs.cat.ridable", catRidable);
|
|
+ catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater);
|
|
+ catControllable = getBoolean("mobs.cat.controllable", catControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.cat.attributes.max-health", catMaxHealth);
|
|
+ set("mobs.cat.attributes.max-health", null);
|
|
+ set("mobs.cat.attributes.max_health", oldValue);
|
|
+ }
|
|
+ catMaxHealth = getDouble("mobs.cat.attributes.max_health", catMaxHealth);
|
|
+ catScale = Mth.clamp(getDouble("mobs.cat.attributes.scale", catScale), 0.0625D, 16.0D);
|
|
+ catSpawnDelay = getInt("mobs.cat.spawn-delay", catSpawnDelay);
|
|
+ catSpawnSwampHutScanRange = getInt("mobs.cat.scan-range-for-other-cats.swamp-hut", catSpawnSwampHutScanRange);
|
|
+ catSpawnVillageScanRange = getInt("mobs.cat.scan-range-for-other-cats.village", catSpawnVillageScanRange);
|
|
+ catBreedingTicks = getInt("mobs.cat.breeding-delay-ticks", catBreedingTicks);
|
|
+ try {
|
|
+ catDefaultCollarColor = DyeColor.valueOf(getString("mobs.cat.default-collar-color", catDefaultCollarColor.name()));
|
|
+ } catch (IllegalArgumentException ignore) {
|
|
+ catDefaultCollarColor = DyeColor.RED;
|
|
+ }
|
|
+ catTakeDamageFromWater = getBoolean("mobs.cat.takes-damage-from-water", catTakeDamageFromWater);
|
|
+ catAlwaysDropExp = getBoolean("mobs.cat.always-drop-exp", catAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean caveSpiderRidable = false;
|
|
+ public boolean caveSpiderRidableInWater = true;
|
|
+ public boolean caveSpiderControllable = true;
|
|
+ public double caveSpiderMaxHealth = 12.0D;
|
|
+ public double caveSpiderScale = 1.0D;
|
|
+ public boolean caveSpiderTakeDamageFromWater = false;
|
|
+ public boolean caveSpiderAlwaysDropExp = false;
|
|
+ private void caveSpiderSettings() {
|
|
+ caveSpiderRidable = getBoolean("mobs.cave_spider.ridable", caveSpiderRidable);
|
|
+ caveSpiderRidableInWater = getBoolean("mobs.cave_spider.ridable-in-water", caveSpiderRidableInWater);
|
|
+ caveSpiderControllable = getBoolean("mobs.cave_spider.controllable", caveSpiderControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.cave_spider.attributes.max-health", caveSpiderMaxHealth);
|
|
+ set("mobs.cave_spider.attributes.max-health", null);
|
|
+ set("mobs.cave_spider.attributes.max_health", oldValue);
|
|
+ }
|
|
+ caveSpiderMaxHealth = getDouble("mobs.cave_spider.attributes.max_health", caveSpiderMaxHealth);
|
|
+ caveSpiderScale = Mth.clamp(getDouble("mobs.cave_spider.attributes.scale", caveSpiderScale), 0.0625D, 16.0D);
|
|
+ caveSpiderTakeDamageFromWater = getBoolean("mobs.cave_spider.takes-damage-from-water", caveSpiderTakeDamageFromWater);
|
|
+ caveSpiderAlwaysDropExp = getBoolean("mobs.cave_spider.always-drop-exp", caveSpiderAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean chickenRidable = false;
|
|
+ public boolean chickenRidableInWater = false;
|
|
+ public boolean chickenControllable = true;
|
|
+ public double chickenMaxHealth = 4.0D;
|
|
+ public double chickenScale = 1.0D;
|
|
+ public boolean chickenRetaliate = false;
|
|
+ public int chickenBreedingTicks = 6000;
|
|
+ public boolean chickenTakeDamageFromWater = false;
|
|
+ public boolean chickenAlwaysDropExp = false;
|
|
+ private void chickenSettings() {
|
|
+ chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable);
|
|
+ chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater);
|
|
+ chickenControllable = getBoolean("mobs.chicken.controllable", chickenControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.chicken.attributes.max-health", chickenMaxHealth);
|
|
+ set("mobs.chicken.attributes.max-health", null);
|
|
+ set("mobs.chicken.attributes.max_health", oldValue);
|
|
+ }
|
|
+ chickenMaxHealth = getDouble("mobs.chicken.attributes.max_health", chickenMaxHealth);
|
|
+ chickenScale = Mth.clamp(getDouble("mobs.chicken.attributes.scale", chickenScale), 0.0625D, 16.0D);
|
|
+ chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate);
|
|
+ chickenBreedingTicks = getInt("mobs.chicken.breeding-delay-ticks", chickenBreedingTicks);
|
|
+ chickenTakeDamageFromWater = getBoolean("mobs.chicken.takes-damage-from-water", chickenTakeDamageFromWater);
|
|
+ chickenAlwaysDropExp = getBoolean("mobs.chicken.always-drop-exp", chickenAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean codRidable = false;
|
|
+ public boolean codControllable = true;
|
|
+ public double codMaxHealth = 3.0D;
|
|
+ public double codScale = 1.0D;
|
|
+ public boolean codTakeDamageFromWater = false;
|
|
+ public boolean codAlwaysDropExp = false;
|
|
+ private void codSettings() {
|
|
+ codRidable = getBoolean("mobs.cod.ridable", codRidable);
|
|
+ codControllable = getBoolean("mobs.cod.controllable", codControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.cod.attributes.max-health", codMaxHealth);
|
|
+ set("mobs.cod.attributes.max-health", null);
|
|
+ set("mobs.cod.attributes.max_health", oldValue);
|
|
+ }
|
|
+ codMaxHealth = getDouble("mobs.cod.attributes.max_health", codMaxHealth);
|
|
+ codScale = Mth.clamp(getDouble("mobs.cod.attributes.scale", codScale), 0.0625D, 16.0D);
|
|
+ codTakeDamageFromWater = getBoolean("mobs.cod.takes-damage-from-water", codTakeDamageFromWater);
|
|
+ codAlwaysDropExp = getBoolean("mobs.cod.always-drop-exp", codAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean cowRidable = false;
|
|
+ public boolean cowRidableInWater = true;
|
|
+ public boolean cowControllable = true;
|
|
+ public double cowMaxHealth = 10.0D;
|
|
+ public double cowScale = 1.0D;
|
|
+ public int cowFeedMushrooms = 0;
|
|
+ public int cowBreedingTicks = 6000;
|
|
+ public boolean cowTakeDamageFromWater = false;
|
|
+ public double cowNaturallyAggressiveToPlayersChance = 0.0D;
|
|
+ public double cowNaturallyAggressiveToPlayersDamage = 2.0D;
|
|
+ public boolean cowAlwaysDropExp = false;
|
|
+ private void cowSettings() {
|
|
+ if (PurpurConfig.version < 22) {
|
|
+ double oldValue = getDouble("mobs.cow.naturally-aggressive-to-players-chance", cowNaturallyAggressiveToPlayersChance);
|
|
+ set("mobs.cow.naturally-aggressive-to-players-chance", null);
|
|
+ set("mobs.cow.naturally-aggressive-to-players.chance", oldValue);
|
|
+ }
|
|
+ cowRidable = getBoolean("mobs.cow.ridable", cowRidable);
|
|
+ cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater);
|
|
+ cowControllable = getBoolean("mobs.cow.controllable", cowControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.cow.attributes.max-health", cowMaxHealth);
|
|
+ set("mobs.cow.attributes.max-health", null);
|
|
+ set("mobs.cow.attributes.max_health", oldValue);
|
|
+ }
|
|
+ cowMaxHealth = getDouble("mobs.cow.attributes.max_health", cowMaxHealth);
|
|
+ cowScale = Mth.clamp(getDouble("mobs.cow.attributes.scale", cowScale), 0.0625D, 16.0D);
|
|
+ cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms);
|
|
+ cowBreedingTicks = getInt("mobs.cow.breeding-delay-ticks", cowBreedingTicks);
|
|
+ cowTakeDamageFromWater = getBoolean("mobs.cow.takes-damage-from-water", cowTakeDamageFromWater);
|
|
+ cowNaturallyAggressiveToPlayersChance = getDouble("mobs.cow.naturally-aggressive-to-players.chance", cowNaturallyAggressiveToPlayersChance);
|
|
+ cowNaturallyAggressiveToPlayersDamage = getDouble("mobs.cow.naturally-aggressive-to-players.damage", cowNaturallyAggressiveToPlayersDamage);
|
|
+ cowAlwaysDropExp = getBoolean("mobs.cow.always-drop-exp", cowAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean creeperRidable = false;
|
|
+ public boolean creeperRidableInWater = true;
|
|
+ public boolean creeperControllable = true;
|
|
+ public double creeperMaxHealth = 20.0D;
|
|
+ public double creeperScale = 1.0D;
|
|
+ public double creeperChargedChance = 0.0D;
|
|
+ public boolean creeperAllowGriefing = true;
|
|
+ public boolean creeperBypassMobGriefing = false;
|
|
+ public boolean creeperTakeDamageFromWater = false;
|
|
+ public boolean creeperExplodeWhenKilled = false;
|
|
+ public boolean creeperHealthRadius = false;
|
|
+ public boolean creeperAlwaysDropExp = false;
|
|
+ public double creeperHeadVisibilityPercent = 0.5D;
|
|
+ public boolean creeperEncircleTarget = false;
|
|
+ private void creeperSettings() {
|
|
+ creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable);
|
|
+ creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater);
|
|
+ creeperControllable = getBoolean("mobs.creeper.controllable", creeperControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.creeper.attributes.max-health", creeperMaxHealth);
|
|
+ set("mobs.creeper.attributes.max-health", null);
|
|
+ set("mobs.creeper.attributes.max_health", oldValue);
|
|
+ }
|
|
+ creeperMaxHealth = getDouble("mobs.creeper.attributes.max_health", creeperMaxHealth);
|
|
+ creeperScale = Mth.clamp(getDouble("mobs.creeper.attributes.scale", creeperScale), 0.0625D, 16.0D);
|
|
+ creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance);
|
|
+ creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing);
|
|
+ creeperBypassMobGriefing = getBoolean("mobs.creeper.bypass-mob-griefing", creeperBypassMobGriefing);
|
|
+ creeperTakeDamageFromWater = getBoolean("mobs.creeper.takes-damage-from-water", creeperTakeDamageFromWater);
|
|
+ creeperExplodeWhenKilled = getBoolean("mobs.creeper.explode-when-killed", creeperExplodeWhenKilled);
|
|
+ creeperHealthRadius = getBoolean("mobs.creeper.health-impacts-explosion", creeperHealthRadius);
|
|
+ creeperAlwaysDropExp = getBoolean("mobs.creeper.always-drop-exp", creeperAlwaysDropExp);
|
|
+ creeperHeadVisibilityPercent = getDouble("mobs.creeper.head-visibility-percent", creeperHeadVisibilityPercent);
|
|
+ creeperEncircleTarget = getBoolean("mobs.creeper.encircle-target", creeperEncircleTarget);
|
|
+ }
|
|
+
|
|
+ public boolean dolphinRidable = false;
|
|
+ public boolean dolphinControllable = true;
|
|
+ public int dolphinSpitCooldown = 20;
|
|
+ public float dolphinSpitSpeed = 1.0F;
|
|
+ public float dolphinSpitDamage = 2.0F;
|
|
+ public double dolphinMaxHealth = 10.0D;
|
|
+ public double dolphinScale = 1.0D;
|
|
+ public boolean dolphinDisableTreasureSearching = false;
|
|
+ public boolean dolphinTakeDamageFromWater = false;
|
|
+ public double dolphinNaturallyAggressiveToPlayersChance = 0.0D;
|
|
+ public boolean dolphinAlwaysDropExp = false;
|
|
+ private void dolphinSettings() {
|
|
+ dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable);
|
|
+ dolphinControllable = getBoolean("mobs.dolphin.controllable", dolphinControllable);
|
|
+ dolphinSpitCooldown = getInt("mobs.dolphin.spit.cooldown", dolphinSpitCooldown);
|
|
+ dolphinSpitSpeed = (float) getDouble("mobs.dolphin.spit.speed", dolphinSpitSpeed);
|
|
+ dolphinSpitDamage = (float) getDouble("mobs.dolphin.spit.damage", dolphinSpitDamage);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.dolphin.attributes.max-health", dolphinMaxHealth);
|
|
+ set("mobs.dolphin.attributes.max-health", null);
|
|
+ set("mobs.dolphin.attributes.max_health", oldValue);
|
|
+ }
|
|
+ dolphinMaxHealth = getDouble("mobs.dolphin.attributes.max_health", dolphinMaxHealth);
|
|
+ dolphinScale = Mth.clamp(getDouble("mobs.dolphin.attributes.scale", dolphinScale), 0.0625D, 16.0D);
|
|
+ dolphinDisableTreasureSearching = getBoolean("mobs.dolphin.disable-treasure-searching", dolphinDisableTreasureSearching);
|
|
+ dolphinTakeDamageFromWater = getBoolean("mobs.dolphin.takes-damage-from-water", dolphinTakeDamageFromWater);
|
|
+ dolphinNaturallyAggressiveToPlayersChance = getDouble("mobs.dolphin.naturally-aggressive-to-players-chance", dolphinNaturallyAggressiveToPlayersChance);
|
|
+ dolphinAlwaysDropExp = getBoolean("mobs.dolphin.always-drop-exp", dolphinAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean donkeyRidableInWater = false;
|
|
+ public double donkeyMaxHealthMin = 15.0D;
|
|
+ public double donkeyMaxHealthMax = 30.0D;
|
|
+ public double donkeyJumpStrengthMin = 0.5D;
|
|
+ public double donkeyJumpStrengthMax = 0.5D;
|
|
+ public double donkeyMovementSpeedMin = 0.175D;
|
|
+ public double donkeyMovementSpeedMax = 0.175D;
|
|
+ public int donkeyBreedingTicks = 6000;
|
|
+ public boolean donkeyTakeDamageFromWater = false;
|
|
+ public boolean donkeyAlwaysDropExp = false;
|
|
+ private void donkeySettings() {
|
|
+ donkeyRidableInWater = getBoolean("mobs.donkey.ridable-in-water", donkeyRidableInWater);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldMin = getDouble("mobs.donkey.attributes.max-health.min", donkeyMaxHealthMin);
|
|
+ double oldMax = getDouble("mobs.donkey.attributes.max-health.max", donkeyMaxHealthMax);
|
|
+ set("mobs.donkey.attributes.max-health", null);
|
|
+ set("mobs.donkey.attributes.max_health.min", oldMin);
|
|
+ set("mobs.donkey.attributes.max_health.max", oldMax);
|
|
+ }
|
|
+ donkeyMaxHealthMin = getDouble("mobs.donkey.attributes.max_health.min", donkeyMaxHealthMin);
|
|
+ donkeyMaxHealthMax = getDouble("mobs.donkey.attributes.max_health.max", donkeyMaxHealthMax);
|
|
+ donkeyJumpStrengthMin = getDouble("mobs.donkey.attributes.jump_strength.min", donkeyJumpStrengthMin);
|
|
+ donkeyJumpStrengthMax = getDouble("mobs.donkey.attributes.jump_strength.max", donkeyJumpStrengthMax);
|
|
+ donkeyMovementSpeedMin = getDouble("mobs.donkey.attributes.movement_speed.min", donkeyMovementSpeedMin);
|
|
+ donkeyMovementSpeedMax = getDouble("mobs.donkey.attributes.movement_speed.max", donkeyMovementSpeedMax);
|
|
+ donkeyBreedingTicks = getInt("mobs.donkey.breeding-delay-ticks", donkeyBreedingTicks);
|
|
+ donkeyTakeDamageFromWater = getBoolean("mobs.donkey.takes-damage-from-water", donkeyTakeDamageFromWater);
|
|
+ donkeyAlwaysDropExp = getBoolean("mobs.donkey.always-drop-exp", donkeyAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean drownedRidable = false;
|
|
+ public boolean drownedRidableInWater = true;
|
|
+ public boolean drownedControllable = true;
|
|
+ public double drownedMaxHealth = 20.0D;
|
|
+ public double drownedScale = 1.0D;
|
|
+ public double drownedSpawnReinforcements = 0.1D;
|
|
+ public boolean drownedJockeyOnlyBaby = true;
|
|
+ public double drownedJockeyChance = 0.05D;
|
|
+ public boolean drownedJockeyTryExistingChickens = true;
|
|
+ public boolean drownedTakeDamageFromWater = false;
|
|
+ public boolean drownedBreakDoors = false;
|
|
+ public boolean drownedAlwaysDropExp = false;
|
|
+ private void drownedSettings() {
|
|
+ drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable);
|
|
+ drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater);
|
|
+ drownedControllable = getBoolean("mobs.drowned.controllable", drownedControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.drowned.attributes.max-health", drownedMaxHealth);
|
|
+ set("mobs.drowned.attributes.max-health", null);
|
|
+ set("mobs.drowned.attributes.max_health", oldValue);
|
|
+ }
|
|
+ drownedMaxHealth = getDouble("mobs.drowned.attributes.max_health", drownedMaxHealth);
|
|
+ drownedScale = Mth.clamp(getDouble("mobs.drowned.attributes.scale", drownedScale), 0.0625D, 16.0D);
|
|
+ drownedSpawnReinforcements = getDouble("mobs.drowned.attributes.spawn_reinforcements", drownedSpawnReinforcements);
|
|
+ drownedJockeyOnlyBaby = getBoolean("mobs.drowned.jockey.only-babies", drownedJockeyOnlyBaby);
|
|
+ drownedJockeyChance = getDouble("mobs.drowned.jockey.chance", drownedJockeyChance);
|
|
+ drownedJockeyTryExistingChickens = getBoolean("mobs.drowned.jockey.try-existing-chickens", drownedJockeyTryExistingChickens);
|
|
+ drownedTakeDamageFromWater = getBoolean("mobs.drowned.takes-damage-from-water", drownedTakeDamageFromWater);
|
|
+ drownedBreakDoors = getBoolean("mobs.drowned.can-break-doors", drownedBreakDoors);
|
|
+ drownedAlwaysDropExp = getBoolean("mobs.drowned.always-drop-exp", drownedAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean elderGuardianRidable = false;
|
|
+ public boolean elderGuardianControllable = true;
|
|
+ public double elderGuardianMaxHealth = 80.0D;
|
|
+ public double elderGuardianScale = 1.0D;
|
|
+ public boolean elderGuardianTakeDamageFromWater = false;
|
|
+ public boolean elderGuardianAlwaysDropExp = false;
|
|
+ private void elderGuardianSettings() {
|
|
+ elderGuardianRidable = getBoolean("mobs.elder_guardian.ridable", elderGuardianRidable);
|
|
+ elderGuardianControllable = getBoolean("mobs.elder_guardian.controllable", elderGuardianControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.elder_guardian.attributes.max-health", elderGuardianMaxHealth);
|
|
+ set("mobs.elder_guardian.attributes.max-health", null);
|
|
+ set("mobs.elder_guardian.attributes.max_health", oldValue);
|
|
+ }
|
|
+ elderGuardianMaxHealth = getDouble("mobs.elder_guardian.attributes.max_health", elderGuardianMaxHealth);
|
|
+ elderGuardianScale = Mth.clamp(getDouble("mobs.elder_guardian.attributes.scale", elderGuardianScale), 0.0625D, 16.0D);
|
|
+ elderGuardianTakeDamageFromWater = getBoolean("mobs.elder_guardian.takes-damage-from-water", elderGuardianTakeDamageFromWater);
|
|
+ elderGuardianAlwaysDropExp = getBoolean("mobs.elder_guardian.always-drop-exp", elderGuardianAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean enchantmentTableLapisPersists = false;
|
|
+ private void enchantmentTableSettings() {
|
|
+ enchantmentTableLapisPersists = getBoolean("blocks.enchantment-table.lapis-persists", enchantmentTableLapisPersists);
|
|
+ }
|
|
+
|
|
+ public boolean enderDragonRidable = false;
|
|
+ public boolean enderDragonRidableInWater = true;
|
|
+ public boolean enderDragonControllable = true;
|
|
+ public double enderDragonMaxY = 320D;
|
|
+ public double enderDragonMaxHealth = 200.0D;
|
|
+ public boolean enderDragonAlwaysDropsFullExp = false;
|
|
+ public boolean enderDragonBypassMobGriefing = false;
|
|
+ public boolean enderDragonTakeDamageFromWater = false;
|
|
+ public boolean enderDragonCanRideVehicles = false;
|
|
+ private void enderDragonSettings() {
|
|
+ enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable);
|
|
+ enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater);
|
|
+ enderDragonControllable = getBoolean("mobs.ender_dragon.controllable", enderDragonControllable);
|
|
+ enderDragonMaxY = getDouble("mobs.ender_dragon.ridable-max-y", enderDragonMaxY);
|
|
+ if (PurpurConfig.version < 8) {
|
|
+ double oldValue = getDouble("mobs.ender_dragon.max-health", enderDragonMaxHealth);
|
|
+ set("mobs.ender_dragon.max-health", null);
|
|
+ set("mobs.ender_dragon.attributes.max_health", oldValue);
|
|
+ } else if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.ender_dragon.attributes.max-health", enderDragonMaxHealth);
|
|
+ set("mobs.ender_dragon.attributes.max-health", null);
|
|
+ set("mobs.ender_dragon.attributes.max_health", oldValue);
|
|
+ }
|
|
+ enderDragonMaxHealth = getDouble("mobs.ender_dragon.attributes.max_health", enderDragonMaxHealth);
|
|
+ enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp);
|
|
+ enderDragonBypassMobGriefing = getBoolean("mobs.ender_dragon.bypass-mob-griefing", enderDragonBypassMobGriefing);
|
|
+ enderDragonTakeDamageFromWater = getBoolean("mobs.ender_dragon.takes-damage-from-water", enderDragonTakeDamageFromWater);
|
|
+ enderDragonCanRideVehicles = getBoolean("mobs.ender_dragon.can-ride-vehicles", enderDragonCanRideVehicles);
|
|
+ }
|
|
+
|
|
+ public boolean endermanRidable = false;
|
|
+ public boolean endermanRidableInWater = true;
|
|
+ public boolean endermanControllable = true;
|
|
+ public double endermanMaxHealth = 40.0D;
|
|
+ public double endermanScale = 1.0D;
|
|
+ public boolean endermanAllowGriefing = true;
|
|
+ public boolean endermanDespawnEvenWithBlock = false;
|
|
+ public boolean endermanBypassMobGriefing = false;
|
|
+ public boolean endermanTakeDamageFromWater = true;
|
|
+ public boolean endermanAggroEndermites = true;
|
|
+ public boolean endermanAggroEndermitesOnlyIfPlayerSpawned = false;
|
|
+ public boolean endermanDisableStareAggro = false;
|
|
+ public boolean endermanIgnoreProjectiles = false;
|
|
+ public boolean endermanAlwaysDropExp = false;
|
|
+ private void endermanSettings() {
|
|
+ endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable);
|
|
+ endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater);
|
|
+ endermanControllable = getBoolean("mobs.enderman.controllable", endermanControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.enderman.attributes.max-health", endermanMaxHealth);
|
|
+ set("mobs.enderman.attributes.max-health", null);
|
|
+ set("mobs.enderman.attributes.max_health", oldValue);
|
|
+ }
|
|
+ if (PurpurConfig.version < 15) {
|
|
+ // remove old option
|
|
+ set("mobs.enderman.aggressive-towards-spawned-endermites", null);
|
|
+ }
|
|
+ endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth);
|
|
+ endermanScale = Mth.clamp(getDouble("mobs.enderman.attributes.scale", endermanScale), 0.0625D, 16.0D);
|
|
+ endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing);
|
|
+ endermanDespawnEvenWithBlock = getBoolean("mobs.enderman.can-despawn-with-held-block", endermanDespawnEvenWithBlock);
|
|
+ endermanBypassMobGriefing = getBoolean("mobs.enderman.bypass-mob-griefing", endermanBypassMobGriefing);
|
|
+ endermanTakeDamageFromWater = getBoolean("mobs.enderman.takes-damage-from-water", endermanTakeDamageFromWater);
|
|
+ endermanAggroEndermites = getBoolean("mobs.enderman.aggressive-towards-endermites", endermanAggroEndermites);
|
|
+ endermanAggroEndermitesOnlyIfPlayerSpawned = getBoolean("mobs.enderman.aggressive-towards-endermites-only-spawned-by-player-thrown-ender-pearls", endermanAggroEndermitesOnlyIfPlayerSpawned);
|
|
+ endermanDisableStareAggro = getBoolean("mobs.enderman.disable-player-stare-aggression", endermanDisableStareAggro);
|
|
+ endermanIgnoreProjectiles = getBoolean("mobs.enderman.ignore-projectiles", endermanIgnoreProjectiles);
|
|
+ endermanAlwaysDropExp = getBoolean("mobs.enderman.always-drop-exp", endermanAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean endermiteRidable = false;
|
|
+ public boolean endermiteRidableInWater = true;
|
|
+ public boolean endermiteControllable = true;
|
|
+ public double endermiteMaxHealth = 8.0D;
|
|
+ public double endermiteScale = 1.0D;
|
|
+ public boolean endermiteTakeDamageFromWater = false;
|
|
+ public boolean endermiteAlwaysDropExp = false;
|
|
+ private void endermiteSettings() {
|
|
+ endermiteRidable = getBoolean("mobs.endermite.ridable", endermiteRidable);
|
|
+ endermiteRidableInWater = getBoolean("mobs.endermite.ridable-in-water", endermiteRidableInWater);
|
|
+ endermiteControllable = getBoolean("mobs.endermite.controllable", endermiteControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.endermite.attributes.max-health", endermiteMaxHealth);
|
|
+ set("mobs.endermite.attributes.max-health", null);
|
|
+ set("mobs.endermite.attributes.max_health", oldValue);
|
|
+ }
|
|
+ endermiteMaxHealth = getDouble("mobs.endermite.attributes.max_health", endermiteMaxHealth);
|
|
+ endermiteScale = Mth.clamp(getDouble("mobs.endermite.attributes.scale", endermiteScale), 0.0625D, 16.0D);
|
|
+ endermiteTakeDamageFromWater = getBoolean("mobs.endermite.takes-damage-from-water", endermiteTakeDamageFromWater);
|
|
+ endermiteAlwaysDropExp = getBoolean("mobs.endermite.always-drop-exp", endermiteAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean evokerRidable = false;
|
|
+ public boolean evokerRidableInWater = true;
|
|
+ public boolean evokerControllable = true;
|
|
+ public double evokerMaxHealth = 24.0D;
|
|
+ public double evokerScale = 1.0D;
|
|
+ public boolean evokerBypassMobGriefing = false;
|
|
+ public boolean evokerTakeDamageFromWater = false;
|
|
+ public boolean evokerAlwaysDropExp = false;
|
|
+ private void evokerSettings() {
|
|
+ evokerRidable = getBoolean("mobs.evoker.ridable", evokerRidable);
|
|
+ evokerRidableInWater = getBoolean("mobs.evoker.ridable-in-water", evokerRidableInWater);
|
|
+ evokerControllable = getBoolean("mobs.evoker.controllable", evokerControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.evoker.attributes.max-health", evokerMaxHealth);
|
|
+ set("mobs.evoker.attributes.max-health", null);
|
|
+ set("mobs.evoker.attributes.max_health", oldValue);
|
|
+ }
|
|
+ evokerMaxHealth = getDouble("mobs.evoker.attributes.max_health", evokerMaxHealth);
|
|
+ evokerScale = Mth.clamp(getDouble("mobs.evoker.attributes.scale", evokerScale), 0.0625D, 16.0D);
|
|
+ evokerBypassMobGriefing = getBoolean("mobs.evoker.bypass-mob-griefing", evokerBypassMobGriefing);
|
|
+ evokerTakeDamageFromWater = getBoolean("mobs.evoker.takes-damage-from-water", evokerTakeDamageFromWater);
|
|
+ evokerAlwaysDropExp = getBoolean("mobs.evoker.always-drop-exp", evokerAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean foxRidable = false;
|
|
+ public boolean foxRidableInWater = true;
|
|
+ public boolean foxControllable = true;
|
|
+ public double foxMaxHealth = 10.0D;
|
|
+ public double foxScale = 1.0D;
|
|
+ public boolean foxTypeChangesWithTulips = false;
|
|
+ public int foxBreedingTicks = 6000;
|
|
+ public boolean foxBypassMobGriefing = false;
|
|
+ public boolean foxTakeDamageFromWater = false;
|
|
+ public boolean foxAlwaysDropExp = false;
|
|
+ private void foxSettings() {
|
|
+ foxRidable = getBoolean("mobs.fox.ridable", foxRidable);
|
|
+ foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater);
|
|
+ foxControllable = getBoolean("mobs.fox.controllable", foxControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.fox.attributes.max-health", foxMaxHealth);
|
|
+ set("mobs.fox.attributes.max-health", null);
|
|
+ set("mobs.fox.attributes.max_health", oldValue);
|
|
+ }
|
|
+ foxMaxHealth = getDouble("mobs.fox.attributes.max_health", foxMaxHealth);
|
|
+ foxScale = Mth.clamp(getDouble("mobs.fox.attributes.scale", foxScale), 0.0625D, 16.0D);
|
|
+ foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips);
|
|
+ foxBreedingTicks = getInt("mobs.fox.breeding-delay-ticks", foxBreedingTicks);
|
|
+ foxBypassMobGriefing = getBoolean("mobs.fox.bypass-mob-griefing", foxBypassMobGriefing);
|
|
+ foxTakeDamageFromWater = getBoolean("mobs.fox.takes-damage-from-water", foxTakeDamageFromWater);
|
|
+ foxAlwaysDropExp = getBoolean("mobs.fox.always-drop-exp", foxAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean frogRidable = false;
|
|
+ public boolean frogRidableInWater = true;
|
|
+ public boolean frogControllable = true;
|
|
+ public float frogRidableJumpHeight = 0.65F;
|
|
+ public int frogBreedingTicks = 6000;
|
|
+ private void frogSettings() {
|
|
+ frogRidable = getBoolean("mobs.frog.ridable", frogRidable);
|
|
+ frogRidableInWater = getBoolean("mobs.frog.ridable-in-water", frogRidableInWater);
|
|
+ frogControllable = getBoolean("mobs.frog.controllable", frogControllable);
|
|
+ frogRidableJumpHeight = (float) getDouble("mobs.frog.ridable-jump-height", frogRidableJumpHeight);
|
|
+ frogBreedingTicks = getInt("mobs.frog.breeding-delay-ticks", frogBreedingTicks);
|
|
+ }
|
|
+
|
|
+ public boolean ghastRidable = false;
|
|
+ public boolean ghastRidableInWater = true;
|
|
+ public boolean ghastControllable = true;
|
|
+ public double ghastMaxY = 320D;
|
|
+ public double ghastMaxHealth = 10.0D;
|
|
+ public double ghastScale = 1.0D;
|
|
+ public boolean ghastTakeDamageFromWater = false;
|
|
+ public boolean ghastAlwaysDropExp = false;
|
|
+ private void ghastSettings() {
|
|
+ ghastRidable = getBoolean("mobs.ghast.ridable", ghastRidable);
|
|
+ ghastRidableInWater = getBoolean("mobs.ghast.ridable-in-water", ghastRidableInWater);
|
|
+ ghastControllable = getBoolean("mobs.ghast.controllable", ghastControllable);
|
|
+ ghastMaxY = getDouble("mobs.ghast.ridable-max-y", ghastMaxY);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.ghast.attributes.max-health", ghastMaxHealth);
|
|
+ set("mobs.ghast.attributes.max-health", null);
|
|
+ set("mobs.ghast.attributes.max_health", oldValue);
|
|
+ }
|
|
+ ghastMaxHealth = getDouble("mobs.ghast.attributes.max_health", ghastMaxHealth);
|
|
+ ghastScale = Mth.clamp(getDouble("mobs.ghast.attributes.scale", ghastScale), 0.0625D, 16.0D);
|
|
+ ghastTakeDamageFromWater = getBoolean("mobs.ghast.takes-damage-from-water", ghastTakeDamageFromWater);
|
|
+ ghastAlwaysDropExp = getBoolean("mobs.ghast.always-drop-exp", ghastAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean giantRidable = false;
|
|
+ public boolean giantRidableInWater = true;
|
|
+ public boolean giantControllable = true;
|
|
+ public double giantMovementSpeed = 0.5D;
|
|
+ public double giantAttackDamage = 50.0D;
|
|
+ public double giantMaxHealth = 100.0D;
|
|
+ public double giantScale = 1.0D;
|
|
+ public float giantStepHeight = 2.0F;
|
|
+ public float giantJumpHeight = 1.0F;
|
|
+ public boolean giantHaveAI = false;
|
|
+ public boolean giantHaveHostileAI = false;
|
|
+ public boolean giantTakeDamageFromWater = false;
|
|
+ public boolean giantAlwaysDropExp = false;
|
|
+ private void giantSettings() {
|
|
+ giantRidable = getBoolean("mobs.giant.ridable", giantRidable);
|
|
+ giantRidableInWater = getBoolean("mobs.giant.ridable-in-water", giantRidableInWater);
|
|
+ giantControllable = getBoolean("mobs.giant.controllable", giantControllable);
|
|
+ giantMovementSpeed = getDouble("mobs.giant.movement-speed", giantMovementSpeed);
|
|
+ giantAttackDamage = getDouble("mobs.giant.attack-damage", giantAttackDamage);
|
|
+ if (PurpurConfig.version < 8) {
|
|
+ double oldValue = getDouble("mobs.giant.max-health", giantMaxHealth);
|
|
+ set("mobs.giant.max-health", null);
|
|
+ set("mobs.giant.attributes.max_health", oldValue);
|
|
+ } else if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.giant.attributes.max-health", giantMaxHealth);
|
|
+ set("mobs.giant.attributes.max-health", null);
|
|
+ set("mobs.giant.attributes.max_health", oldValue);
|
|
+ }
|
|
+ giantMaxHealth = getDouble("mobs.giant.attributes.max_health", giantMaxHealth);
|
|
+ giantScale = Mth.clamp(getDouble("mobs.giant.attributes.scale", giantScale), 0.0625D, 16.0D);
|
|
+ giantStepHeight = (float) getDouble("mobs.giant.step-height", giantStepHeight);
|
|
+ giantJumpHeight = (float) getDouble("mobs.giant.jump-height", giantJumpHeight);
|
|
+ giantHaveAI = getBoolean("mobs.giant.have-ai", giantHaveAI);
|
|
+ giantHaveHostileAI = getBoolean("mobs.giant.have-hostile-ai", giantHaveHostileAI);
|
|
+ giantTakeDamageFromWater = getBoolean("mobs.giant.takes-damage-from-water", giantTakeDamageFromWater);
|
|
+ giantAlwaysDropExp = getBoolean("mobs.giant.always-drop-exp", giantAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean glowSquidRidable = false;
|
|
+ public boolean glowSquidControllable = true;
|
|
+ public double glowSquidMaxHealth = 10.0D;
|
|
+ public double glowSquidScale = 1.0D;
|
|
+ public boolean glowSquidsCanFly = false;
|
|
+ public boolean glowSquidTakeDamageFromWater = false;
|
|
+ public boolean glowSquidAlwaysDropExp = false;
|
|
+ private void glowSquidSettings() {
|
|
+ glowSquidRidable = getBoolean("mobs.glow_squid.ridable", glowSquidRidable);
|
|
+ glowSquidControllable = getBoolean("mobs.glow_squid.controllable", glowSquidControllable);
|
|
+ glowSquidMaxHealth = getDouble("mobs.glow_squid.attributes.max_health", glowSquidMaxHealth);
|
|
+ glowSquidScale = Mth.clamp(getDouble("mobs.glow_squid.attributes.scale", glowSquidScale), 0.0625D, 16.0D);
|
|
+ glowSquidsCanFly = getBoolean("mobs.glow_squid.can-fly", glowSquidsCanFly);
|
|
+ glowSquidTakeDamageFromWater = getBoolean("mobs.glow_squid.takes-damage-from-water", glowSquidTakeDamageFromWater);
|
|
+ glowSquidAlwaysDropExp = getBoolean("mobs.glow_squid.always-drop-exp", glowSquidAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean goatRidable = false;
|
|
+ public boolean goatRidableInWater = true;
|
|
+ public boolean goatControllable = true;
|
|
+ public double goatMaxHealth = 10.0D;
|
|
+ public double goatScale = 1.0D;
|
|
+ public int goatBreedingTicks = 6000;
|
|
+ public boolean goatTakeDamageFromWater = false;
|
|
+ public boolean goatAlwaysDropExp = false;
|
|
+ private void goatSettings() {
|
|
+ goatRidable = getBoolean("mobs.goat.ridable", goatRidable);
|
|
+ goatRidableInWater = getBoolean("mobs.goat.ridable-in-water", goatRidableInWater);
|
|
+ goatControllable = getBoolean("mobs.goat.controllable", goatControllable);
|
|
+ goatMaxHealth = getDouble("mobs.goat.attributes.max_health", goatMaxHealth);
|
|
+ goatScale = Mth.clamp(getDouble("mobs.goat.attributes.scale", goatScale), 0.0625D, 16.0D);
|
|
+ goatBreedingTicks = getInt("mobs.goat.breeding-delay-ticks", goatBreedingTicks);
|
|
+ goatTakeDamageFromWater = getBoolean("mobs.goat.takes-damage-from-water", goatTakeDamageFromWater);
|
|
+ goatAlwaysDropExp = getBoolean("mobs.goat.always-drop-exp", goatAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean guardianRidable = false;
|
|
+ public boolean guardianControllable = true;
|
|
+ public double guardianMaxHealth = 30.0D;
|
|
+ public double guardianScale = 1.0D;
|
|
+ public boolean guardianTakeDamageFromWater = false;
|
|
+ public boolean guardianAlwaysDropExp = false;
|
|
+ private void guardianSettings() {
|
|
+ guardianRidable = getBoolean("mobs.guardian.ridable", guardianRidable);
|
|
+ guardianControllable = getBoolean("mobs.guardian.controllable", guardianControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.guardian.attributes.max-health", guardianMaxHealth);
|
|
+ set("mobs.guardian.attributes.max-health", null);
|
|
+ set("mobs.guardian.attributes.max_health", oldValue);
|
|
+ }
|
|
+ guardianMaxHealth = getDouble("mobs.guardian.attributes.max_health", guardianMaxHealth);
|
|
+ guardianScale = Mth.clamp(getDouble("mobs.guardian.attributes.scale", guardianScale), 0.0625D, 16.0D);
|
|
+ guardianTakeDamageFromWater = getBoolean("mobs.guardian.takes-damage-from-water", guardianTakeDamageFromWater);
|
|
+ guardianAlwaysDropExp = getBoolean("mobs.guardian.always-drop-exp", guardianAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean forceHalloweenSeason = false;
|
|
+ public float chanceHeadHalloweenOnEntity = 0.25F;
|
|
+ private void halloweenSetting() {
|
|
+ forceHalloweenSeason = getBoolean("gameplay-mechanics.halloween.force", forceHalloweenSeason);
|
|
+ chanceHeadHalloweenOnEntity = (float) getDouble("gameplay-mechanics.halloween.head-chance", chanceHeadHalloweenOnEntity);
|
|
+ }
|
|
+
|
|
+ public boolean hoglinRidable = false;
|
|
+ public boolean hoglinRidableInWater = true;
|
|
+ public boolean hoglinControllable = true;
|
|
+ public double hoglinMaxHealth = 40.0D;
|
|
+ public double hoglinScale = 1.0D;
|
|
+ public int hoglinBreedingTicks = 6000;
|
|
+ public boolean hoglinTakeDamageFromWater = false;
|
|
+ public boolean hoglinAlwaysDropExp = false;
|
|
+ private void hoglinSettings() {
|
|
+ hoglinRidable = getBoolean("mobs.hoglin.ridable", hoglinRidable);
|
|
+ hoglinRidableInWater = getBoolean("mobs.hoglin.ridable-in-water", hoglinRidableInWater);
|
|
+ hoglinControllable = getBoolean("mobs.hoglin.controllable", hoglinControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.hoglin.attributes.max-health", hoglinMaxHealth);
|
|
+ set("mobs.hoglin.attributes.max-health", null);
|
|
+ set("mobs.hoglin.attributes.max_health", oldValue);
|
|
+ }
|
|
+ hoglinMaxHealth = getDouble("mobs.hoglin.attributes.max_health", hoglinMaxHealth);
|
|
+ hoglinScale = Mth.clamp(getDouble("mobs.hoglin.attributes.scale", hoglinScale), 0.0625D, 16.0D);
|
|
+ hoglinBreedingTicks = getInt("mobs.hoglin.breeding-delay-ticks", hoglinBreedingTicks);
|
|
+ hoglinTakeDamageFromWater = getBoolean("mobs.hoglin.takes-damage-from-water", hoglinTakeDamageFromWater);
|
|
+ hoglinAlwaysDropExp = getBoolean("mobs.hoglin.always-drop-exp", hoglinAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean horseRidableInWater = false;
|
|
+ public double horseMaxHealthMin = 15.0D;
|
|
+ public double horseMaxHealthMax = 30.0D;
|
|
+ public double horseJumpStrengthMin = 0.4D;
|
|
+ public double horseJumpStrengthMax = 1.0D;
|
|
+ public double horseMovementSpeedMin = 0.1125D;
|
|
+ public double horseMovementSpeedMax = 0.3375D;
|
|
+ public int horseBreedingTicks = 6000;
|
|
+ public boolean horseTakeDamageFromWater = false;
|
|
+ public boolean horseAlwaysDropExp = false;
|
|
+ private void horseSettings() {
|
|
+ horseRidableInWater = getBoolean("mobs.horse.ridable-in-water", horseRidableInWater);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldMin = getDouble("mobs.horse.attributes.max-health.min", horseMaxHealthMin);
|
|
+ double oldMax = getDouble("mobs.horse.attributes.max-health.max", horseMaxHealthMax);
|
|
+ set("mobs.horse.attributes.max-health", null);
|
|
+ set("mobs.horse.attributes.max_health.min", oldMin);
|
|
+ set("mobs.horse.attributes.max_health.max", oldMax);
|
|
+ }
|
|
+ horseMaxHealthMin = getDouble("mobs.horse.attributes.max_health.min", horseMaxHealthMin);
|
|
+ horseMaxHealthMax = getDouble("mobs.horse.attributes.max_health.max", horseMaxHealthMax);
|
|
+ horseJumpStrengthMin = getDouble("mobs.horse.attributes.jump_strength.min", horseJumpStrengthMin);
|
|
+ horseJumpStrengthMax = getDouble("mobs.horse.attributes.jump_strength.max", horseJumpStrengthMax);
|
|
+ horseMovementSpeedMin = getDouble("mobs.horse.attributes.movement_speed.min", horseMovementSpeedMin);
|
|
+ horseMovementSpeedMax = getDouble("mobs.horse.attributes.movement_speed.max", horseMovementSpeedMax);
|
|
+ horseBreedingTicks = getInt("mobs.horse.breeding-delay-ticks", horseBreedingTicks);
|
|
+ horseTakeDamageFromWater = getBoolean("mobs.horse.takes-damage-from-water", horseTakeDamageFromWater);
|
|
+ horseAlwaysDropExp = getBoolean("mobs.horse.always-drop-exp", horseAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean huskRidable = false;
|
|
+ public boolean huskRidableInWater = true;
|
|
+ public boolean huskControllable = true;
|
|
+ public double huskMaxHealth = 20.0D;
|
|
+ public double huskScale = 1.0D;
|
|
+ public double huskSpawnReinforcements = 0.1D;
|
|
+ public boolean huskJockeyOnlyBaby = true;
|
|
+ public double huskJockeyChance = 0.05D;
|
|
+ public boolean huskJockeyTryExistingChickens = true;
|
|
+ public boolean huskTakeDamageFromWater = false;
|
|
+ public boolean huskAlwaysDropExp = false;
|
|
+ private void huskSettings() {
|
|
+ huskRidable = getBoolean("mobs.husk.ridable", huskRidable);
|
|
+ huskRidableInWater = getBoolean("mobs.husk.ridable-in-water", huskRidableInWater);
|
|
+ huskControllable = getBoolean("mobs.husk.controllable", huskControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.husk.attributes.max-health", huskMaxHealth);
|
|
+ set("mobs.husk.attributes.max-health", null);
|
|
+ set("mobs.husk.attributes.max_health", oldValue);
|
|
+ }
|
|
+ huskMaxHealth = getDouble("mobs.husk.attributes.max_health", huskMaxHealth);
|
|
+ huskScale = Mth.clamp(getDouble("mobs.husk.attributes.scale", huskScale), 0.0625D, 16.0D);
|
|
+ huskSpawnReinforcements = getDouble("mobs.husk.attributes.spawn_reinforcements", huskSpawnReinforcements);
|
|
+ huskJockeyOnlyBaby = getBoolean("mobs.husk.jockey.only-babies", huskJockeyOnlyBaby);
|
|
+ huskJockeyChance = getDouble("mobs.husk.jockey.chance", huskJockeyChance);
|
|
+ huskJockeyTryExistingChickens = getBoolean("mobs.husk.jockey.try-existing-chickens", huskJockeyTryExistingChickens);
|
|
+ huskTakeDamageFromWater = getBoolean("mobs.husk.takes-damage-from-water", huskTakeDamageFromWater);
|
|
+ huskAlwaysDropExp = getBoolean("mobs.husk.always-drop-exp", huskAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean illusionerRidable = false;
|
|
+ public boolean illusionerRidableInWater = true;
|
|
+ public boolean illusionerControllable = true;
|
|
+ public double illusionerMovementSpeed = 0.5D;
|
|
+ public double illusionerFollowRange = 18.0D;
|
|
+ public double illusionerMaxHealth = 32.0D;
|
|
+ public double illusionerScale = 1.0D;
|
|
+ public boolean illusionerTakeDamageFromWater = false;
|
|
+ public boolean illusionerAlwaysDropExp = false;
|
|
+ private void illusionerSettings() {
|
|
+ illusionerRidable = getBoolean("mobs.illusioner.ridable", illusionerRidable);
|
|
+ illusionerRidableInWater = getBoolean("mobs.illusioner.ridable-in-water", illusionerRidableInWater);
|
|
+ illusionerControllable = getBoolean("mobs.illusioner.controllable", illusionerControllable);
|
|
+ illusionerMovementSpeed = getDouble("mobs.illusioner.movement-speed", illusionerMovementSpeed);
|
|
+ illusionerFollowRange = getDouble("mobs.illusioner.follow-range", illusionerFollowRange);
|
|
+ if (PurpurConfig.version < 8) {
|
|
+ double oldValue = getDouble("mobs.illusioner.max-health", illusionerMaxHealth);
|
|
+ set("mobs.illusioner.max-health", null);
|
|
+ set("mobs.illusioner.attributes.max_health", oldValue);
|
|
+ } else if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.illusioner.attributes.max-health", illusionerMaxHealth);
|
|
+ set("mobs.illusioner.attributes.max-health", null);
|
|
+ set("mobs.illusioner.attributes.max_health", oldValue);
|
|
+ }
|
|
+ illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max_health", illusionerMaxHealth);
|
|
+ illusionerScale = Mth.clamp(getDouble("mobs.illusioner.attributes.scale", illusionerScale), 0.0625D, 16.0D);
|
|
+ illusionerTakeDamageFromWater = getBoolean("mobs.illusioner.takes-damage-from-water", illusionerTakeDamageFromWater);
|
|
+ illusionerAlwaysDropExp = getBoolean("mobs.illusioner.always-drop-exp", illusionerAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean ironGolemRidable = false;
|
|
+ public boolean ironGolemRidableInWater = true;
|
|
+ public boolean ironGolemControllable = true;
|
|
+ public boolean ironGolemCanSwim = false;
|
|
+ public double ironGolemMaxHealth = 100.0D;
|
|
+ public double ironGolemScale = 1.0D;
|
|
+ public boolean ironGolemTakeDamageFromWater = false;
|
|
+ public boolean ironGolemPoppyCalm = false;
|
|
+ public boolean ironGolemHealCalm = false;
|
|
+ public boolean ironGolemAlwaysDropExp = false;
|
|
+ private void ironGolemSettings() {
|
|
+ ironGolemRidable = getBoolean("mobs.iron_golem.ridable", ironGolemRidable);
|
|
+ ironGolemRidableInWater = getBoolean("mobs.iron_golem.ridable-in-water", ironGolemRidableInWater);
|
|
+ ironGolemControllable = getBoolean("mobs.iron_golem.controllable", ironGolemControllable);
|
|
+ ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.iron_golem.attributes.max-health", ironGolemMaxHealth);
|
|
+ set("mobs.iron_golem.attributes.max-health", null);
|
|
+ set("mobs.iron_golem.attributes.max_health", oldValue);
|
|
+ }
|
|
+ ironGolemMaxHealth = getDouble("mobs.iron_golem.attributes.max_health", ironGolemMaxHealth);
|
|
+ ironGolemScale = Mth.clamp(getDouble("mobs.iron_golem.attributes.scale", ironGolemScale), 0.0625D, 16.0D);
|
|
+ ironGolemTakeDamageFromWater = getBoolean("mobs.iron_golem.takes-damage-from-water", ironGolemTakeDamageFromWater);
|
|
+ ironGolemPoppyCalm = getBoolean("mobs.iron_golem.poppy-calms-anger", ironGolemPoppyCalm);
|
|
+ ironGolemHealCalm = getBoolean("mobs.iron_golem.healing-calms-anger", ironGolemHealCalm);
|
|
+ ironGolemAlwaysDropExp = getBoolean("mobs.iron_golem.always-drop-exp", ironGolemAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean llamaRidable = false;
|
|
+ public boolean llamaRidableInWater = false;
|
|
+ public boolean llamaControllable = true;
|
|
+ public double llamaMaxHealthMin = 15.0D;
|
|
+ public double llamaMaxHealthMax = 30.0D;
|
|
+ public double llamaJumpStrengthMin = 0.5D;
|
|
+ public double llamaJumpStrengthMax = 0.5D;
|
|
+ public double llamaMovementSpeedMin = 0.175D;
|
|
+ public double llamaMovementSpeedMax = 0.175D;
|
|
+ public int llamaBreedingTicks = 6000;
|
|
+ public boolean llamaTakeDamageFromWater = false;
|
|
+ public boolean llamaJoinCaravans = true;
|
|
+ public boolean llamaAlwaysDropExp = false;
|
|
+ private void llamaSettings() {
|
|
+ llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable);
|
|
+ llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater);
|
|
+ llamaControllable = getBoolean("mobs.llama.controllable", llamaControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldMin = getDouble("mobs.llama.attributes.max-health.min", llamaMaxHealthMin);
|
|
+ double oldMax = getDouble("mobs.llama.attributes.max-health.max", llamaMaxHealthMax);
|
|
+ set("mobs.llama.attributes.max-health", null);
|
|
+ set("mobs.llama.attributes.max_health.min", oldMin);
|
|
+ set("mobs.llama.attributes.max_health.max", oldMax);
|
|
+ }
|
|
+ llamaMaxHealthMin = getDouble("mobs.llama.attributes.max_health.min", llamaMaxHealthMin);
|
|
+ llamaMaxHealthMax = getDouble("mobs.llama.attributes.max_health.max", llamaMaxHealthMax);
|
|
+ llamaJumpStrengthMin = getDouble("mobs.llama.attributes.jump_strength.min", llamaJumpStrengthMin);
|
|
+ llamaJumpStrengthMax = getDouble("mobs.llama.attributes.jump_strength.max", llamaJumpStrengthMax);
|
|
+ llamaMovementSpeedMin = getDouble("mobs.llama.attributes.movement_speed.min", llamaMovementSpeedMin);
|
|
+ llamaMovementSpeedMax = getDouble("mobs.llama.attributes.movement_speed.max", llamaMovementSpeedMax);
|
|
+ llamaBreedingTicks = getInt("mobs.llama.breeding-delay-ticks", llamaBreedingTicks);
|
|
+ llamaTakeDamageFromWater = getBoolean("mobs.llama.takes-damage-from-water", llamaTakeDamageFromWater);
|
|
+ llamaJoinCaravans = getBoolean("mobs.llama.join-caravans", llamaJoinCaravans);
|
|
+ llamaAlwaysDropExp = getBoolean("mobs.llama.always-drop-exp", llamaAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean magmaCubeRidable = false;
|
|
+ public boolean magmaCubeRidableInWater = true;
|
|
+ public boolean magmaCubeControllable = true;
|
|
+ public String magmaCubeMaxHealth = "size * size";
|
|
+ public String magmaCubeAttackDamage = "size";
|
|
+ public Map<Integer, Double> magmaCubeMaxHealthCache = new HashMap<>();
|
|
+ public Map<Integer, Double> magmaCubeAttackDamageCache = new HashMap<>();
|
|
+ public boolean magmaCubeTakeDamageFromWater = false;
|
|
+ public boolean magmaCubeAlwaysDropExp = false;
|
|
+ private void magmaCubeSettings() {
|
|
+ magmaCubeRidable = getBoolean("mobs.magma_cube.ridable", magmaCubeRidable);
|
|
+ magmaCubeRidableInWater = getBoolean("mobs.magma_cube.ridable-in-water", magmaCubeRidableInWater);
|
|
+ magmaCubeControllable = getBoolean("mobs.magma_cube.controllable", magmaCubeControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ String oldValue = getString("mobs.magma_cube.attributes.max-health", magmaCubeMaxHealth);
|
|
+ set("mobs.magma_cube.attributes.max-health", null);
|
|
+ set("mobs.magma_cube.attributes.max_health", oldValue);
|
|
+ }
|
|
+ magmaCubeMaxHealth = getString("mobs.magma_cube.attributes.max_health", magmaCubeMaxHealth);
|
|
+ magmaCubeAttackDamage = getString("mobs.magma_cube.attributes.attack_damage", magmaCubeAttackDamage);
|
|
+ magmaCubeMaxHealthCache.clear();
|
|
+ magmaCubeAttackDamageCache.clear();
|
|
+ magmaCubeTakeDamageFromWater = getBoolean("mobs.magma_cube.takes-damage-from-water", magmaCubeTakeDamageFromWater);
|
|
+ magmaCubeAlwaysDropExp = getBoolean("mobs.magma_cube.always-drop-exp", magmaCubeAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean mooshroomRidable = false;
|
|
+ public boolean mooshroomRidableInWater = true;
|
|
+ public boolean mooshroomControllable = true;
|
|
+ public double mooshroomMaxHealth = 10.0D;
|
|
+ public double mooshroomScale = 1.0D;
|
|
+ public int mooshroomBreedingTicks = 6000;
|
|
+ public boolean mooshroomTakeDamageFromWater = false;
|
|
+ public boolean mooshroomAlwaysDropExp = false;
|
|
+ private void mooshroomSettings() {
|
|
+ mooshroomRidable = getBoolean("mobs.mooshroom.ridable", mooshroomRidable);
|
|
+ mooshroomRidableInWater = getBoolean("mobs.mooshroom.ridable-in-water", mooshroomRidableInWater);
|
|
+ mooshroomControllable = getBoolean("mobs.mooshroom.controllable", mooshroomControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.mooshroom.attributes.max-health", mooshroomMaxHealth);
|
|
+ set("mobs.mooshroom.attributes.max-health", null);
|
|
+ set("mobs.mooshroom.attributes.max_health", oldValue);
|
|
+ }
|
|
+ mooshroomMaxHealth = getDouble("mobs.mooshroom.attributes.max_health", mooshroomMaxHealth);
|
|
+ mooshroomScale = Mth.clamp(getDouble("mobs.mooshroom.attributes.scale", mooshroomScale), 0.0625D, 16.0D);
|
|
+ mooshroomBreedingTicks = getInt("mobs.mooshroom.breeding-delay-ticks", mooshroomBreedingTicks);
|
|
+ mooshroomTakeDamageFromWater = getBoolean("mobs.mooshroom.takes-damage-from-water", mooshroomTakeDamageFromWater);
|
|
+ mooshroomAlwaysDropExp = getBoolean("mobs.mooshroom.always-drop-exp", mooshroomAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean muleRidableInWater = false;
|
|
+ public double muleMaxHealthMin = 15.0D;
|
|
+ public double muleMaxHealthMax = 30.0D;
|
|
+ public double muleJumpStrengthMin = 0.5D;
|
|
+ public double muleJumpStrengthMax = 0.5D;
|
|
+ public double muleMovementSpeedMin = 0.175D;
|
|
+ public double muleMovementSpeedMax = 0.175D;
|
|
+ public int muleBreedingTicks = 6000;
|
|
+ public boolean muleTakeDamageFromWater = false;
|
|
+ public boolean muleAlwaysDropExp = false;
|
|
+ private void muleSettings() {
|
|
+ muleRidableInWater = getBoolean("mobs.mule.ridable-in-water", muleRidableInWater);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldMin = getDouble("mobs.mule.attributes.max-health.min", muleMaxHealthMin);
|
|
+ double oldMax = getDouble("mobs.mule.attributes.max-health.max", muleMaxHealthMax);
|
|
+ set("mobs.mule.attributes.max-health", null);
|
|
+ set("mobs.mule.attributes.max_health.min", oldMin);
|
|
+ set("mobs.mule.attributes.max_health.max", oldMax);
|
|
+ }
|
|
+ muleMaxHealthMin = getDouble("mobs.mule.attributes.max_health.min", muleMaxHealthMin);
|
|
+ muleMaxHealthMax = getDouble("mobs.mule.attributes.max_health.max", muleMaxHealthMax);
|
|
+ muleJumpStrengthMin = getDouble("mobs.mule.attributes.jump_strength.min", muleJumpStrengthMin);
|
|
+ muleJumpStrengthMax = getDouble("mobs.mule.attributes.jump_strength.max", muleJumpStrengthMax);
|
|
+ muleMovementSpeedMin = getDouble("mobs.mule.attributes.movement_speed.min", muleMovementSpeedMin);
|
|
+ muleMovementSpeedMax = getDouble("mobs.mule.attributes.movement_speed.max", muleMovementSpeedMax);
|
|
+ muleBreedingTicks = getInt("mobs.mule.breeding-delay-ticks", muleBreedingTicks);
|
|
+ muleTakeDamageFromWater = getBoolean("mobs.mule.takes-damage-from-water", muleTakeDamageFromWater);
|
|
+ muleAlwaysDropExp = getBoolean("mobs.mule.always-drop-exp", muleAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean ocelotRidable = false;
|
|
+ public boolean ocelotRidableInWater = true;
|
|
+ public boolean ocelotControllable = true;
|
|
+ public double ocelotMaxHealth = 10.0D;
|
|
+ public double ocelotScale = 1.0D;
|
|
+ public int ocelotBreedingTicks = 6000;
|
|
+ public boolean ocelotTakeDamageFromWater = false;
|
|
+ public boolean ocelotAlwaysDropExp = false;
|
|
+ public boolean ocelotSpawnUnderSeaLevel = false;
|
|
+ private void ocelotSettings() {
|
|
+ ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable);
|
|
+ ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater);
|
|
+ ocelotControllable = getBoolean("mobs.ocelot.controllable", ocelotControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.ocelot.attributes.max-health", ocelotMaxHealth);
|
|
+ set("mobs.ocelot.attributes.max-health", null);
|
|
+ set("mobs.ocelot.attributes.max_health", oldValue);
|
|
+ }
|
|
+ ocelotMaxHealth = getDouble("mobs.ocelot.attributes.max_health", ocelotMaxHealth);
|
|
+ ocelotScale = Mth.clamp(getDouble("mobs.ocelot.attributes.scale", ocelotScale), 0.0625D, 16.0D);
|
|
+ ocelotBreedingTicks = getInt("mobs.ocelot.breeding-delay-ticks", ocelotBreedingTicks);
|
|
+ ocelotTakeDamageFromWater = getBoolean("mobs.ocelot.takes-damage-from-water", ocelotTakeDamageFromWater);
|
|
+ ocelotAlwaysDropExp = getBoolean("mobs.ocelot.always-drop-exp", ocelotAlwaysDropExp);
|
|
+ ocelotSpawnUnderSeaLevel = getBoolean("mobs.ocelot.spawn-below-sea-level", ocelotSpawnUnderSeaLevel);
|
|
+ }
|
|
+
|
|
+ public boolean pandaRidable = false;
|
|
+ public boolean pandaRidableInWater = true;
|
|
+ public boolean pandaControllable = true;
|
|
+ public double pandaMaxHealth = 20.0D;
|
|
+ public double pandaScale = 1.0D;
|
|
+ public int pandaBreedingTicks = 6000;
|
|
+ public boolean pandaTakeDamageFromWater = false;
|
|
+ public boolean pandaAlwaysDropExp = false;
|
|
+ private void pandaSettings() {
|
|
+ pandaRidable = getBoolean("mobs.panda.ridable", pandaRidable);
|
|
+ pandaRidableInWater = getBoolean("mobs.panda.ridable-in-water", pandaRidableInWater);
|
|
+ pandaControllable = getBoolean("mobs.panda.controllable", pandaControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.panda.attributes.max-health", pandaMaxHealth);
|
|
+ set("mobs.panda.attributes.max-health", null);
|
|
+ set("mobs.panda.attributes.max_health", oldValue);
|
|
+ }
|
|
+ pandaMaxHealth = getDouble("mobs.panda.attributes.max_health", pandaMaxHealth);
|
|
+ pandaScale = Mth.clamp(getDouble("mobs.panda.attributes.scale", pandaScale), 0.0625D, 16.0D);
|
|
+ pandaBreedingTicks = getInt("mobs.panda.breeding-delay-ticks", pandaBreedingTicks);
|
|
+ pandaTakeDamageFromWater = getBoolean("mobs.panda.takes-damage-from-water", pandaTakeDamageFromWater);
|
|
+ pandaAlwaysDropExp = getBoolean("mobs.panda.always-drop-exp", pandaAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean parrotRidable = false;
|
|
+ public boolean parrotRidableInWater = true;
|
|
+ public boolean parrotControllable = true;
|
|
+ public double parrotMaxY = 320D;
|
|
+ public double parrotMaxHealth = 6.0D;
|
|
+ public double parrotScale = 1.0D;
|
|
+ public boolean parrotTakeDamageFromWater = false;
|
|
+ public boolean parrotBreedable = false;
|
|
+ public boolean parrotAlwaysDropExp = false;
|
|
+ private void parrotSettings() {
|
|
+ parrotRidable = getBoolean("mobs.parrot.ridable", parrotRidable);
|
|
+ parrotRidableInWater = getBoolean("mobs.parrot.ridable-in-water", parrotRidableInWater);
|
|
+ parrotControllable = getBoolean("mobs.parrot.controllable", parrotControllable);
|
|
+ parrotMaxY = getDouble("mobs.parrot.ridable-max-y", parrotMaxY);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.parrot.attributes.max-health", parrotMaxHealth);
|
|
+ set("mobs.parrot.attributes.max-health", null);
|
|
+ set("mobs.parrot.attributes.max_health", oldValue);
|
|
+ }
|
|
+ parrotMaxHealth = getDouble("mobs.parrot.attributes.max_health", parrotMaxHealth);
|
|
+ parrotScale = Mth.clamp(getDouble("mobs.parrot.attributes.scale", parrotScale), 0.0625D, 16.0D);
|
|
+ parrotTakeDamageFromWater = getBoolean("mobs.parrot.takes-damage-from-water", parrotTakeDamageFromWater);
|
|
+ parrotBreedable = getBoolean("mobs.parrot.can-breed", parrotBreedable);
|
|
+ parrotAlwaysDropExp = getBoolean("mobs.parrot.always-drop-exp", parrotAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean phantomRidable = false;
|
|
+ public boolean phantomRidableInWater = true;
|
|
+ public boolean phantomControllable = true;
|
|
+ public double phantomMaxY = 320D;
|
|
+ public float phantomFlameDamage = 1.0F;
|
|
+ public int phantomFlameFireTime = 8;
|
|
+ public boolean phantomAllowGriefing = false;
|
|
+ public String phantomMaxHealth = "20.0";
|
|
+ public String phantomAttackDamage = "6 + size";
|
|
+ public Map<Integer, Double> phantomMaxHealthCache = new HashMap<>();
|
|
+ public Map<Integer, Double> phantomAttackDamageCache = new HashMap<>();
|
|
+ public double phantomAttackedByCrystalRadius = 0.0D;
|
|
+ public float phantomAttackedByCrystalDamage = 1.0F;
|
|
+ public double phantomOrbitCrystalRadius = 0.0D;
|
|
+ public int phantomSpawnMinSkyDarkness = 5;
|
|
+ public boolean phantomSpawnOnlyAboveSeaLevel = true;
|
|
+ public boolean phantomSpawnOnlyWithVisibleSky = true;
|
|
+ public double phantomSpawnLocalDifficultyChance = 3.0D;
|
|
+ public int phantomSpawnMinPerAttempt = 1;
|
|
+ public int phantomSpawnMaxPerAttempt = -1;
|
|
+ public int phantomBurnInLight = 0;
|
|
+ public boolean phantomIgnorePlayersWithTorch = false;
|
|
+ public boolean phantomBurnInDaylight = true;
|
|
+ public boolean phantomFlamesOnSwoop = false;
|
|
+ public boolean phantomTakeDamageFromWater = false;
|
|
+ public boolean phantomAlwaysDropExp = false;
|
|
+ public int phantomMinSize = 0;
|
|
+ public int phantomMaxSize = 0;
|
|
+ private void phantomSettings() {
|
|
+ phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable);
|
|
+ phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater);
|
|
+ phantomControllable = getBoolean("mobs.phantom.controllable", phantomControllable);
|
|
+ phantomMaxY = getDouble("mobs.phantom.ridable-max-y", phantomMaxY);
|
|
+ phantomFlameDamage = (float) getDouble("mobs.phantom.flames.damage", phantomFlameDamage);
|
|
+ phantomFlameFireTime = getInt("mobs.phantom.flames.fire-time", phantomFlameFireTime);
|
|
+ phantomAllowGriefing = getBoolean("mobs.phantom.allow-griefing", phantomAllowGriefing);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.phantom.attributes.max-health", Double.parseDouble(phantomMaxHealth));
|
|
+ set("mobs.phantom.attributes.max-health", null);
|
|
+ set("mobs.phantom.attributes.max_health", String.valueOf(oldValue));
|
|
+ }
|
|
+ if (PurpurConfig.version < 25) {
|
|
+ double oldValue = getDouble("mobs.phantom.attributes.max_health", Double.parseDouble(phantomMaxHealth));
|
|
+ set("mobs.phantom.attributes.max_health", String.valueOf(oldValue));
|
|
+ }
|
|
+ phantomMaxHealth = getString("mobs.phantom.attributes.max_health", phantomMaxHealth);
|
|
+ phantomAttackDamage = getString("mobs.phantom.attributes.attack_damage", phantomAttackDamage);
|
|
+ phantomMaxHealthCache.clear();
|
|
+ phantomAttackDamageCache.clear();
|
|
+ phantomAttackedByCrystalRadius = getDouble("mobs.phantom.attacked-by-crystal-range", phantomAttackedByCrystalRadius);
|
|
+ phantomAttackedByCrystalDamage = (float) getDouble("mobs.phantom.attacked-by-crystal-damage", phantomAttackedByCrystalDamage);
|
|
+ phantomOrbitCrystalRadius = getDouble("mobs.phantom.orbit-crystal-radius", phantomOrbitCrystalRadius);
|
|
+ phantomSpawnMinSkyDarkness = getInt("mobs.phantom.spawn.min-sky-darkness", phantomSpawnMinSkyDarkness);
|
|
+ phantomSpawnOnlyAboveSeaLevel = getBoolean("mobs.phantom.spawn.only-above-sea-level", phantomSpawnOnlyAboveSeaLevel);
|
|
+ phantomSpawnOnlyWithVisibleSky = getBoolean("mobs.phantom.spawn.only-with-visible-sky", phantomSpawnOnlyWithVisibleSky);
|
|
+ phantomSpawnLocalDifficultyChance = getDouble("mobs.phantom.spawn.local-difficulty-chance", phantomSpawnLocalDifficultyChance);
|
|
+ phantomSpawnMinPerAttempt = getInt("mobs.phantom.spawn.per-attempt.min", phantomSpawnMinPerAttempt);
|
|
+ phantomSpawnMaxPerAttempt = getInt("mobs.phantom.spawn.per-attempt.max", phantomSpawnMaxPerAttempt);
|
|
+ phantomBurnInLight = getInt("mobs.phantom.burn-in-light", phantomBurnInLight);
|
|
+ phantomBurnInDaylight = getBoolean("mobs.phantom.burn-in-daylight", phantomBurnInDaylight);
|
|
+ phantomIgnorePlayersWithTorch = getBoolean("mobs.phantom.ignore-players-with-torch", phantomIgnorePlayersWithTorch);
|
|
+ phantomFlamesOnSwoop = getBoolean("mobs.phantom.flames-on-swoop", phantomFlamesOnSwoop);
|
|
+ phantomTakeDamageFromWater = getBoolean("mobs.phantom.takes-damage-from-water", phantomTakeDamageFromWater);
|
|
+ phantomAlwaysDropExp = getBoolean("mobs.phantom.always-drop-exp", phantomAlwaysDropExp);
|
|
+ phantomMinSize = Mth.clamp(getInt("mobs.phantom.size.min", phantomMinSize), 0, 64);
|
|
+ phantomMaxSize = Mth.clamp(getInt("mobs.phantom.size.max", phantomMaxSize), 0, 64);
|
|
+ if (phantomMinSize > phantomMaxSize) {
|
|
+ phantomMinSize = phantomMinSize ^ phantomMaxSize;
|
|
+ phantomMaxSize = phantomMinSize ^ phantomMaxSize;
|
|
+ phantomMinSize = phantomMinSize ^ phantomMaxSize;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public boolean pigRidable = false;
|
|
+ public boolean pigRidableInWater = false;
|
|
+ public boolean pigControllable = true;
|
|
+ public double pigMaxHealth = 10.0D;
|
|
+ public double pigScale = 1.0D;
|
|
+ public boolean pigGiveSaddleBack = false;
|
|
+ public int pigBreedingTicks = 6000;
|
|
+ public boolean pigTakeDamageFromWater = false;
|
|
+ public boolean pigAlwaysDropExp = false;
|
|
+ private void pigSettings() {
|
|
+ pigRidable = getBoolean("mobs.pig.ridable", pigRidable);
|
|
+ pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater);
|
|
+ pigControllable = getBoolean("mobs.pig.controllable", pigControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.pig.attributes.max-health", pigMaxHealth);
|
|
+ set("mobs.pig.attributes.max-health", null);
|
|
+ set("mobs.pig.attributes.max_health", oldValue);
|
|
+ }
|
|
+ pigMaxHealth = getDouble("mobs.pig.attributes.max_health", pigMaxHealth);
|
|
+ pigScale = Mth.clamp(getDouble("mobs.pig.attributes.scale", pigScale), 0.0625D, 16.0D);
|
|
+ pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack);
|
|
+ pigBreedingTicks = getInt("mobs.pig.breeding-delay-ticks", pigBreedingTicks);
|
|
+ pigTakeDamageFromWater = getBoolean("mobs.pig.takes-damage-from-water", pigTakeDamageFromWater);
|
|
+ pigAlwaysDropExp = getBoolean("mobs.pig.always-drop-exp", pigAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean piglinRidable = false;
|
|
+ public boolean piglinRidableInWater = true;
|
|
+ public boolean piglinControllable = true;
|
|
+ public double piglinMaxHealth = 16.0D;
|
|
+ public double piglinScale = 1.0D;
|
|
+ public boolean piglinBypassMobGriefing = false;
|
|
+ public boolean piglinTakeDamageFromWater = false;
|
|
+ public int piglinPortalSpawnModifier = 2000;
|
|
+ public boolean piglinAlwaysDropExp = false;
|
|
+ public double piglinHeadVisibilityPercent = 0.5D;
|
|
+ public boolean piglinIgnoresArmorWithGoldTrim = false;
|
|
+ private void piglinSettings() {
|
|
+ piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable);
|
|
+ piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater);
|
|
+ piglinControllable = getBoolean("mobs.piglin.controllable", piglinControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.piglin.attributes.max-health", piglinMaxHealth);
|
|
+ set("mobs.piglin.attributes.max-health", null);
|
|
+ set("mobs.piglin.attributes.max_health", oldValue);
|
|
+ }
|
|
+ piglinMaxHealth = getDouble("mobs.piglin.attributes.max_health", piglinMaxHealth);
|
|
+ piglinScale = Mth.clamp(getDouble("mobs.piglin.attributes.scale", piglinScale), 0.0625D, 16.0D);
|
|
+ piglinBypassMobGriefing = getBoolean("mobs.piglin.bypass-mob-griefing", piglinBypassMobGriefing);
|
|
+ piglinTakeDamageFromWater = getBoolean("mobs.piglin.takes-damage-from-water", piglinTakeDamageFromWater);
|
|
+ piglinPortalSpawnModifier = getInt("mobs.piglin.portal-spawn-modifier", piglinPortalSpawnModifier);
|
|
+ piglinAlwaysDropExp = getBoolean("mobs.piglin.always-drop-exp", piglinAlwaysDropExp);
|
|
+ piglinHeadVisibilityPercent = getDouble("mobs.piglin.head-visibility-percent", piglinHeadVisibilityPercent);
|
|
+ piglinIgnoresArmorWithGoldTrim = getBoolean("mobs.piglin.ignores-armor-with-gold-trim", piglinIgnoresArmorWithGoldTrim);
|
|
+ }
|
|
+
|
|
+ public boolean piglinBruteRidable = false;
|
|
+ public boolean piglinBruteRidableInWater = true;
|
|
+ public boolean piglinBruteControllable = true;
|
|
+ public double piglinBruteMaxHealth = 50.0D;
|
|
+ public double piglinBruteScale = 1.0D;
|
|
+ public boolean piglinBruteTakeDamageFromWater = false;
|
|
+ public boolean piglinBruteAlwaysDropExp = false;
|
|
+ private void piglinBruteSettings() {
|
|
+ piglinBruteRidable = getBoolean("mobs.piglin_brute.ridable", piglinBruteRidable);
|
|
+ piglinBruteRidableInWater = getBoolean("mobs.piglin_brute.ridable-in-water", piglinBruteRidableInWater);
|
|
+ piglinBruteControllable = getBoolean("mobs.piglin_brute.controllable", piglinBruteControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.piglin_brute.attributes.max-health", piglinBruteMaxHealth);
|
|
+ set("mobs.piglin_brute.attributes.max-health", null);
|
|
+ set("mobs.piglin_brute.attributes.max_health", oldValue);
|
|
+ }
|
|
+ piglinBruteMaxHealth = getDouble("mobs.piglin_brute.attributes.max_health", piglinBruteMaxHealth);
|
|
+ piglinBruteScale = Mth.clamp(getDouble("mobs.piglin_brute.attributes.scale", piglinBruteScale), 0.0625D, 16.0D);
|
|
+ piglinBruteTakeDamageFromWater = getBoolean("mobs.piglin_brute.takes-damage-from-water", piglinBruteTakeDamageFromWater);
|
|
+ piglinBruteAlwaysDropExp = getBoolean("mobs.piglin_brute.always-drop-exp", piglinBruteAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean pillagerRidable = false;
|
|
+ public boolean pillagerRidableInWater = true;
|
|
+ public boolean pillagerControllable = true;
|
|
+ public double pillagerMaxHealth = 24.0D;
|
|
+ public double pillagerScale = 1.0D;
|
|
+ public boolean pillagerBypassMobGriefing = false;
|
|
+ public boolean pillagerTakeDamageFromWater = false;
|
|
+ public boolean pillagerAlwaysDropExp = false;
|
|
+ private void pillagerSettings() {
|
|
+ pillagerRidable = getBoolean("mobs.pillager.ridable", pillagerRidable);
|
|
+ pillagerRidableInWater = getBoolean("mobs.pillager.ridable-in-water", pillagerRidableInWater);
|
|
+ pillagerControllable = getBoolean("mobs.pillager.controllable", pillagerControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.pillager.attributes.max-health", pillagerMaxHealth);
|
|
+ set("mobs.pillager.attributes.max-health", null);
|
|
+ set("mobs.pillager.attributes.max_health", oldValue);
|
|
+ }
|
|
+ pillagerMaxHealth = getDouble("mobs.pillager.attributes.max_health", pillagerMaxHealth);
|
|
+ pillagerScale = Mth.clamp(getDouble("mobs.pillager.attributes.scale", pillagerScale), 0.0625D, 16.0D);
|
|
+ pillagerBypassMobGriefing = getBoolean("mobs.pillager.bypass-mob-griefing", pillagerBypassMobGriefing);
|
|
+ pillagerTakeDamageFromWater = getBoolean("mobs.pillager.takes-damage-from-water", pillagerTakeDamageFromWater);
|
|
+ pillagerAlwaysDropExp = getBoolean("mobs.pillager.always-drop-exp", pillagerAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean polarBearRidable = false;
|
|
+ public boolean polarBearRidableInWater = true;
|
|
+ public boolean polarBearControllable = true;
|
|
+ public double polarBearMaxHealth = 30.0D;
|
|
+ public double polarBearScale = 1.0D;
|
|
+ public String polarBearBreedableItemString = "";
|
|
+ public Item polarBearBreedableItem = null;
|
|
+ public int polarBearBreedingTicks = 6000;
|
|
+ public boolean polarBearTakeDamageFromWater = false;
|
|
+ public boolean polarBearAlwaysDropExp = false;
|
|
+ private void polarBearSettings() {
|
|
+ polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable);
|
|
+ polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater);
|
|
+ polarBearControllable = getBoolean("mobs.polar_bear.controllable", polarBearControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.polar_bear.attributes.max-health", polarBearMaxHealth);
|
|
+ set("mobs.polar_bear.attributes.max-health", null);
|
|
+ set("mobs.polar_bear.attributes.max_health", oldValue);
|
|
+ }
|
|
+ polarBearMaxHealth = getDouble("mobs.polar_bear.attributes.max_health", polarBearMaxHealth);
|
|
+ polarBearScale = Mth.clamp(getDouble("mobs.polar_bear.attributes.scale", polarBearScale), 0.0625D, 16.0D);
|
|
+ polarBearBreedableItemString = getString("mobs.polar_bear.breedable-item", polarBearBreedableItemString);
|
|
+ Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(polarBearBreedableItemString));
|
|
+ if (item != Items.AIR) polarBearBreedableItem = item;
|
|
+ polarBearBreedingTicks = getInt("mobs.polar_bear.breeding-delay-ticks", polarBearBreedingTicks);
|
|
+ polarBearTakeDamageFromWater = getBoolean("mobs.polar_bear.takes-damage-from-water", polarBearTakeDamageFromWater);
|
|
+ polarBearAlwaysDropExp = getBoolean("mobs.polar_bear.always-drop-exp", polarBearAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean pufferfishRidable = false;
|
|
+ public boolean pufferfishControllable = true;
|
|
+ public double pufferfishMaxHealth = 3.0D;
|
|
+ public double pufferfishScale = 1.0D;
|
|
+ public boolean pufferfishTakeDamageFromWater = false;
|
|
+ public boolean pufferfishAlwaysDropExp = false;
|
|
+ private void pufferfishSettings() {
|
|
+ pufferfishRidable = getBoolean("mobs.pufferfish.ridable", pufferfishRidable);
|
|
+ pufferfishControllable = getBoolean("mobs.pufferfish.controllable", pufferfishControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.pufferfish.attributes.max-health", pufferfishMaxHealth);
|
|
+ set("mobs.pufferfish.attributes.max-health", null);
|
|
+ set("mobs.pufferfish.attributes.max_health", oldValue);
|
|
+ }
|
|
+ pufferfishMaxHealth = getDouble("mobs.pufferfish.attributes.max_health", pufferfishMaxHealth);
|
|
+ pufferfishScale = Mth.clamp(getDouble("mobs.pufferfish.attributes.scale", pufferfishScale), 0.0625D, 16.0D);
|
|
+ pufferfishTakeDamageFromWater = getBoolean("mobs.pufferfish.takes-damage-from-water", pufferfishTakeDamageFromWater);
|
|
+ pufferfishAlwaysDropExp = getBoolean("mobs.pufferfish.always-drop-exp", pufferfishAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean rabbitRidable = false;
|
|
+ public boolean rabbitRidableInWater = true;
|
|
+ public boolean rabbitControllable = true;
|
|
+ public double rabbitMaxHealth = 3.0D;
|
|
+ public double rabbitScale = 1.0D;
|
|
+ public double rabbitNaturalToast = 0.0D;
|
|
+ public double rabbitNaturalKiller = 0.0D;
|
|
+ public int rabbitBreedingTicks = 6000;
|
|
+ public boolean rabbitBypassMobGriefing = false;
|
|
+ public boolean rabbitTakeDamageFromWater = false;
|
|
+ public boolean rabbitAlwaysDropExp = false;
|
|
+ private void rabbitSettings() {
|
|
+ rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable);
|
|
+ rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater);
|
|
+ rabbitControllable = getBoolean("mobs.rabbit.controllable", rabbitControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.rabbit.attributes.max-health", rabbitMaxHealth);
|
|
+ set("mobs.rabbit.attributes.max-health", null);
|
|
+ set("mobs.rabbit.attributes.max_health", oldValue);
|
|
+ }
|
|
+ rabbitMaxHealth = getDouble("mobs.rabbit.attributes.max_health", rabbitMaxHealth);
|
|
+ rabbitScale = Mth.clamp(getDouble("mobs.rabbit.attributes.scale", rabbitScale), 0.0625D, 16.0D);
|
|
+ rabbitNaturalToast = getDouble("mobs.rabbit.spawn-toast-chance", rabbitNaturalToast);
|
|
+ rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller);
|
|
+ rabbitBreedingTicks = getInt("mobs.rabbit.breeding-delay-ticks", rabbitBreedingTicks);
|
|
+ rabbitBypassMobGriefing = getBoolean("mobs.rabbit.bypass-mob-griefing", rabbitBypassMobGriefing);
|
|
+ rabbitTakeDamageFromWater = getBoolean("mobs.rabbit.takes-damage-from-water", rabbitTakeDamageFromWater);
|
|
+ rabbitAlwaysDropExp = getBoolean("mobs.rabbit.always-drop-exp", rabbitAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean ravagerRidable = false;
|
|
+ public boolean ravagerRidableInWater = false;
|
|
+ public boolean ravagerControllable = true;
|
|
+ public double ravagerMaxHealth = 100.0D;
|
|
+ public double ravagerScale = 1.0D;
|
|
+ public boolean ravagerBypassMobGriefing = false;
|
|
+ public boolean ravagerTakeDamageFromWater = false;
|
|
+ public List<Block> ravagerGriefableBlocks = new ArrayList<>();
|
|
+ public boolean ravagerAlwaysDropExp = false;
|
|
+ public boolean ravagerAvoidRabbits = false;
|
|
+ private void ravagerSettings() {
|
|
+ ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable);
|
|
+ ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater);
|
|
+ ravagerControllable = getBoolean("mobs.ravager.controllable", ravagerControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.ravager.attributes.max-health", ravagerMaxHealth);
|
|
+ set("mobs.ravager.attributes.max-health", null);
|
|
+ set("mobs.ravager.attributes.max_health", oldValue);
|
|
+ }
|
|
+ ravagerMaxHealth = getDouble("mobs.ravager.attributes.max_health", ravagerMaxHealth);
|
|
+ ravagerScale = Mth.clamp(getDouble("mobs.ravager.attributes.scale", ravagerScale), 0.0625D, 16.0D);
|
|
+ ravagerBypassMobGriefing = getBoolean("mobs.ravager.bypass-mob-griefing", ravagerBypassMobGriefing);
|
|
+ ravagerTakeDamageFromWater = getBoolean("mobs.ravager.takes-damage-from-water", ravagerTakeDamageFromWater);
|
|
+ getList("mobs.ravager.griefable-blocks", new ArrayList<String>(){{
|
|
+ add("minecraft:oak_leaves");
|
|
+ add("minecraft:spruce_leaves");
|
|
+ add("minecraft:birch_leaves");
|
|
+ add("minecraft:jungle_leaves");
|
|
+ add("minecraft:acacia_leaves");
|
|
+ add("minecraft:dark_oak_leaves");
|
|
+ add("minecraft:beetroots");
|
|
+ add("minecraft:carrots");
|
|
+ add("minecraft:potatoes");
|
|
+ add("minecraft:wheat");
|
|
+ }}).forEach(key -> {
|
|
+ Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(key.toString()));
|
|
+ if (!block.defaultBlockState().isAir()) {
|
|
+ ravagerGriefableBlocks.add(block);
|
|
+ }
|
|
+ });
|
|
+ ravagerAlwaysDropExp = getBoolean("mobs.ravager.always-drop-exp", ravagerAlwaysDropExp);
|
|
+ ravagerAvoidRabbits = getBoolean("mobs.ravager.avoid-rabbits", ravagerAvoidRabbits);
|
|
+ }
|
|
+
|
|
+ public boolean salmonRidable = false;
|
|
+ public boolean salmonControllable = true;
|
|
+ public double salmonMaxHealth = 3.0D;
|
|
+ public double salmonScale = 1.0D;
|
|
+ public boolean salmonTakeDamageFromWater = false;
|
|
+ public boolean salmonAlwaysDropExp = false;
|
|
+ private void salmonSettings() {
|
|
+ salmonRidable = getBoolean("mobs.salmon.ridable", salmonRidable);
|
|
+ salmonControllable = getBoolean("mobs.salmon.controllable", salmonControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.salmon.attributes.max-health", salmonMaxHealth);
|
|
+ set("mobs.salmon.attributes.max-health", null);
|
|
+ set("mobs.salmon.attributes.max_health", oldValue);
|
|
+ }
|
|
+ salmonMaxHealth = getDouble("mobs.salmon.attributes.max_health", salmonMaxHealth);
|
|
+ salmonScale = Mth.clamp(getDouble("mobs.salmon.attributes.scale", salmonScale), 0.0625D, 16.0D);
|
|
+ salmonTakeDamageFromWater = getBoolean("mobs.salmon.takes-damage-from-water", salmonTakeDamageFromWater);
|
|
+ salmonAlwaysDropExp = getBoolean("mobs.salmon.always-drop-exp", salmonAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean sheepRidable = false;
|
|
+ public boolean sheepRidableInWater = true;
|
|
+ public boolean sheepControllable = true;
|
|
+ public double sheepMaxHealth = 8.0D;
|
|
+ public double sheepScale = 1.0D;
|
|
+ public int sheepBreedingTicks = 6000;
|
|
+ public boolean sheepBypassMobGriefing = false;
|
|
+ public boolean sheepTakeDamageFromWater = false;
|
|
+ public boolean sheepAlwaysDropExp = false;
|
|
+ private void sheepSettings() {
|
|
+ sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable);
|
|
+ sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater);
|
|
+ sheepControllable = getBoolean("mobs.sheep.controllable", sheepControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.sheep.attributes.max-health", sheepMaxHealth);
|
|
+ set("mobs.sheep.attributes.max-health", null);
|
|
+ set("mobs.sheep.attributes.max_health", oldValue);
|
|
+ }
|
|
+ sheepMaxHealth = getDouble("mobs.sheep.attributes.max_health", sheepMaxHealth);
|
|
+ sheepScale = Mth.clamp(getDouble("mobs.sheep.attributes.scale", sheepScale), 0.0625D, 16.0D);
|
|
+ sheepBreedingTicks = getInt("mobs.sheep.breeding-delay-ticks", sheepBreedingTicks);
|
|
+ sheepBypassMobGriefing = getBoolean("mobs.sheep.bypass-mob-griefing", sheepBypassMobGriefing);
|
|
+ sheepTakeDamageFromWater = getBoolean("mobs.sheep.takes-damage-from-water", sheepTakeDamageFromWater);
|
|
+ sheepAlwaysDropExp = getBoolean("mobs.sheep.always-drop-exp", sheepAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean shulkerRidable = false;
|
|
+ public boolean shulkerRidableInWater = true;
|
|
+ public boolean shulkerControllable = true;
|
|
+ public double shulkerMaxHealth = 30.0D;
|
|
+ public double shulkerScale = 1.0D;
|
|
+ public boolean shulkerTakeDamageFromWater = false;
|
|
+ public float shulkerSpawnFromBulletBaseChance = 1.0F;
|
|
+ public boolean shulkerSpawnFromBulletRequireOpenLid = true;
|
|
+ public double shulkerSpawnFromBulletNearbyRange = 8.0D;
|
|
+ public String shulkerSpawnFromBulletNearbyEquation = "(nearby - 1) / 5.0";
|
|
+ public boolean shulkerSpawnFromBulletRandomColor = false;
|
|
+ public boolean shulkerChangeColorWithDye = false;
|
|
+ public boolean shulkerAlwaysDropExp = false;
|
|
+ private void shulkerSettings() {
|
|
+ shulkerRidable = getBoolean("mobs.shulker.ridable", shulkerRidable);
|
|
+ shulkerRidableInWater = getBoolean("mobs.shulker.ridable-in-water", shulkerRidableInWater);
|
|
+ shulkerControllable = getBoolean("mobs.shulker.controllable", shulkerControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.shulker.attributes.max-health", shulkerMaxHealth);
|
|
+ set("mobs.shulker.attributes.max-health", null);
|
|
+ set("mobs.shulker.attributes.max_health", oldValue);
|
|
+ }
|
|
+ shulkerMaxHealth = getDouble("mobs.shulker.attributes.max_health", shulkerMaxHealth);
|
|
+ shulkerScale = Mth.clamp(getDouble("mobs.shulker.attributes.scale", shulkerScale), 0.0625D, Shulker.MAX_SCALE);
|
|
+ shulkerTakeDamageFromWater = getBoolean("mobs.shulker.takes-damage-from-water", shulkerTakeDamageFromWater);
|
|
+ shulkerSpawnFromBulletBaseChance = (float) getDouble("mobs.shulker.spawn-from-bullet.base-chance", shulkerSpawnFromBulletBaseChance);
|
|
+ shulkerSpawnFromBulletRequireOpenLid = getBoolean("mobs.shulker.spawn-from-bullet.require-open-lid", shulkerSpawnFromBulletRequireOpenLid);
|
|
+ shulkerSpawnFromBulletNearbyRange = getDouble("mobs.shulker.spawn-from-bullet.nearby-range", shulkerSpawnFromBulletNearbyRange);
|
|
+ shulkerSpawnFromBulletNearbyEquation = getString("mobs.shulker.spawn-from-bullet.nearby-equation", shulkerSpawnFromBulletNearbyEquation);
|
|
+ shulkerSpawnFromBulletRandomColor = getBoolean("mobs.shulker.spawn-from-bullet.random-color", shulkerSpawnFromBulletRandomColor);
|
|
+ shulkerChangeColorWithDye = getBoolean("mobs.shulker.change-color-with-dye", shulkerChangeColorWithDye);
|
|
+ shulkerAlwaysDropExp = getBoolean("mobs.shulker.always-drop-exp", shulkerAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean silverfishRidable = false;
|
|
+ public boolean silverfishRidableInWater = true;
|
|
+ public boolean silverfishControllable = true;
|
|
+ public double silverfishMaxHealth = 8.0D;
|
|
+ public double silverfishScale = 1.0D;
|
|
+ public double silverfishMovementSpeed = 0.25D;
|
|
+ public double silverfishAttackDamage = 1.0D;
|
|
+ public boolean silverfishBypassMobGriefing = false;
|
|
+ public boolean silverfishTakeDamageFromWater = false;
|
|
+ public boolean silverfishAlwaysDropExp = false;
|
|
+ private void silverfishSettings() {
|
|
+ silverfishRidable = getBoolean("mobs.silverfish.ridable", silverfishRidable);
|
|
+ silverfishRidableInWater = getBoolean("mobs.silverfish.ridable-in-water", silverfishRidableInWater);
|
|
+ silverfishControllable = getBoolean("mobs.silverfish.controllable", silverfishControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.silverfish.attributes.max-health", silverfishMaxHealth);
|
|
+ set("mobs.silverfish.attributes.max-health", null);
|
|
+ set("mobs.silverfish.attributes.max_health", oldValue);
|
|
+ }
|
|
+ silverfishMaxHealth = getDouble("mobs.silverfish.attributes.max_health", silverfishMaxHealth);
|
|
+ silverfishScale = Mth.clamp(getDouble("mobs.silverfish.attributes.scale", silverfishScale), 0.0625D, 16.0D);
|
|
+ silverfishMovementSpeed = getDouble("mobs.silverfish.attributes.movement_speed", silverfishMovementSpeed);
|
|
+ silverfishAttackDamage = getDouble("mobs.silverfish.attributes.attack_damage", silverfishAttackDamage);
|
|
+ silverfishBypassMobGriefing = getBoolean("mobs.silverfish.bypass-mob-griefing", silverfishBypassMobGriefing);
|
|
+ silverfishTakeDamageFromWater = getBoolean("mobs.silverfish.takes-damage-from-water", silverfishTakeDamageFromWater);
|
|
+ silverfishAlwaysDropExp = getBoolean("mobs.silverfish.always-drop-exp", silverfishAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean skeletonRidable = false;
|
|
+ public boolean skeletonRidableInWater = true;
|
|
+ public boolean skeletonControllable = true;
|
|
+ public double skeletonMaxHealth = 20.0D;
|
|
+ public double skeletonScale = 1.0D;
|
|
+ public boolean skeletonTakeDamageFromWater = false;
|
|
+ public boolean skeletonAlwaysDropExp = false;
|
|
+ public double skeletonHeadVisibilityPercent = 0.5D;
|
|
+ public int skeletonFeedWitherRoses = 0;
|
|
+ public String skeletonBowAccuracy = "14 - difficulty * 4";
|
|
+ public Map<Integer, Float> skeletonBowAccuracyMap = new HashMap<>();
|
|
+ private void skeletonSettings() {
|
|
+ skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable);
|
|
+ skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater);
|
|
+ skeletonControllable = getBoolean("mobs.skeleton.controllable", skeletonControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.skeleton.attributes.max-health", skeletonMaxHealth);
|
|
+ set("mobs.skeleton.attributes.max-health", null);
|
|
+ set("mobs.skeleton.attributes.max_health", oldValue);
|
|
+ }
|
|
+ skeletonMaxHealth = getDouble("mobs.skeleton.attributes.max_health", skeletonMaxHealth);
|
|
+ skeletonScale = Mth.clamp(getDouble("mobs.skeleton.attributes.scale", skeletonScale), 0.0625D, 16.0D);
|
|
+ skeletonTakeDamageFromWater = getBoolean("mobs.skeleton.takes-damage-from-water", skeletonTakeDamageFromWater);
|
|
+ skeletonAlwaysDropExp = getBoolean("mobs.skeleton.always-drop-exp", skeletonAlwaysDropExp);
|
|
+ skeletonHeadVisibilityPercent = getDouble("mobs.skeleton.head-visibility-percent", skeletonHeadVisibilityPercent);
|
|
+ skeletonFeedWitherRoses = getInt("mobs.skeleton.feed-wither-roses", skeletonFeedWitherRoses);
|
|
+ final String defaultSkeletonBowAccuracy = skeletonBowAccuracy;
|
|
+ skeletonBowAccuracy = getString("mobs.skeleton.bow-accuracy", skeletonBowAccuracy);
|
|
+ for (int i = 1; i < 4; i++) {
|
|
+ final float divergence;
|
|
+ try {
|
|
+ divergence = ((Number) Entity.scriptEngine.eval("let difficulty = " + i + "; " + skeletonBowAccuracy)).floatValue();
|
|
+ } catch (javax.script.ScriptException e) {
|
|
+ e.printStackTrace();
|
|
+ break;
|
|
+ }
|
|
+ skeletonBowAccuracyMap.put(i, divergence);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public boolean skeletonHorseRidable = false;
|
|
+ public boolean skeletonHorseRidableInWater = true;
|
|
+ public boolean skeletonHorseCanSwim = false;
|
|
+ public double skeletonHorseMaxHealthMin = 15.0D;
|
|
+ public double skeletonHorseMaxHealthMax = 15.0D;
|
|
+ public double skeletonHorseJumpStrengthMin = 0.4D;
|
|
+ public double skeletonHorseJumpStrengthMax = 1.0D;
|
|
+ public double skeletonHorseMovementSpeedMin = 0.2D;
|
|
+ public double skeletonHorseMovementSpeedMax = 0.2D;
|
|
+ public boolean skeletonHorseTakeDamageFromWater = false;
|
|
+ public boolean skeletonHorseAlwaysDropExp = false;
|
|
+ private void skeletonHorseSettings() {
|
|
+ skeletonHorseRidable = getBoolean("mobs.skeleton_horse.ridable", skeletonHorseRidable);
|
|
+ skeletonHorseRidableInWater = getBoolean("mobs.skeleton_horse.ridable-in-water", skeletonHorseRidableInWater);
|
|
+ skeletonHorseCanSwim = getBoolean("mobs.skeleton_horse.can-swim", skeletonHorseCanSwim);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.skeleton_horse.attributes.max-health", skeletonHorseMaxHealthMin);
|
|
+ set("mobs.skeleton_horse.attributes.max-health", null);
|
|
+ set("mobs.skeleton_horse.attributes.max_health.min", oldValue);
|
|
+ set("mobs.skeleton_horse.attributes.max_health.max", oldValue);
|
|
+ }
|
|
+ skeletonHorseMaxHealthMin = getDouble("mobs.skeleton_horse.attributes.max_health.min", skeletonHorseMaxHealthMin);
|
|
+ skeletonHorseMaxHealthMax = getDouble("mobs.skeleton_horse.attributes.max_health.max", skeletonHorseMaxHealthMax);
|
|
+ skeletonHorseJumpStrengthMin = getDouble("mobs.skeleton_horse.attributes.jump_strength.min", skeletonHorseJumpStrengthMin);
|
|
+ skeletonHorseJumpStrengthMax = getDouble("mobs.skeleton_horse.attributes.jump_strength.max", skeletonHorseJumpStrengthMax);
|
|
+ skeletonHorseMovementSpeedMin = getDouble("mobs.skeleton_horse.attributes.movement_speed.min", skeletonHorseMovementSpeedMin);
|
|
+ skeletonHorseMovementSpeedMax = getDouble("mobs.skeleton_horse.attributes.movement_speed.max", skeletonHorseMovementSpeedMax);
|
|
+ skeletonHorseTakeDamageFromWater = getBoolean("mobs.skeleton_horse.takes-damage-from-water", skeletonHorseTakeDamageFromWater);
|
|
+ skeletonHorseAlwaysDropExp = getBoolean("mobs.skeleton_horse.always-drop-exp", skeletonHorseAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean slimeRidable = false;
|
|
+ public boolean slimeRidableInWater = true;
|
|
+ public boolean slimeControllable = true;
|
|
+ public String slimeMaxHealth = "size * size";
|
|
+ public String slimeAttackDamage = "size";
|
|
+ public Map<Integer, Double> slimeMaxHealthCache = new HashMap<>();
|
|
+ public Map<Integer, Double> slimeAttackDamageCache = new HashMap<>();
|
|
+ public boolean slimeTakeDamageFromWater = false;
|
|
+ public boolean slimeAlwaysDropExp = false;
|
|
+ private void slimeSettings() {
|
|
+ slimeRidable = getBoolean("mobs.slime.ridable", slimeRidable);
|
|
+ slimeRidableInWater = getBoolean("mobs.slime.ridable-in-water", slimeRidableInWater);
|
|
+ slimeControllable = getBoolean("mobs.slime.controllable", slimeControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ String oldValue = getString("mobs.slime.attributes.max-health", slimeMaxHealth);
|
|
+ set("mobs.slime.attributes.max-health", null);
|
|
+ set("mobs.slime.attributes.max_health", oldValue);
|
|
+ }
|
|
+ slimeMaxHealth = getString("mobs.slime.attributes.max_health", slimeMaxHealth);
|
|
+ slimeAttackDamage = getString("mobs.slime.attributes.attack_damage", slimeAttackDamage);
|
|
+ slimeMaxHealthCache.clear();
|
|
+ slimeAttackDamageCache.clear();
|
|
+ slimeTakeDamageFromWater = getBoolean("mobs.slime.takes-damage-from-water", slimeTakeDamageFromWater);
|
|
+ slimeAlwaysDropExp = getBoolean("mobs.slime.always-drop-exp", slimeAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean snowGolemRidable = false;
|
|
+ public boolean snowGolemRidableInWater = true;
|
|
+ public boolean snowGolemControllable = true;
|
|
+ public boolean snowGolemLeaveTrailWhenRidden = false;
|
|
+ public double snowGolemMaxHealth = 4.0D;
|
|
+ public double snowGolemScale = 1.0D;
|
|
+ public boolean snowGolemPutPumpkinBack = false;
|
|
+ public int snowGolemSnowBallMin = 20;
|
|
+ public int snowGolemSnowBallMax = 20;
|
|
+ public float snowGolemSnowBallModifier = 10.0F;
|
|
+ public double snowGolemAttackDistance = 1.25D;
|
|
+ public boolean snowGolemBypassMobGriefing = false;
|
|
+ public boolean snowGolemTakeDamageFromWater = true;
|
|
+ public boolean snowGolemAlwaysDropExp = false;
|
|
+ private void snowGolemSettings() {
|
|
+ snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable);
|
|
+ snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater);
|
|
+ snowGolemControllable = getBoolean("mobs.snow_golem.controllable", snowGolemControllable);
|
|
+ snowGolemLeaveTrailWhenRidden = getBoolean("mobs.snow_golem.leave-trail-when-ridden", snowGolemLeaveTrailWhenRidden);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.snow_golem.attributes.max-health", snowGolemMaxHealth);
|
|
+ set("mobs.snow_golem.attributes.max-health", null);
|
|
+ set("mobs.snow_golem.attributes.max_health", oldValue);
|
|
+ }
|
|
+ snowGolemMaxHealth = getDouble("mobs.snow_golem.attributes.max_health", snowGolemMaxHealth);
|
|
+ snowGolemScale = Mth.clamp(getDouble("mobs.snow_golem.attributes.scale", snowGolemScale), 0.0625D, 16.0D);
|
|
+ snowGolemPutPumpkinBack = getBoolean("mobs.snow_golem.pumpkin-can-be-added-back", snowGolemPutPumpkinBack);
|
|
+ snowGolemSnowBallMin = getInt("mobs.snow_golem.min-shoot-interval-ticks", snowGolemSnowBallMin);
|
|
+ snowGolemSnowBallMax = getInt("mobs.snow_golem.max-shoot-interval-ticks", snowGolemSnowBallMax);
|
|
+ snowGolemSnowBallModifier = (float) getDouble("mobs.snow_golem.snow-ball-modifier", snowGolemSnowBallModifier);
|
|
+ snowGolemAttackDistance = getDouble("mobs.snow_golem.attack-distance", snowGolemAttackDistance);
|
|
+ snowGolemBypassMobGriefing = getBoolean("mobs.snow_golem.bypass-mob-griefing", snowGolemBypassMobGriefing);
|
|
+ snowGolemTakeDamageFromWater = getBoolean("mobs.snow_golem.takes-damage-from-water", snowGolemTakeDamageFromWater);
|
|
+ snowGolemAlwaysDropExp = getBoolean("mobs.snow_golem.always-drop-exp", snowGolemAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean snifferRidable = false;
|
|
+ public boolean snifferRidableInWater = true;
|
|
+ public boolean snifferControllable = true;
|
|
+ public double snifferMaxHealth = 14.0D;
|
|
+ public double snifferScale = 1.0D;
|
|
+ public int snifferBreedingTicks = 6000;
|
|
+ private void snifferSettings() {
|
|
+ snifferRidable = getBoolean("mobs.sniffer.ridable", snifferRidable);
|
|
+ snifferRidableInWater = getBoolean("mobs.sniffer.ridable-in-water", snifferRidableInWater);
|
|
+ snifferControllable = getBoolean("mobs.sniffer.controllable", snifferControllable);
|
|
+ snifferMaxHealth = getDouble("mobs.sniffer.attributes.max_health", snifferMaxHealth);
|
|
+ snifferScale = Mth.clamp(getDouble("mobs.sniffer.attributes.scale", snifferScale), 0.0625D, 16.0D);
|
|
+ snifferBreedingTicks = getInt("mobs.sniffer.breeding-delay-ticks", snifferBreedingTicks);
|
|
+ }
|
|
+
|
|
+ public boolean squidRidable = false;
|
|
+ public boolean squidControllable = true;
|
|
+ public double squidMaxHealth = 10.0D;
|
|
+ public double squidScale = 1.0D;
|
|
+ public boolean squidImmuneToEAR = true;
|
|
+ public double squidOffsetWaterCheck = 0.0D;
|
|
+ public boolean squidsCanFly = false;
|
|
+ public boolean squidTakeDamageFromWater = false;
|
|
+ public boolean squidAlwaysDropExp = false;
|
|
+ private void squidSettings() {
|
|
+ squidRidable = getBoolean("mobs.squid.ridable", squidRidable);
|
|
+ squidControllable = getBoolean("mobs.squid.controllable", squidControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.squid.attributes.max-health", squidMaxHealth);
|
|
+ set("mobs.squid.attributes.max-health", null);
|
|
+ set("mobs.squid.attributes.max_health", oldValue);
|
|
+ }
|
|
+ squidMaxHealth = getDouble("mobs.squid.attributes.max_health", squidMaxHealth);
|
|
+ squidScale = Mth.clamp(getDouble("mobs.squid.attributes.scale", squidScale), 0.0625D, 16.0D);
|
|
+ squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR);
|
|
+ squidOffsetWaterCheck = getDouble("mobs.squid.water-offset-check", squidOffsetWaterCheck);
|
|
+ squidsCanFly = getBoolean("mobs.squid.can-fly", squidsCanFly);
|
|
+ squidTakeDamageFromWater = getBoolean("mobs.squid.takes-damage-from-water", squidTakeDamageFromWater);
|
|
+ squidAlwaysDropExp = getBoolean("mobs.squid.always-drop-exp", squidAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean spiderRidable = false;
|
|
+ public boolean spiderRidableInWater = false;
|
|
+ public boolean spiderControllable = true;
|
|
+ public double spiderMaxHealth = 16.0D;
|
|
+ public double spiderScale = 1.0D;
|
|
+ public boolean spiderTakeDamageFromWater = false;
|
|
+ public boolean spiderAlwaysDropExp = false;
|
|
+ private void spiderSettings() {
|
|
+ spiderRidable = getBoolean("mobs.spider.ridable", spiderRidable);
|
|
+ spiderRidableInWater = getBoolean("mobs.spider.ridable-in-water", spiderRidableInWater);
|
|
+ spiderControllable = getBoolean("mobs.spider.controllable", spiderControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.spider.attributes.max-health", spiderMaxHealth);
|
|
+ set("mobs.spider.attributes.max-health", null);
|
|
+ set("mobs.spider.attributes.max_health", oldValue);
|
|
+ }
|
|
+ spiderMaxHealth = getDouble("mobs.spider.attributes.max_health", spiderMaxHealth);
|
|
+ spiderScale = Mth.clamp(getDouble("mobs.spider.attributes.scale", spiderScale), 0.0625D, 16.0D);
|
|
+ spiderTakeDamageFromWater = getBoolean("mobs.spider.takes-damage-from-water", spiderTakeDamageFromWater);
|
|
+ spiderAlwaysDropExp = getBoolean("mobs.spider.always-drop-exp", spiderAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean strayRidable = false;
|
|
+ public boolean strayRidableInWater = true;
|
|
+ public boolean strayControllable = true;
|
|
+ public double strayMaxHealth = 20.0D;
|
|
+ public double strayScale = 1.0D;
|
|
+ public boolean strayTakeDamageFromWater = false;
|
|
+ public boolean strayAlwaysDropExp = false;
|
|
+ private void straySettings() {
|
|
+ strayRidable = getBoolean("mobs.stray.ridable", strayRidable);
|
|
+ strayRidableInWater = getBoolean("mobs.stray.ridable-in-water", strayRidableInWater);
|
|
+ strayControllable = getBoolean("mobs.stray.controllable", strayControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.stray.attributes.max-health", strayMaxHealth);
|
|
+ set("mobs.stray.attributes.max-health", null);
|
|
+ set("mobs.stray.attributes.max_health", oldValue);
|
|
+ }
|
|
+ strayMaxHealth = getDouble("mobs.stray.attributes.max_health", strayMaxHealth);
|
|
+ strayScale = Mth.clamp(getDouble("mobs.stray.attributes.scale", strayScale), 0.0625D, 16.0D);
|
|
+ strayTakeDamageFromWater = getBoolean("mobs.stray.takes-damage-from-water", strayTakeDamageFromWater);
|
|
+ strayAlwaysDropExp = getBoolean("mobs.stray.always-drop-exp", strayAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean striderRidable = false;
|
|
+ public boolean striderRidableInWater = false;
|
|
+ public boolean striderControllable = true;
|
|
+ public double striderMaxHealth = 20.0D;
|
|
+ public double striderScale = 1.0D;
|
|
+ public int striderBreedingTicks = 6000;
|
|
+ public boolean striderGiveSaddleBack = false;
|
|
+ public boolean striderTakeDamageFromWater = true;
|
|
+ public boolean striderAlwaysDropExp = false;
|
|
+ private void striderSettings() {
|
|
+ striderRidable = getBoolean("mobs.strider.ridable", striderRidable);
|
|
+ striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater);
|
|
+ striderControllable = getBoolean("mobs.strider.controllable", striderControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.strider.attributes.max-health", striderMaxHealth);
|
|
+ set("mobs.strider.attributes.max-health", null);
|
|
+ set("mobs.strider.attributes.max_health", oldValue);
|
|
+ }
|
|
+ striderMaxHealth = getDouble("mobs.strider.attributes.max_health", striderMaxHealth);
|
|
+ striderScale = Mth.clamp(getDouble("mobs.strider.attributes.scale", striderScale), 0.0625D, 16.0D);
|
|
+ striderBreedingTicks = getInt("mobs.strider.breeding-delay-ticks", striderBreedingTicks);
|
|
+ striderGiveSaddleBack = getBoolean("mobs.strider.give-saddle-back", striderGiveSaddleBack);
|
|
+ striderTakeDamageFromWater = getBoolean("mobs.strider.takes-damage-from-water", striderTakeDamageFromWater);
|
|
+ striderAlwaysDropExp = getBoolean("mobs.strider.always-drop-exp", striderAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean tadpoleRidable = false;
|
|
+ public boolean tadpoleRidableInWater = true;
|
|
+ public boolean tadpoleControllable = true;
|
|
+ private void tadpoleSettings() {
|
|
+ tadpoleRidable = getBoolean("mobs.tadpole.ridable", tadpoleRidable);
|
|
+ tadpoleRidableInWater = getBoolean("mobs.tadpole.ridable-in-water", tadpoleRidableInWater);
|
|
+ tadpoleControllable = getBoolean("mobs.tadpole.controllable", tadpoleControllable);
|
|
+ }
|
|
+
|
|
+ public boolean traderLlamaRidable = false;
|
|
+ public boolean traderLlamaRidableInWater = false;
|
|
+ public boolean traderLlamaControllable = true;
|
|
+ public double traderLlamaMaxHealthMin = 15.0D;
|
|
+ public double traderLlamaMaxHealthMax = 30.0D;
|
|
+ public double traderLlamaJumpStrengthMin = 0.5D;
|
|
+ public double traderLlamaJumpStrengthMax = 0.5D;
|
|
+ public double traderLlamaMovementSpeedMin = 0.175D;
|
|
+ public double traderLlamaMovementSpeedMax = 0.175D;
|
|
+ public int traderLlamaBreedingTicks = 6000;
|
|
+ public boolean traderLlamaTakeDamageFromWater = false;
|
|
+ public boolean traderLlamaAlwaysDropExp = false;
|
|
+ private void traderLlamaSettings() {
|
|
+ traderLlamaRidable = getBoolean("mobs.trader_llama.ridable", traderLlamaRidable);
|
|
+ traderLlamaRidableInWater = getBoolean("mobs.trader_llama.ridable-in-water", traderLlamaRidableInWater);
|
|
+ traderLlamaControllable = getBoolean("mobs.trader_llama.controllable", traderLlamaControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldMin = getDouble("mobs.trader_llama.attributes.max-health.min", traderLlamaMaxHealthMin);
|
|
+ double oldMax = getDouble("mobs.trader_llama.attributes.max-health.max", traderLlamaMaxHealthMax);
|
|
+ set("mobs.trader_llama.attributes.max-health", null);
|
|
+ set("mobs.trader_llama.attributes.max_health.min", oldMin);
|
|
+ set("mobs.trader_llama.attributes.max_health.max", oldMax);
|
|
+ }
|
|
+ traderLlamaMaxHealthMin = getDouble("mobs.trader_llama.attributes.max_health.min", traderLlamaMaxHealthMin);
|
|
+ traderLlamaMaxHealthMax = getDouble("mobs.trader_llama.attributes.max_health.max", traderLlamaMaxHealthMax);
|
|
+ traderLlamaJumpStrengthMin = getDouble("mobs.trader_llama.attributes.jump_strength.min", traderLlamaJumpStrengthMin);
|
|
+ traderLlamaJumpStrengthMax = getDouble("mobs.trader_llama.attributes.jump_strength.max", traderLlamaJumpStrengthMax);
|
|
+ traderLlamaMovementSpeedMin = getDouble("mobs.trader_llama.attributes.movement_speed.min", traderLlamaMovementSpeedMin);
|
|
+ traderLlamaMovementSpeedMax = getDouble("mobs.trader_llama.attributes.movement_speed.max", traderLlamaMovementSpeedMax);
|
|
+ traderLlamaBreedingTicks = getInt("mobs.trader_llama.breeding-delay-ticks", traderLlamaBreedingTicks);
|
|
+ traderLlamaTakeDamageFromWater = getBoolean("mobs.trader_llama.takes-damage-from-water", traderLlamaTakeDamageFromWater);
|
|
+ traderLlamaAlwaysDropExp = getBoolean("mobs.trader_llama.always-drop-exp", traderLlamaAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean tropicalFishRidable = false;
|
|
+ public boolean tropicalFishControllable = true;
|
|
+ public double tropicalFishMaxHealth = 3.0D;
|
|
+ public double tropicalFishScale = 1.0D;
|
|
+ public boolean tropicalFishTakeDamageFromWater = false;
|
|
+ public boolean tropicalFishAlwaysDropExp = false;
|
|
+ private void tropicalFishSettings() {
|
|
+ tropicalFishRidable = getBoolean("mobs.tropical_fish.ridable", tropicalFishRidable);
|
|
+ tropicalFishControllable = getBoolean("mobs.tropical_fish.controllable", tropicalFishControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.tropical_fish.attributes.max-health", tropicalFishMaxHealth);
|
|
+ set("mobs.tropical_fish.attributes.max-health", null);
|
|
+ set("mobs.tropical_fish.attributes.max_health", oldValue);
|
|
+ }
|
|
+ tropicalFishMaxHealth = getDouble("mobs.tropical_fish.attributes.max_health", tropicalFishMaxHealth);
|
|
+ tropicalFishScale = Mth.clamp(getDouble("mobs.tropical_fish.attributes.scale", tropicalFishScale), 0.0625D, 16.0D);
|
|
+ tropicalFishTakeDamageFromWater = getBoolean("mobs.tropical_fish.takes-damage-from-water", tropicalFishTakeDamageFromWater);
|
|
+ tropicalFishAlwaysDropExp = getBoolean("mobs.tropical_fish.always-drop-exp", tropicalFishAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean turtleRidable = false;
|
|
+ public boolean turtleRidableInWater = true;
|
|
+ public boolean turtleControllable = true;
|
|
+ public double turtleMaxHealth = 30.0D;
|
|
+ public double turtleScale = 1.0D;
|
|
+ public int turtleBreedingTicks = 6000;
|
|
+ public boolean turtleTakeDamageFromWater = false;
|
|
+ public boolean turtleAlwaysDropExp = false;
|
|
+ private void turtleSettings() {
|
|
+ turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable);
|
|
+ turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater);
|
|
+ turtleControllable = getBoolean("mobs.turtle.controllable", turtleControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.turtle.attributes.max-health", turtleMaxHealth);
|
|
+ set("mobs.turtle.attributes.max-health", null);
|
|
+ set("mobs.turtle.attributes.max_health", oldValue);
|
|
+ }
|
|
+ turtleMaxHealth = getDouble("mobs.turtle.attributes.max_health", turtleMaxHealth);
|
|
+ turtleScale = Mth.clamp(getDouble("mobs.turtle.attributes.scale", turtleScale), 0.0625D, 16.0D);
|
|
+ turtleBreedingTicks = getInt("mobs.turtle.breeding-delay-ticks", turtleBreedingTicks);
|
|
+ turtleTakeDamageFromWater = getBoolean("mobs.turtle.takes-damage-from-water", turtleTakeDamageFromWater);
|
|
+ turtleAlwaysDropExp = getBoolean("mobs.turtle.always-drop-exp", turtleAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean vexRidable = false;
|
|
+ public boolean vexRidableInWater = true;
|
|
+ public boolean vexControllable = true;
|
|
+ public double vexMaxY = 320D;
|
|
+ public double vexMaxHealth = 14.0D;
|
|
+ public double vexScale = 1.0D;
|
|
+ public boolean vexTakeDamageFromWater = false;
|
|
+ public boolean vexAlwaysDropExp = false;
|
|
+ private void vexSettings() {
|
|
+ vexRidable = getBoolean("mobs.vex.ridable", vexRidable);
|
|
+ vexRidableInWater = getBoolean("mobs.vex.ridable-in-water", vexRidableInWater);
|
|
+ vexControllable = getBoolean("mobs.vex.controllable", vexControllable);
|
|
+ vexMaxY = getDouble("mobs.vex.ridable-max-y", vexMaxY);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.vex.attributes.max-health", vexMaxHealth);
|
|
+ set("mobs.vex.attributes.max-health", null);
|
|
+ set("mobs.vex.attributes.max_health", oldValue);
|
|
+ }
|
|
+ vexMaxHealth = getDouble("mobs.vex.attributes.max_health", vexMaxHealth);
|
|
+ vexScale = Mth.clamp(getDouble("mobs.vex.attributes.scale", vexScale), 0.0625D, 16.0D);
|
|
+ vexTakeDamageFromWater = getBoolean("mobs.vex.takes-damage-from-water", vexTakeDamageFromWater);
|
|
+ vexAlwaysDropExp = getBoolean("mobs.vex.always-drop-exp", vexAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean villagerRidable = false;
|
|
+ public boolean villagerRidableInWater = true;
|
|
+ public boolean villagerControllable = true;
|
|
+ public double villagerMaxHealth = 20.0D;
|
|
+ public double villagerScale = 1.0D;
|
|
+ public boolean villagerFollowEmeraldBlock = false;
|
|
+ public boolean villagerCanBeLeashed = false;
|
|
+ public boolean villagerCanBreed = true;
|
|
+ public int villagerBreedingTicks = 6000;
|
|
+ public boolean villagerClericsFarmWarts = false;
|
|
+ public boolean villagerClericFarmersThrowWarts = true;
|
|
+ public boolean villagerBypassMobGriefing = false;
|
|
+ public boolean villagerTakeDamageFromWater = false;
|
|
+ public boolean villagerAllowTrading = true;
|
|
+ public boolean villagerAlwaysDropExp = false;
|
|
+ public int villagerMinimumDemand = 0;
|
|
+ public boolean villagerLobotomizeEnabled = false;
|
|
+ public int villagerLobotomizeCheckInterval = 100;
|
|
+ public boolean villagerLobotomizeWaitUntilTradeLocked = false;
|
|
+ public boolean villagerDisplayTradeItem = true;
|
|
+ public int villagerSpawnIronGolemRadius = 0;
|
|
+ public int villagerSpawnIronGolemLimit = 0;
|
|
+ public int villagerAcquirePoiSearchRadius = 48;
|
|
+ public int villagerNearestBedSensorSearchRadius = 48;
|
|
+ private void villagerSettings() {
|
|
+ villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable);
|
|
+ villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater);
|
|
+ villagerControllable = getBoolean("mobs.villager.controllable", villagerControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.villager.attributes.max-health", villagerMaxHealth);
|
|
+ set("mobs.villager.attributes.max-health", null);
|
|
+ set("mobs.villager.attributes.max_health", oldValue);
|
|
+ }
|
|
+ villagerMaxHealth = getDouble("mobs.villager.attributes.max_health", villagerMaxHealth);
|
|
+ villagerScale = Mth.clamp(getDouble("mobs.villager.attributes.scale", villagerScale), 0.0625D, 16.0D);
|
|
+ villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock);
|
|
+ villagerCanBeLeashed = getBoolean("mobs.villager.can-be-leashed", villagerCanBeLeashed);
|
|
+ villagerCanBreed = getBoolean("mobs.villager.can-breed", villagerCanBreed);
|
|
+ villagerBreedingTicks = getInt("mobs.villager.breeding-delay-ticks", villagerBreedingTicks);
|
|
+ villagerClericsFarmWarts = getBoolean("mobs.villager.clerics-farm-warts", villagerClericsFarmWarts);
|
|
+ villagerClericFarmersThrowWarts = getBoolean("mobs.villager.cleric-wart-farmers-throw-warts-at-villagers", villagerClericFarmersThrowWarts);
|
|
+ villagerBypassMobGriefing = getBoolean("mobs.villager.bypass-mob-griefing", villagerBypassMobGriefing);
|
|
+ villagerTakeDamageFromWater = getBoolean("mobs.villager.takes-damage-from-water", villagerTakeDamageFromWater);
|
|
+ villagerAllowTrading = getBoolean("mobs.villager.allow-trading", villagerAllowTrading);
|
|
+ villagerAlwaysDropExp = getBoolean("mobs.villager.always-drop-exp", villagerAlwaysDropExp);
|
|
+ villagerMinimumDemand = getInt("mobs.villager.minimum-demand", villagerMinimumDemand);
|
|
+ if (PurpurConfig.version < 9) {
|
|
+ boolean oldValue = getBoolean("mobs.villager.lobotomize-1x1", villagerLobotomizeEnabled);
|
|
+ set("mobs.villager.lobotomize.enabled", oldValue);
|
|
+ set("mobs.villager.lobotomize-1x1", null);
|
|
+ }
|
|
+ if (PurpurConfig.version < 27) {
|
|
+ int oldValue = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval);
|
|
+ set("mobs.villager.lobotomize.check-interval", oldValue == 60 ? 100 : oldValue);
|
|
+ }
|
|
+ villagerLobotomizeEnabled = getBoolean("mobs.villager.lobotomize.enabled", villagerLobotomizeEnabled);
|
|
+ villagerLobotomizeCheckInterval = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval);
|
|
+ villagerLobotomizeWaitUntilTradeLocked = getBoolean("mobs.villager.lobotomize.wait-until-trade-locked", villagerLobotomizeWaitUntilTradeLocked);
|
|
+ villagerDisplayTradeItem = getBoolean("mobs.villager.display-trade-item", villagerDisplayTradeItem);
|
|
+ villagerSpawnIronGolemRadius = getInt("mobs.villager.spawn-iron-golem.radius", villagerSpawnIronGolemRadius);
|
|
+ villagerSpawnIronGolemLimit = getInt("mobs.villager.spawn-iron-golem.limit", villagerSpawnIronGolemLimit);
|
|
+ villagerAcquirePoiSearchRadius = getInt("mobs.villager.search-radius.acquire-poi", villagerAcquirePoiSearchRadius);
|
|
+ villagerNearestBedSensorSearchRadius = getInt("mobs.villager.search-radius.nearest-bed-sensor", villagerNearestBedSensorSearchRadius);
|
|
+ }
|
|
+
|
|
+ public boolean vindicatorRidable = false;
|
|
+ public boolean vindicatorRidableInWater = true;
|
|
+ public boolean vindicatorControllable = true;
|
|
+ public double vindicatorMaxHealth = 24.0D;
|
|
+ public double vindicatorScale = 1.0D;
|
|
+ public double vindicatorJohnnySpawnChance = 0D;
|
|
+ public boolean vindicatorTakeDamageFromWater = false;
|
|
+ public boolean vindicatorAlwaysDropExp = false;
|
|
+ private void vindicatorSettings() {
|
|
+ vindicatorRidable = getBoolean("mobs.vindicator.ridable", vindicatorRidable);
|
|
+ vindicatorRidableInWater = getBoolean("mobs.vindicator.ridable-in-water", vindicatorRidableInWater);
|
|
+ vindicatorControllable = getBoolean("mobs.vindicator.controllable", vindicatorControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.vindicator.attributes.max-health", vindicatorMaxHealth);
|
|
+ set("mobs.vindicator.attributes.max-health", null);
|
|
+ set("mobs.vindicator.attributes.max_health", oldValue);
|
|
+ }
|
|
+ vindicatorMaxHealth = getDouble("mobs.vindicator.attributes.max_health", vindicatorMaxHealth);
|
|
+ vindicatorScale = Mth.clamp(getDouble("mobs.vindicator.attributes.scale", vindicatorScale), 0.0625D, 16.0D);
|
|
+ vindicatorJohnnySpawnChance = getDouble("mobs.vindicator.johnny.spawn-chance", vindicatorJohnnySpawnChance);
|
|
+ vindicatorTakeDamageFromWater = getBoolean("mobs.vindicator.takes-damage-from-water", vindicatorTakeDamageFromWater);
|
|
+ vindicatorAlwaysDropExp = getBoolean("mobs.vindicator.always-drop-exp", vindicatorAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean wanderingTraderRidable = false;
|
|
+ public boolean wanderingTraderRidableInWater = true;
|
|
+ public boolean wanderingTraderControllable = true;
|
|
+ public double wanderingTraderMaxHealth = 20.0D;
|
|
+ public double wanderingTraderScale = 1.0D;
|
|
+ public boolean wanderingTraderFollowEmeraldBlock = false;
|
|
+ public boolean wanderingTraderCanBeLeashed = false;
|
|
+ public boolean wanderingTraderTakeDamageFromWater = false;
|
|
+ public boolean wanderingTraderAllowTrading = true;
|
|
+ public boolean wanderingTraderAlwaysDropExp = false;
|
|
+ private void wanderingTraderSettings() {
|
|
+ wanderingTraderRidable = getBoolean("mobs.wandering_trader.ridable", wanderingTraderRidable);
|
|
+ wanderingTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", wanderingTraderRidableInWater);
|
|
+ wanderingTraderControllable = getBoolean("mobs.wandering_trader.controllable", wanderingTraderControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.wandering_trader.attributes.max-health", wanderingTraderMaxHealth);
|
|
+ set("mobs.wandering_trader.attributes.max-health", null);
|
|
+ set("mobs.wandering_trader.attributes.max_health", oldValue);
|
|
+ }
|
|
+ wanderingTraderMaxHealth = getDouble("mobs.wandering_trader.attributes.max_health", wanderingTraderMaxHealth);
|
|
+ wanderingTraderScale = Mth.clamp(getDouble("mobs.wandering_trader.attributes.scale", wanderingTraderScale), 0.0625D, 16.0D);
|
|
+ wanderingTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", wanderingTraderFollowEmeraldBlock);
|
|
+ wanderingTraderCanBeLeashed = getBoolean("mobs.wandering_trader.can-be-leashed", wanderingTraderCanBeLeashed);
|
|
+ wanderingTraderTakeDamageFromWater = getBoolean("mobs.wandering_trader.takes-damage-from-water", wanderingTraderTakeDamageFromWater);
|
|
+ wanderingTraderAllowTrading = getBoolean("mobs.wandering_trader.allow-trading", wanderingTraderAllowTrading);
|
|
+ wanderingTraderAlwaysDropExp = getBoolean("mobs.wandering_trader.always-drop-exp", wanderingTraderAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean wardenRidable = false;
|
|
+ public boolean wardenRidableInWater = true;
|
|
+ public boolean wardenControllable = true;
|
|
+ private void wardenSettings() {
|
|
+ wardenRidable = getBoolean("mobs.warden.ridable", wardenRidable);
|
|
+ wardenRidableInWater = getBoolean("mobs.warden.ridable-in-water", wardenRidableInWater);
|
|
+ wardenControllable = getBoolean("mobs.warden.controllable", wardenControllable);
|
|
+ }
|
|
+
|
|
+ public boolean witchRidable = false;
|
|
+ public boolean witchRidableInWater = true;
|
|
+ public boolean witchControllable = true;
|
|
+ public double witchMaxHealth = 26.0D;
|
|
+ public double witchScale = 1.0D;
|
|
+ public boolean witchTakeDamageFromWater = false;
|
|
+ public boolean witchAlwaysDropExp = false;
|
|
+ private void witchSettings() {
|
|
+ witchRidable = getBoolean("mobs.witch.ridable", witchRidable);
|
|
+ witchRidableInWater = getBoolean("mobs.witch.ridable-in-water", witchRidableInWater);
|
|
+ witchControllable = getBoolean("mobs.witch.controllable", witchControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.witch.attributes.max-health", witchMaxHealth);
|
|
+ set("mobs.witch.attributes.max-health", null);
|
|
+ set("mobs.witch.attributes.max_health", oldValue);
|
|
+ }
|
|
+ witchMaxHealth = getDouble("mobs.witch.attributes.max_health", witchMaxHealth);
|
|
+ witchScale = Mth.clamp(getDouble("mobs.witch.attributes.scale", witchScale), 0.0625D, 16.0D);
|
|
+ witchTakeDamageFromWater = getBoolean("mobs.witch.takes-damage-from-water", witchTakeDamageFromWater);
|
|
+ witchAlwaysDropExp = getBoolean("mobs.witch.always-drop-exp", witchAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean witherRidable = false;
|
|
+ public boolean witherRidableInWater = true;
|
|
+ public boolean witherControllable = true;
|
|
+ public double witherMaxY = 320D;
|
|
+ public double witherMaxHealth = 300.0D;
|
|
+ public double witherScale = 1.0D;
|
|
+ public float witherHealthRegenAmount = 1.0f;
|
|
+ public int witherHealthRegenDelay = 20;
|
|
+ public boolean witherBypassMobGriefing = false;
|
|
+ public boolean witherTakeDamageFromWater = false;
|
|
+ public boolean witherCanRideVehicles = false;
|
|
+ public float witherExplosionRadius = 1.0F;
|
|
+ public boolean witherPlaySpawnSound = true;
|
|
+ public boolean witherAlwaysDropExp = false;
|
|
+ private void witherSettings() {
|
|
+ witherRidable = getBoolean("mobs.wither.ridable", witherRidable);
|
|
+ witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater);
|
|
+ witherControllable = getBoolean("mobs.wither.controllable", witherControllable);
|
|
+ witherMaxY = getDouble("mobs.wither.ridable-max-y", witherMaxY);
|
|
+ if (PurpurConfig.version < 8) {
|
|
+ double oldValue = getDouble("mobs.wither.max-health", witherMaxHealth);
|
|
+ set("mobs.wither.max_health", null);
|
|
+ set("mobs.wither.attributes.max-health", oldValue);
|
|
+ } else if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.wither.attributes.max-health", witherMaxHealth);
|
|
+ set("mobs.wither.attributes.max-health", null);
|
|
+ set("mobs.wither.attributes.max_health", oldValue);
|
|
+ }
|
|
+ witherMaxHealth = getDouble("mobs.wither.attributes.max_health", witherMaxHealth);
|
|
+ witherScale = Mth.clamp(getDouble("mobs.wither.attributes.scale", witherScale), 0.0625D, 16.0D);
|
|
+ witherHealthRegenAmount = (float) getDouble("mobs.wither.health-regen-amount", witherHealthRegenAmount);
|
|
+ witherHealthRegenDelay = getInt("mobs.wither.health-regen-delay", witherHealthRegenDelay);
|
|
+ witherBypassMobGriefing = getBoolean("mobs.wither.bypass-mob-griefing", witherBypassMobGriefing);
|
|
+ witherTakeDamageFromWater = getBoolean("mobs.wither.takes-damage-from-water", witherTakeDamageFromWater);
|
|
+ witherCanRideVehicles = getBoolean("mobs.wither.can-ride-vehicles", witherCanRideVehicles);
|
|
+ witherExplosionRadius = (float) getDouble("mobs.wither.explosion-radius", witherExplosionRadius);
|
|
+ witherPlaySpawnSound = getBoolean("mobs.wither.play-spawn-sound", witherPlaySpawnSound);
|
|
+ witherAlwaysDropExp = getBoolean("mobs.wither.always-drop-exp", witherAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean witherSkeletonRidable = false;
|
|
+ public boolean witherSkeletonRidableInWater = true;
|
|
+ public boolean witherSkeletonControllable = true;
|
|
+ public double witherSkeletonMaxHealth = 20.0D;
|
|
+ public double witherSkeletonScale = 1.0D;
|
|
+ public boolean witherSkeletonTakeDamageFromWater = false;
|
|
+ public boolean witherSkeletonAlwaysDropExp = false;
|
|
+ private void witherSkeletonSettings() {
|
|
+ witherSkeletonRidable = getBoolean("mobs.wither_skeleton.ridable", witherSkeletonRidable);
|
|
+ witherSkeletonRidableInWater = getBoolean("mobs.wither_skeleton.ridable-in-water", witherSkeletonRidableInWater);
|
|
+ witherSkeletonControllable = getBoolean("mobs.wither_skeleton.controllable", witherSkeletonControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.wither_skeleton.attributes.max-health", witherSkeletonMaxHealth);
|
|
+ set("mobs.wither_skeleton.attributes.max-health", null);
|
|
+ set("mobs.wither_skeleton.attributes.max_health", oldValue);
|
|
+ }
|
|
+ witherSkeletonMaxHealth = getDouble("mobs.wither_skeleton.attributes.max_health", witherSkeletonMaxHealth);
|
|
+ witherSkeletonScale = Mth.clamp(getDouble("mobs.wither_skeleton.attributes.scale", witherSkeletonScale), 0.0625D, 16.0D);
|
|
+ witherSkeletonTakeDamageFromWater = getBoolean("mobs.wither_skeleton.takes-damage-from-water", witherSkeletonTakeDamageFromWater);
|
|
+ witherSkeletonAlwaysDropExp = getBoolean("mobs.wither_skeleton.always-drop-exp", witherSkeletonAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean wolfRidable = false;
|
|
+ public boolean wolfRidableInWater = true;
|
|
+ public boolean wolfControllable = true;
|
|
+ public double wolfMaxHealth = 8.0D;
|
|
+ public double wolfScale = 1.0D;
|
|
+ public DyeColor wolfDefaultCollarColor = DyeColor.RED;
|
|
+ public boolean wolfMilkCuresRabies = true;
|
|
+ public double wolfNaturalRabid = 0.0D;
|
|
+ public int wolfBreedingTicks = 6000;
|
|
+ public boolean wolfTakeDamageFromWater = false;
|
|
+ public boolean wolfAlwaysDropExp = false;
|
|
+ private void wolfSettings() {
|
|
+ wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable);
|
|
+ wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater);
|
|
+ wolfControllable = getBoolean("mobs.wolf.controllable", wolfControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.wolf.attributes.max-health", wolfMaxHealth);
|
|
+ set("mobs.wolf.attributes.max-health", null);
|
|
+ set("mobs.wolf.attributes.max_health", oldValue);
|
|
+ }
|
|
+ wolfMaxHealth = getDouble("mobs.wolf.attributes.max_health", wolfMaxHealth);
|
|
+ wolfScale = Mth.clamp(getDouble("mobs.wolf.attributes.scale", wolfScale), 0.0625D, 16.0D);
|
|
+ try {
|
|
+ wolfDefaultCollarColor = DyeColor.valueOf(getString("mobs.wolf.default-collar-color", wolfDefaultCollarColor.name()));
|
|
+ } catch (IllegalArgumentException ignore) {
|
|
+ wolfDefaultCollarColor = DyeColor.RED;
|
|
+ }
|
|
+ wolfMilkCuresRabies = getBoolean("mobs.wolf.milk-cures-rabid-wolves", wolfMilkCuresRabies);
|
|
+ wolfNaturalRabid = getDouble("mobs.wolf.spawn-rabid-chance", wolfNaturalRabid);
|
|
+ wolfBreedingTicks = getInt("mobs.wolf.breeding-delay-ticks", wolfBreedingTicks);
|
|
+ wolfTakeDamageFromWater = getBoolean("mobs.wolf.takes-damage-from-water", wolfTakeDamageFromWater);
|
|
+ wolfAlwaysDropExp = getBoolean("mobs.wolf.always-drop-exp", wolfAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean zoglinRidable = false;
|
|
+ public boolean zoglinRidableInWater = true;
|
|
+ public boolean zoglinControllable = true;
|
|
+ public double zoglinMaxHealth = 40.0D;
|
|
+ public double zoglinScale = 1.0D;
|
|
+ public boolean zoglinTakeDamageFromWater = false;
|
|
+ public boolean zoglinAlwaysDropExp = false;
|
|
+ private void zoglinSettings() {
|
|
+ zoglinRidable = getBoolean("mobs.zoglin.ridable", zoglinRidable);
|
|
+ zoglinRidableInWater = getBoolean("mobs.zoglin.ridable-in-water", zoglinRidableInWater);
|
|
+ zoglinControllable = getBoolean("mobs.zoglin.controllable", zoglinControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.zoglin.attributes.max-health", zoglinMaxHealth);
|
|
+ set("mobs.zoglin.attributes.max-health", null);
|
|
+ set("mobs.zoglin.attributes.max_health", oldValue);
|
|
+ }
|
|
+ zoglinMaxHealth = getDouble("mobs.zoglin.attributes.max_health", zoglinMaxHealth);
|
|
+ zoglinScale = Mth.clamp(getDouble("mobs.zoglin.attributes.scale", zoglinScale), 0.0625D, 16.0D);
|
|
+ zoglinTakeDamageFromWater = getBoolean("mobs.zoglin.takes-damage-from-water", zoglinTakeDamageFromWater);
|
|
+ zoglinAlwaysDropExp = getBoolean("mobs.zoglin.always-drop-exp", zoglinAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean zombieRidable = false;
|
|
+ public boolean zombieRidableInWater = true;
|
|
+ public boolean zombieControllable = true;
|
|
+ public double zombieMaxHealth = 20.0D;
|
|
+ public double zombieScale = 1.0D;
|
|
+ public double zombieSpawnReinforcements = 0.1D;
|
|
+ public boolean zombieJockeyOnlyBaby = true;
|
|
+ public double zombieJockeyChance = 0.05D;
|
|
+ public boolean zombieJockeyTryExistingChickens = true;
|
|
+ public boolean zombieAggressiveTowardsVillagerWhenLagging = true;
|
|
+ public boolean zombieBypassMobGriefing = false;
|
|
+ public boolean zombieTakeDamageFromWater = false;
|
|
+ public boolean zombieAlwaysDropExp = false;
|
|
+ public double zombieHeadVisibilityPercent = 0.5D;
|
|
+ private void zombieSettings() {
|
|
+ zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable);
|
|
+ zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater);
|
|
+ zombieControllable = getBoolean("mobs.zombie.controllable", zombieControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.zombie.attributes.max-health", zombieMaxHealth);
|
|
+ set("mobs.zombie.attributes.max-health", null);
|
|
+ set("mobs.zombie.attributes.max_health", oldValue);
|
|
+ }
|
|
+ zombieMaxHealth = getDouble("mobs.zombie.attributes.max_health", zombieMaxHealth);
|
|
+ zombieScale = Mth.clamp(getDouble("mobs.zombie.attributes.scale", zombieScale), 0.0625D, 16.0D);
|
|
+ zombieSpawnReinforcements = getDouble("mobs.zombie.attributes.spawn_reinforcements", zombieSpawnReinforcements);
|
|
+ zombieJockeyOnlyBaby = getBoolean("mobs.zombie.jockey.only-babies", zombieJockeyOnlyBaby);
|
|
+ zombieJockeyChance = getDouble("mobs.zombie.jockey.chance", zombieJockeyChance);
|
|
+ zombieJockeyTryExistingChickens = getBoolean("mobs.zombie.jockey.try-existing-chickens", zombieJockeyTryExistingChickens);
|
|
+ zombieAggressiveTowardsVillagerWhenLagging = getBoolean("mobs.zombie.aggressive-towards-villager-when-lagging", zombieAggressiveTowardsVillagerWhenLagging);
|
|
+ zombieBypassMobGriefing = getBoolean("mobs.zombie.bypass-mob-griefing", zombieBypassMobGriefing);
|
|
+ zombieTakeDamageFromWater = getBoolean("mobs.zombie.takes-damage-from-water", zombieTakeDamageFromWater);
|
|
+ zombieAlwaysDropExp = getBoolean("mobs.zombie.always-drop-exp", zombieAlwaysDropExp);
|
|
+ zombieHeadVisibilityPercent = getDouble("mobs.zombie.head-visibility-percent", zombieHeadVisibilityPercent);
|
|
+ }
|
|
+
|
|
+ public boolean zombieHorseRidable = false;
|
|
+ public boolean zombieHorseRidableInWater = false;
|
|
+ public boolean zombieHorseCanSwim = false;
|
|
+ public double zombieHorseMaxHealthMin = 15.0D;
|
|
+ public double zombieHorseMaxHealthMax = 15.0D;
|
|
+ public double zombieHorseJumpStrengthMin = 0.4D;
|
|
+ public double zombieHorseJumpStrengthMax = 1.0D;
|
|
+ public double zombieHorseMovementSpeedMin = 0.2D;
|
|
+ public double zombieHorseMovementSpeedMax = 0.2D;
|
|
+ public double zombieHorseSpawnChance = 0.0D;
|
|
+ public boolean zombieHorseTakeDamageFromWater = false;
|
|
+ public boolean zombieHorseAlwaysDropExp = false;
|
|
+ private void zombieHorseSettings() {
|
|
+ zombieHorseRidable = getBoolean("mobs.zombie_horse.ridable", zombieHorseRidable);
|
|
+ zombieHorseRidableInWater = getBoolean("mobs.zombie_horse.ridable-in-water", zombieHorseRidableInWater);
|
|
+ zombieHorseCanSwim = getBoolean("mobs.zombie_horse.can-swim", zombieHorseCanSwim);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.zombie_horse.attributes.max-health", zombieHorseMaxHealthMin);
|
|
+ set("mobs.zombie_horse.attributes.max-health", null);
|
|
+ set("mobs.zombie_horse.attributes.max_health.min", oldValue);
|
|
+ set("mobs.zombie_horse.attributes.max_health.max", oldValue);
|
|
+ }
|
|
+ zombieHorseMaxHealthMin = getDouble("mobs.zombie_horse.attributes.max_health.min", zombieHorseMaxHealthMin);
|
|
+ zombieHorseMaxHealthMax = getDouble("mobs.zombie_horse.attributes.max_health.max", zombieHorseMaxHealthMax);
|
|
+ zombieHorseJumpStrengthMin = getDouble("mobs.zombie_horse.attributes.jump_strength.min", zombieHorseJumpStrengthMin);
|
|
+ zombieHorseJumpStrengthMax = getDouble("mobs.zombie_horse.attributes.jump_strength.max", zombieHorseJumpStrengthMax);
|
|
+ zombieHorseMovementSpeedMin = getDouble("mobs.zombie_horse.attributes.movement_speed.min", zombieHorseMovementSpeedMin);
|
|
+ zombieHorseMovementSpeedMax = getDouble("mobs.zombie_horse.attributes.movement_speed.max", zombieHorseMovementSpeedMax);
|
|
+ zombieHorseSpawnChance = getDouble("mobs.zombie_horse.spawn-chance", zombieHorseSpawnChance);
|
|
+ zombieHorseTakeDamageFromWater = getBoolean("mobs.zombie_horse.takes-damage-from-water", zombieHorseTakeDamageFromWater);
|
|
+ zombieHorseAlwaysDropExp = getBoolean("mobs.zombie_horse.always-drop-exp", zombieHorseAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean zombieVillagerRidable = false;
|
|
+ public boolean zombieVillagerRidableInWater = true;
|
|
+ public boolean zombieVillagerControllable = true;
|
|
+ public double zombieVillagerMaxHealth = 20.0D;
|
|
+ public double zombieVillagerScale = 1.0D;
|
|
+ public double zombieVillagerSpawnReinforcements = 0.1D;
|
|
+ public boolean zombieVillagerJockeyOnlyBaby = true;
|
|
+ public double zombieVillagerJockeyChance = 0.05D;
|
|
+ public boolean zombieVillagerJockeyTryExistingChickens = true;
|
|
+ public boolean zombieVillagerTakeDamageFromWater = false;
|
|
+ public int zombieVillagerCuringTimeMin = 3600;
|
|
+ public int zombieVillagerCuringTimeMax = 6000;
|
|
+ public boolean zombieVillagerCureEnabled = true;
|
|
+ public boolean zombieVillagerAlwaysDropExp = false;
|
|
+ private void zombieVillagerSettings() {
|
|
+ zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable);
|
|
+ zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater);
|
|
+ zombieVillagerControllable = getBoolean("mobs.zombie_villager.controllable", zombieVillagerControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.zombie_villager.attributes.max-health", zombieVillagerMaxHealth);
|
|
+ set("mobs.zombie_villager.attributes.max-health", null);
|
|
+ set("mobs.zombie_villager.attributes.max_health", oldValue);
|
|
+ }
|
|
+ zombieVillagerMaxHealth = getDouble("mobs.zombie_villager.attributes.max_health", zombieVillagerMaxHealth);
|
|
+ zombieVillagerScale = Mth.clamp(getDouble("mobs.zombie_villager.attributes.scale", zombieVillagerScale), 0.0625D, 16.0D);
|
|
+ zombieVillagerSpawnReinforcements = getDouble("mobs.zombie_villager.attributes.spawn_reinforcements", zombieVillagerSpawnReinforcements);
|
|
+ zombieVillagerJockeyOnlyBaby = getBoolean("mobs.zombie_villager.jockey.only-babies", zombieVillagerJockeyOnlyBaby);
|
|
+ zombieVillagerJockeyChance = getDouble("mobs.zombie_villager.jockey.chance", zombieVillagerJockeyChance);
|
|
+ zombieVillagerJockeyTryExistingChickens = getBoolean("mobs.zombie_villager.jockey.try-existing-chickens", zombieVillagerJockeyTryExistingChickens);
|
|
+ zombieVillagerTakeDamageFromWater = getBoolean("mobs.zombie_villager.takes-damage-from-water", zombieVillagerTakeDamageFromWater);
|
|
+ zombieVillagerCuringTimeMin = getInt("mobs.zombie_villager.curing_time.min", zombieVillagerCuringTimeMin);
|
|
+ zombieVillagerCuringTimeMax = getInt("mobs.zombie_villager.curing_time.max", zombieVillagerCuringTimeMax);
|
|
+ zombieVillagerCureEnabled = getBoolean("mobs.zombie_villager.cure.enabled", zombieVillagerCureEnabled);
|
|
+ zombieVillagerAlwaysDropExp = getBoolean("mobs.zombie_villager.always-drop-exp", zombieVillagerAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public boolean zombifiedPiglinRidable = false;
|
|
+ public boolean zombifiedPiglinRidableInWater = true;
|
|
+ public boolean zombifiedPiglinControllable = true;
|
|
+ public double zombifiedPiglinMaxHealth = 20.0D;
|
|
+ public double zombifiedPiglinScale = 1.0D;
|
|
+ public double zombifiedPiglinSpawnReinforcements = 0.0D;
|
|
+ public boolean zombifiedPiglinJockeyOnlyBaby = true;
|
|
+ public double zombifiedPiglinJockeyChance = 0.05D;
|
|
+ public boolean zombifiedPiglinJockeyTryExistingChickens = true;
|
|
+ public boolean zombifiedPiglinCountAsPlayerKillWhenAngry = true;
|
|
+ public boolean zombifiedPiglinTakeDamageFromWater = false;
|
|
+ public boolean zombifiedPiglinAlwaysDropExp = false;
|
|
+ private void zombifiedPiglinSettings() {
|
|
+ zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable);
|
|
+ zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater);
|
|
+ zombifiedPiglinControllable = getBoolean("mobs.zombified_piglin.controllable", zombifiedPiglinControllable);
|
|
+ if (PurpurConfig.version < 10) {
|
|
+ double oldValue = getDouble("mobs.zombified_piglin.attributes.max-health", zombifiedPiglinMaxHealth);
|
|
+ set("mobs.zombified_piglin.attributes.max-health", null);
|
|
+ set("mobs.zombified_piglin.attributes.max_health", oldValue);
|
|
+ }
|
|
+ zombifiedPiglinMaxHealth = getDouble("mobs.zombified_piglin.attributes.max_health", zombifiedPiglinMaxHealth);
|
|
+ zombifiedPiglinScale = Mth.clamp(getDouble("mobs.zombified_piglin.attributes.scale", zombifiedPiglinScale), 0.0625D, 16.0D);
|
|
+ zombifiedPiglinSpawnReinforcements = getDouble("mobs.zombified_piglin.attributes.spawn_reinforcements", zombifiedPiglinSpawnReinforcements);
|
|
+ zombifiedPiglinJockeyOnlyBaby = getBoolean("mobs.zombified_piglin.jockey.only-babies", zombifiedPiglinJockeyOnlyBaby);
|
|
+ zombifiedPiglinJockeyChance = getDouble("mobs.zombified_piglin.jockey.chance", zombifiedPiglinJockeyChance);
|
|
+ zombifiedPiglinJockeyTryExistingChickens = getBoolean("mobs.zombified_piglin.jockey.try-existing-chickens", zombifiedPiglinJockeyTryExistingChickens);
|
|
+ zombifiedPiglinCountAsPlayerKillWhenAngry = getBoolean("mobs.zombified_piglin.count-as-player-kill-when-angry", zombifiedPiglinCountAsPlayerKillWhenAngry);
|
|
+ zombifiedPiglinTakeDamageFromWater = getBoolean("mobs.zombified_piglin.takes-damage-from-water", zombifiedPiglinTakeDamageFromWater);
|
|
+ zombifiedPiglinAlwaysDropExp = getBoolean("mobs.zombified_piglin.always-drop-exp", zombifiedPiglinAlwaysDropExp);
|
|
+ }
|
|
+
|
|
+ public float hungerStarvationDamage = 1.0F;
|
|
+ private void hungerSettings() {
|
|
+ hungerStarvationDamage = (float) getDouble("hunger.starvation-damage", hungerStarvationDamage);
|
|
+ }
|
|
+
|
|
+ public int conduitDistance = 16;
|
|
+ public double conduitDamageDistance = 8;
|
|
+ public float conduitDamageAmount = 4;
|
|
+ public Block[] conduitBlocks;
|
|
+ private void conduitSettings() {
|
|
+ conduitDistance = getInt("blocks.conduit.effect-distance", conduitDistance);
|
|
+ conduitDamageDistance = getDouble("blocks.conduit.mob-damage.distance", conduitDamageDistance);
|
|
+ conduitDamageAmount = (float) getDouble("blocks.conduit.mob-damage.damage-amount", conduitDamageAmount);
|
|
+ List<Block> conduitBlockList = new ArrayList<>();
|
|
+ getList("blocks.conduit.valid-ring-blocks", new ArrayList<String>(){{
|
|
+ add("minecraft:prismarine");
|
|
+ add("minecraft:prismarine_bricks");
|
|
+ add("minecraft:sea_lantern");
|
|
+ add("minecraft:dark_prismarine");
|
|
+ }}).forEach(key -> {
|
|
+ Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(key.toString()));
|
|
+ if (!block.defaultBlockState().isAir()) {
|
|
+ conduitBlockList.add(block);
|
|
+ }
|
|
+ });
|
|
+ conduitBlocks = conduitBlockList.toArray(Block[]::new);
|
|
+ }
|
|
+
|
|
+ public float cauldronRainChance = 0.05F;
|
|
+ public float cauldronPowderSnowChance = 0.1F;
|
|
+ public float cauldronDripstoneWaterFillChance = 0.17578125F;
|
|
+ public float cauldronDripstoneLavaFillChance = 0.05859375F;
|
|
+ private void cauldronSettings() {
|
|
+ cauldronRainChance = (float) getDouble("blocks.cauldron.fill-chances.rain", cauldronRainChance);
|
|
+ cauldronPowderSnowChance = (float) getDouble("blocks.cauldron.fill-chances.powder-snow", cauldronPowderSnowChance);
|
|
+ cauldronDripstoneWaterFillChance = (float) getDouble("blocks.cauldron.fill-chances.dripstone-water", cauldronDripstoneWaterFillChance);
|
|
+ cauldronDripstoneLavaFillChance = (float) getDouble("blocks.cauldron.fill-chances.dripstone-lava", cauldronDripstoneLavaFillChance);
|
|
+ }
|
|
+
|
|
+ public float shearsCanDefuseTntChance = 0.00F;
|
|
+ public boolean shearsCanDefuseTnt = false;
|
|
+ private void shearsCanDefuseTntSettings() {
|
|
+ shearsCanDefuseTntChance = (float) getDouble("gameplay-mechanics.item.shears.defuse-tnt-chance", 0.00D);
|
|
+ shearsCanDefuseTnt = shearsCanDefuseTntChance > 0.00F;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/command/CompassCommand.java b/src/main/java/org/purpurmc/purpur/command/CompassCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..79b8490832d2a0cc7846ddcb091cb6bcac74ea45
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/command/CompassCommand.java
|
|
@@ -0,0 +1,27 @@
|
|
+package org.purpurmc.purpur.command;
|
|
+
|
|
+import com.mojang.brigadier.CommandDispatcher;
|
|
+import net.minecraft.commands.CommandSourceStack;
|
|
+import net.minecraft.commands.Commands;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import org.purpurmc.purpur.task.CompassTask;
|
|
+
|
|
+public class CompassCommand {
|
|
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
|
+ dispatcher.register(Commands.literal("compass")
|
|
+ .requires(listener -> listener.hasPermission(2, "bukkit.command.compass"))
|
|
+ .executes(context -> {
|
|
+ ServerPlayer player = context.getSource().getPlayerOrException();
|
|
+ CompassTask task = CompassTask.instance();
|
|
+ if (player.compassBar()) {
|
|
+ task.removePlayer(player.getBukkitEntity());
|
|
+ player.compassBar(false);
|
|
+ } else {
|
|
+ task.addPlayer(player.getBukkitEntity());
|
|
+ player.compassBar(true);
|
|
+ }
|
|
+ return 1;
|
|
+ })
|
|
+ );
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/command/CreditsCommand.java b/src/main/java/org/purpurmc/purpur/command/CreditsCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..40d2fab4a9728ac90c36e30c130f3116b7025d11
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/command/CreditsCommand.java
|
|
@@ -0,0 +1,35 @@
|
|
+package org.purpurmc.purpur.command;
|
|
+
|
|
+import com.mojang.brigadier.CommandDispatcher;
|
|
+import net.minecraft.commands.CommandSourceStack;
|
|
+import net.minecraft.commands.Commands;
|
|
+import net.minecraft.commands.arguments.EntityArgument;
|
|
+import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import org.purpurmc.purpur.PurpurConfig;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.Collections;
|
|
+
|
|
+public class CreditsCommand {
|
|
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
|
+ dispatcher.register(Commands.literal("credits")
|
|
+ .requires((listener) -> listener.hasPermission(2, "bukkit.command.credits"))
|
|
+ .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException())))
|
|
+ .then(Commands.argument("targets", EntityArgument.players())
|
|
+ .requires(listener -> listener.hasPermission(2, "bukkit.command.credits.other"))
|
|
+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets")))
|
|
+ )
|
|
+ );
|
|
+ }
|
|
+
|
|
+ private static int execute(CommandSourceStack sender, Collection<ServerPlayer> targets) {
|
|
+ for (ServerPlayer player : targets) {
|
|
+ ClientboundGameEventPacket packet = new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, 1F);
|
|
+ player.connection.send(packet);
|
|
+ String output = String.format(PurpurConfig.creditsCommandOutput, player.getGameProfile().getName());
|
|
+ sender.sendSuccess(output, false);
|
|
+ }
|
|
+ return targets.size();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/command/DemoCommand.java b/src/main/java/org/purpurmc/purpur/command/DemoCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..235f3cd89f675b70a6152a00534608c0902f19fd
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/command/DemoCommand.java
|
|
@@ -0,0 +1,35 @@
|
|
+package org.purpurmc.purpur.command;
|
|
+
|
|
+import com.mojang.brigadier.CommandDispatcher;
|
|
+import net.minecraft.commands.CommandSourceStack;
|
|
+import net.minecraft.commands.Commands;
|
|
+import net.minecraft.commands.arguments.EntityArgument;
|
|
+import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import org.purpurmc.purpur.PurpurConfig;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.Collections;
|
|
+
|
|
+public class DemoCommand {
|
|
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
|
+ dispatcher.register(Commands.literal("demo")
|
|
+ .requires((listener) -> listener.hasPermission(2, "bukkit.command.demo"))
|
|
+ .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException())))
|
|
+ .then(Commands.argument("targets", EntityArgument.players())
|
|
+ .requires(listener -> listener.hasPermission(2, "bukkit.command.demo.other"))
|
|
+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets")))
|
|
+ )
|
|
+ );
|
|
+ }
|
|
+
|
|
+ private static int execute(CommandSourceStack sender, Collection<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();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/command/PingCommand.java b/src/main/java/org/purpurmc/purpur/command/PingCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..f202b98a194604e39798fdb8e417c6d2835f71c8
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/command/PingCommand.java
|
|
@@ -0,0 +1,33 @@
|
|
+package org.purpurmc.purpur.command;
|
|
+
|
|
+import com.mojang.brigadier.CommandDispatcher;
|
|
+import net.minecraft.commands.CommandSourceStack;
|
|
+import net.minecraft.commands.Commands;
|
|
+import net.minecraft.commands.arguments.EntityArgument;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import org.purpurmc.purpur.PurpurConfig;
|
|
+import org.bukkit.craftbukkit.util.CraftChatMessage;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.Collections;
|
|
+
|
|
+public class PingCommand {
|
|
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
|
+ dispatcher.register(Commands.literal("ping")
|
|
+ .requires((listener) -> listener.hasPermission(2, "bukkit.command.ping"))
|
|
+ .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException())))
|
|
+ .then(Commands.argument("targets", EntityArgument.players())
|
|
+ .requires(listener -> listener.hasPermission(2, "bukkit.command.ping.other"))
|
|
+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets")))
|
|
+ )
|
|
+ );
|
|
+ }
|
|
+
|
|
+ private static int execute(CommandSourceStack sender, Collection<ServerPlayer> targets) {
|
|
+ for (ServerPlayer player : targets) {
|
|
+ String output = String.format(PurpurConfig.pingCommandOutput, player.getGameProfile().getName(), player.connection.latency());
|
|
+ sender.sendSuccess(output, false);
|
|
+ }
|
|
+ return targets.size();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java b/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..2621e54879e9ab0029a875f1d09eee67878b90d5
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java
|
|
@@ -0,0 +1,66 @@
|
|
+package org.purpurmc.purpur.command;
|
|
+
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.server.level.ServerLevel;
|
|
+import org.purpurmc.purpur.PurpurConfig;
|
|
+import org.bukkit.ChatColor;
|
|
+import org.bukkit.Location;
|
|
+import org.bukkit.command.Command;
|
|
+import org.bukkit.command.CommandSender;
|
|
+
|
|
+import java.io.File;
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.stream.Collectors;
|
|
+import java.util.stream.Stream;
|
|
+
|
|
+public class PurpurCommand extends Command {
|
|
+ public PurpurCommand(String name) {
|
|
+ super(name);
|
|
+ this.description = "Purpur related commands";
|
|
+ this.usageMessage = "/purpur [reload | version]";
|
|
+ this.setPermission("bukkit.command.purpur");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<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();
|
|
+ level.resetBreedingCooldowns();
|
|
+ }
|
|
+ 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/purpurmc/purpur/command/RamBarCommand.java b/src/main/java/org/purpurmc/purpur/command/RamBarCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..2852c07adb080c34905f5d1b19efed8ea47eecc6
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/command/RamBarCommand.java
|
|
@@ -0,0 +1,44 @@
|
|
+package org.purpurmc.purpur.command;
|
|
+
|
|
+import com.mojang.brigadier.CommandDispatcher;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
|
+import net.minecraft.commands.CommandSourceStack;
|
|
+import net.minecraft.commands.Commands;
|
|
+import net.minecraft.commands.arguments.EntityArgument;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import org.purpurmc.purpur.PurpurConfig;
|
|
+import org.purpurmc.purpur.task.RamBarTask;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.Collections;
|
|
+
|
|
+public class RamBarCommand {
|
|
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
|
+ dispatcher.register(Commands.literal("rambar")
|
|
+ .requires(listener -> listener.hasPermission(2, "bukkit.command.rambar"))
|
|
+ .executes(context -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException())))
|
|
+ .then(Commands.argument("targets", EntityArgument.players())
|
|
+ .requires(listener -> listener.hasPermission(2, "bukkit.command.rambar.other"))
|
|
+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets")))
|
|
+ )
|
|
+ );
|
|
+ }
|
|
+
|
|
+ private static int execute(CommandSourceStack sender, Collection<ServerPlayer> targets) {
|
|
+ for (ServerPlayer player : targets) {
|
|
+ boolean result = RamBarTask.instance().togglePlayer(player.getBukkitEntity());
|
|
+ player.ramBar(result);
|
|
+
|
|
+ Component output = MiniMessage.miniMessage().deserialize(PurpurConfig.rambarCommandOutput,
|
|
+ Placeholder.component("onoff", Component.translatable(result ? "options.on" : "options.off")
|
|
+ .color(result ? NamedTextColor.GREEN : NamedTextColor.RED)),
|
|
+ Placeholder.parsed("target", player.getGameProfile().getName()));
|
|
+
|
|
+ sender.sendSuccess(output, false);
|
|
+ }
|
|
+ return targets.size();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/command/RamCommand.java b/src/main/java/org/purpurmc/purpur/command/RamCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..992f8dfc628c7485e335191e1308cdfd4eedfbe8
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/command/RamCommand.java
|
|
@@ -0,0 +1,30 @@
|
|
+package org.purpurmc.purpur.command;
|
|
+
|
|
+import com.mojang.brigadier.CommandDispatcher;
|
|
+import io.papermc.paper.adventure.PaperAdventure;
|
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
|
+import net.minecraft.commands.CommandSourceStack;
|
|
+import net.minecraft.commands.Commands;
|
|
+import org.purpurmc.purpur.PurpurConfig;
|
|
+import org.purpurmc.purpur.task.RamBarTask;
|
|
+
|
|
+public class RamCommand {
|
|
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
|
+ dispatcher.register(Commands.literal("ram")
|
|
+ .requires(listener -> listener.hasPermission(2, "bukkit.command.ram"))
|
|
+ .executes(context -> {
|
|
+ CommandSourceStack sender = context.getSource();
|
|
+ RamBarTask ramBar = RamBarTask.instance();
|
|
+ sender.sendSuccess(() -> PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(PurpurConfig.ramCommandOutput,
|
|
+ Placeholder.component("allocated", ramBar.format(ramBar.getAllocated())),
|
|
+ Placeholder.component("used", ramBar.format(ramBar.getUsed())),
|
|
+ Placeholder.component("xmx", ramBar.format(ramBar.getXmx())),
|
|
+ Placeholder.component("xms", ramBar.format(ramBar.getXms())),
|
|
+ Placeholder.unparsed("percent", ((int) (ramBar.getPercent() * 100)) + "%")
|
|
+ )), false);
|
|
+ return 1;
|
|
+ })
|
|
+ );
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/command/TPSBarCommand.java b/src/main/java/org/purpurmc/purpur/command/TPSBarCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..d8f9b044107ff7c29a83eb5378aa9f5465ba1995
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/command/TPSBarCommand.java
|
|
@@ -0,0 +1,44 @@
|
|
+package org.purpurmc.purpur.command;
|
|
+
|
|
+import com.mojang.brigadier.CommandDispatcher;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
|
+import net.minecraft.commands.CommandSourceStack;
|
|
+import net.minecraft.commands.Commands;
|
|
+import net.minecraft.commands.arguments.EntityArgument;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import org.purpurmc.purpur.PurpurConfig;
|
|
+import org.purpurmc.purpur.task.TPSBarTask;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.Collections;
|
|
+
|
|
+public class TPSBarCommand {
|
|
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
|
+ dispatcher.register(Commands.literal("tpsbar")
|
|
+ .requires(listener -> listener.hasPermission(2, "bukkit.command.tpsbar"))
|
|
+ .executes(context -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException())))
|
|
+ .then(Commands.argument("targets", EntityArgument.players())
|
|
+ .requires(listener -> listener.hasPermission(2, "bukkit.command.tpsbar.other"))
|
|
+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets")))
|
|
+ )
|
|
+ );
|
|
+ }
|
|
+
|
|
+ private static int execute(CommandSourceStack sender, Collection<ServerPlayer> targets) {
|
|
+ for (ServerPlayer player : targets) {
|
|
+ boolean result = TPSBarTask.instance().togglePlayer(player.getBukkitEntity());
|
|
+ player.tpsBar(result);
|
|
+
|
|
+ Component output = MiniMessage.miniMessage().deserialize(PurpurConfig.tpsbarCommandOutput,
|
|
+ Placeholder.component("onoff", Component.translatable(result ? "options.on" : "options.off")
|
|
+ .color(result ? NamedTextColor.GREEN : NamedTextColor.RED)),
|
|
+ Placeholder.parsed("target", player.getGameProfile().getName()));
|
|
+
|
|
+ sender.sendSuccess(output, false);
|
|
+ }
|
|
+ return targets.size();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/command/UptimeCommand.java b/src/main/java/org/purpurmc/purpur/command/UptimeCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..4bb475099bcf8f05d5f1474e7fbf29c57c2c40cd
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/command/UptimeCommand.java
|
|
@@ -0,0 +1,55 @@
|
|
+package org.purpurmc.purpur.command;
|
|
+
|
|
+import com.mojang.brigadier.CommandDispatcher;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
|
+import net.minecraft.commands.CommandSourceStack;
|
|
+import net.minecraft.commands.Commands;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import org.purpurmc.purpur.PurpurConfig;
|
|
+
|
|
+import java.util.concurrent.TimeUnit;
|
|
+import java.util.function.Function;
|
|
+
|
|
+public class UptimeCommand {
|
|
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
|
+ dispatcher.register(Commands.literal("uptime")
|
|
+ .requires((listener) -> listener.hasPermission(2, "bukkit.command.uptime"))
|
|
+ .executes((context) -> execute(context.getSource()))
|
|
+ );
|
|
+ }
|
|
+
|
|
+ private static int execute(CommandSourceStack sender) {
|
|
+ Data data = new Data();
|
|
+
|
|
+ data.format = PurpurConfig.uptimeFormat;
|
|
+ data.hide = true;
|
|
+ data.millis = System.currentTimeMillis() - MinecraftServer.startTimeMillis;
|
|
+
|
|
+ process(data, "<days>", PurpurConfig.uptimeDay, PurpurConfig.uptimeDays, TimeUnit.DAYS, TimeUnit.MILLISECONDS::toDays);
|
|
+ process(data, "<hours>", PurpurConfig.uptimeHour, PurpurConfig.uptimeHours, TimeUnit.HOURS, TimeUnit.MILLISECONDS::toHours);
|
|
+ process(data, "<minutes>", PurpurConfig.uptimeMinute, PurpurConfig.uptimeMinutes, TimeUnit.MINUTES, TimeUnit.MILLISECONDS::toMinutes);
|
|
+ data.hide = false; // never hide seconds
|
|
+ process(data, "<seconds>", PurpurConfig.uptimeSecond, PurpurConfig.uptimeSeconds, TimeUnit.SECONDS, TimeUnit.MILLISECONDS::toSeconds);
|
|
+
|
|
+ Component output = MiniMessage.miniMessage().deserialize(PurpurConfig.uptimeCommandOutput, Placeholder.unparsed("uptime", data.format));
|
|
+ sender.sendSuccess(output, false);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ private static void process(Data data, String replace, String singular, String plural, TimeUnit unit, Function<Long, Long> func) {
|
|
+ if (data.format.contains(replace)) {
|
|
+ long val = func.apply(data.millis);
|
|
+ if (data.hide) data.hide = val == 0;
|
|
+ if (!data.hide) data.millis -= unit.toMillis(val);
|
|
+ data.format = data.format.replace(replace, data.hide ? "" : String.format(val == 1 ? singular : plural, val));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static class Data {
|
|
+ String format;
|
|
+ boolean hide;
|
|
+ long millis;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/configuration/transformation/VoidDamageHeightMigration.java b/src/main/java/org/purpurmc/purpur/configuration/transformation/VoidDamageHeightMigration.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..a04d23bd98075cd65a24d4de8d18281d1668480f
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/configuration/transformation/VoidDamageHeightMigration.java
|
|
@@ -0,0 +1,67 @@
|
|
+package org.purpurmc.purpur.configuration.transformation;
|
|
+
|
|
+import io.papermc.paper.configuration.Configurations;
|
|
+import io.papermc.paper.configuration.PaperConfigurations;
|
|
+import io.papermc.paper.configuration.type.number.DoubleOr;
|
|
+import java.util.OptionalDouble;
|
|
+import org.checkerframework.checker.nullness.qual.Nullable;
|
|
+import org.purpurmc.purpur.PurpurConfig;
|
|
+import org.spongepowered.configurate.ConfigurateException;
|
|
+import org.spongepowered.configurate.ConfigurationNode;
|
|
+import org.spongepowered.configurate.NodePath;
|
|
+import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
|
+import org.spongepowered.configurate.transformation.TransformAction;
|
|
+
|
|
+import static org.spongepowered.configurate.NodePath.path;
|
|
+
|
|
+public class VoidDamageHeightMigration implements TransformAction {
|
|
+
|
|
+ public static boolean HAS_BEEN_REGISTERED = false;
|
|
+
|
|
+ public static final String ENVIRONMENT_KEY = "environment";
|
|
+ public static final String VOID_DAMAGE_KEY = "void-damage-amount";
|
|
+ public static final String VOID_DAMAGE_MIN_HEIGHT_OFFSET_KEY = "void-damage-min-build-height-offset";
|
|
+ public static final double DEFAULT_VOID_DAMAGE_HEIGHT = -64.0D;
|
|
+ public static final double DEFAULT_VOID_DAMAGE = 4.0D;
|
|
+
|
|
+ private final String worldName;
|
|
+
|
|
+ private VoidDamageHeightMigration(String worldName) {
|
|
+ this.worldName = PaperConfigurations.WORLD_DEFAULTS.equals(worldName) ? "default" : worldName;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object @Nullable [] visitPath(final NodePath path, final ConfigurationNode value) throws ConfigurateException {
|
|
+ String purpurVoidDamageHeightPath = "world-settings." + this.worldName + ".gameplay-mechanics.void-damage-height";
|
|
+ ConfigurationNode voidDamageMinHeightOffsetNode = value.node(ENVIRONMENT_KEY, VOID_DAMAGE_MIN_HEIGHT_OFFSET_KEY);
|
|
+ if (PurpurConfig.config.contains(purpurVoidDamageHeightPath)) {
|
|
+ double purpurVoidDamageHeight = PurpurConfig.config.getDouble(purpurVoidDamageHeightPath);
|
|
+ if (purpurVoidDamageHeight != DEFAULT_VOID_DAMAGE_HEIGHT && (voidDamageMinHeightOffsetNode.empty() || voidDamageMinHeightOffsetNode.getDouble() == DEFAULT_VOID_DAMAGE_HEIGHT)) {
|
|
+ voidDamageMinHeightOffsetNode.raw(null);
|
|
+ voidDamageMinHeightOffsetNode.set(purpurVoidDamageHeight);
|
|
+ }
|
|
+ PurpurConfig.config.set(purpurVoidDamageHeightPath, null);
|
|
+ }
|
|
+
|
|
+ String purpurVoidDamagePath = "world-settings." + this.worldName + ".gameplay-mechanics.void-damage-dealt";
|
|
+ ConfigurationNode voidDamageNode = value.node(ENVIRONMENT_KEY, VOID_DAMAGE_KEY);
|
|
+ if (PurpurConfig.config.contains(purpurVoidDamagePath)) {
|
|
+ double purpurVoidDamage = PurpurConfig.config.getDouble(purpurVoidDamagePath);
|
|
+ if (purpurVoidDamage != DEFAULT_VOID_DAMAGE && (voidDamageNode.empty() || voidDamageNode.getDouble() == DEFAULT_VOID_DAMAGE)) {
|
|
+ voidDamageNode.raw(null);
|
|
+ voidDamageNode.set(new DoubleOr.Disabled(OptionalDouble.of(purpurVoidDamage)));
|
|
+ }
|
|
+ PurpurConfig.config.set(purpurVoidDamagePath, null);
|
|
+ }
|
|
+
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ public static void apply(final ConfigurationTransformation.Builder builder, final Configurations.ContextMap contextMap) {
|
|
+ if (PurpurConfig.version < 36) {
|
|
+ HAS_BEEN_REGISTERED = true;
|
|
+ builder.addAction(path(), new VoidDamageHeightMigration(contextMap.require(Configurations.WORLD_NAME)));
|
|
+ }
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/controller/FlyingMoveControllerWASD.java b/src/main/java/org/purpurmc/purpur/controller/FlyingMoveControllerWASD.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..ed494e0ad278813a0eb261101447b84cca3ad7aa
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/controller/FlyingMoveControllerWASD.java
|
|
@@ -0,0 +1,71 @@
|
|
+package org.purpurmc.purpur.controller;
|
|
+
|
|
+import net.minecraft.world.entity.Mob;
|
|
+import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+
|
|
+public class FlyingMoveControllerWASD extends MoveControllerWASD {
|
|
+ protected final float groundSpeedModifier;
|
|
+ protected final float flyingSpeedModifier;
|
|
+ protected int tooHighCooldown = 0;
|
|
+ protected boolean setNoGravityFlag;
|
|
+
|
|
+ public FlyingMoveControllerWASD(Mob entity) {
|
|
+ this(entity, 1.0F);
|
|
+ }
|
|
+
|
|
+ public FlyingMoveControllerWASD(Mob entity, float groundSpeedModifier) {
|
|
+ this(entity, groundSpeedModifier, 1.0F, true);
|
|
+ }
|
|
+
|
|
+ public FlyingMoveControllerWASD(Mob entity, float groundSpeedModifier, float flyingSpeedModifier) {
|
|
+ this(entity, groundSpeedModifier, flyingSpeedModifier, true);
|
|
+ }
|
|
+
|
|
+ public FlyingMoveControllerWASD(Mob entity, float groundSpeedModifier, float flyingSpeedModifier, boolean setNoGravityFlag) {
|
|
+ super(entity);
|
|
+ this.groundSpeedModifier = groundSpeedModifier;
|
|
+ this.flyingSpeedModifier = flyingSpeedModifier;
|
|
+ this.setNoGravityFlag = setNoGravityFlag;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void purpurTick(Player rider) {
|
|
+ float forward = Math.max(0.0F, rider.getForwardMot());
|
|
+ float vertical = forward == 0.0F ? 0.0F : -(rider.xRotO / 45.0F);
|
|
+ float strafe = rider.getStrafeMot();
|
|
+
|
|
+ if (rider.jumping && spacebarEvent(entity)) {
|
|
+ entity.onSpacebar();
|
|
+ }
|
|
+
|
|
+ if (entity.getY() >= entity.getMaxY() || --tooHighCooldown > 0) {
|
|
+ if (tooHighCooldown <= 0) {
|
|
+ tooHighCooldown = 20;
|
|
+ }
|
|
+ entity.setDeltaMovement(entity.getDeltaMovement().add(0.0D, -0.05D, 0.0D));
|
|
+ vertical = 0.0F;
|
|
+ }
|
|
+
|
|
+ setSpeedModifier(entity.getAttributeValue(Attributes.MOVEMENT_SPEED));
|
|
+ float speed = (float) getSpeedModifier();
|
|
+
|
|
+ if (entity.onGround) {
|
|
+ speed *= groundSpeedModifier; // TODO = fix this!
|
|
+ } else {
|
|
+ speed *= flyingSpeedModifier;
|
|
+ }
|
|
+
|
|
+ if (setNoGravityFlag) {
|
|
+ entity.setNoGravity(forward > 0);
|
|
+ }
|
|
+
|
|
+ entity.setSpeed(speed);
|
|
+ entity.setVerticalMot(vertical);
|
|
+ entity.setStrafeMot(strafe);
|
|
+ entity.setForwardMot(forward);
|
|
+
|
|
+ setForward(entity.getForwardMot());
|
|
+ setStrafe(entity.getStrafeMot());
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/controller/FlyingWithSpacebarMoveControllerWASD.java b/src/main/java/org/purpurmc/purpur/controller/FlyingWithSpacebarMoveControllerWASD.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..9383c07fa53141127106a1f289366a040960d52e
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/controller/FlyingWithSpacebarMoveControllerWASD.java
|
|
@@ -0,0 +1,63 @@
|
|
+package org.purpurmc.purpur.controller;
|
|
+
|
|
+import net.minecraft.world.entity.Mob;
|
|
+import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+import net.minecraft.world.phys.Vec3;
|
|
+
|
|
+public class FlyingWithSpacebarMoveControllerWASD extends FlyingMoveControllerWASD {
|
|
+ public FlyingWithSpacebarMoveControllerWASD(Mob entity) {
|
|
+ super(entity);
|
|
+ }
|
|
+
|
|
+ public FlyingWithSpacebarMoveControllerWASD(Mob entity, float groundSpeedModifier) {
|
|
+ super(entity, groundSpeedModifier);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void purpurTick(Player rider) {
|
|
+ float forward = rider.getForwardMot();
|
|
+ float strafe = rider.getStrafeMot() * 0.5F;
|
|
+ float vertical = 0;
|
|
+
|
|
+ if (forward < 0.0F) {
|
|
+ forward *= 0.5F;
|
|
+ strafe *= 0.5F;
|
|
+ }
|
|
+
|
|
+ float speed = (float) entity.getAttributeValue(Attributes.MOVEMENT_SPEED);
|
|
+
|
|
+ if (entity.onGround) {
|
|
+ speed *= groundSpeedModifier;
|
|
+ }
|
|
+
|
|
+ if (rider.jumping && spacebarEvent(entity) && !entity.onSpacebar()) {
|
|
+ entity.setNoGravity(true);
|
|
+ vertical = 1.0F;
|
|
+ } else {
|
|
+ entity.setNoGravity(false);
|
|
+ }
|
|
+
|
|
+ if (entity.getY() >= entity.getMaxY() || --tooHighCooldown > 0) {
|
|
+ if (tooHighCooldown <= 0) {
|
|
+ tooHighCooldown = 20;
|
|
+ }
|
|
+ entity.setDeltaMovement(entity.getDeltaMovement().add(0.0D, -0.2D, 0.0D));
|
|
+ vertical = 0.0F;
|
|
+ }
|
|
+
|
|
+ setSpeedModifier(speed);
|
|
+ entity.setSpeed((float) getSpeedModifier());
|
|
+ entity.setVerticalMot(vertical);
|
|
+ entity.setStrafeMot(strafe);
|
|
+ entity.setForwardMot(forward);
|
|
+
|
|
+ setForward(entity.getForwardMot());
|
|
+ setStrafe(entity.getStrafeMot());
|
|
+
|
|
+ Vec3 mot = entity.getDeltaMovement();
|
|
+ if (mot.y > 0.2D) {
|
|
+ entity.setDeltaMovement(mot.x, 0.2D, mot.z);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/controller/LookControllerWASD.java b/src/main/java/org/purpurmc/purpur/controller/LookControllerWASD.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..dd219518150ca90f89ad238904fd4095efe032d8
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/controller/LookControllerWASD.java
|
|
@@ -0,0 +1,79 @@
|
|
+package org.purpurmc.purpur.controller;
|
|
+
|
|
+
|
|
+import net.minecraft.network.protocol.game.ClientboundMoveEntityPacket;
|
|
+import net.minecraft.server.level.ServerLevel;
|
|
+import net.minecraft.util.Mth;
|
|
+import net.minecraft.world.entity.Mob;
|
|
+import net.minecraft.world.entity.ai.control.LookControl;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+
|
|
+public class LookControllerWASD extends LookControl {
|
|
+ protected final Mob entity;
|
|
+ private float yOffset = 0;
|
|
+ private float xOffset = 0;
|
|
+
|
|
+ public LookControllerWASD(Mob entity) {
|
|
+ super(entity);
|
|
+ this.entity = entity;
|
|
+ }
|
|
+
|
|
+ // tick
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ if (entity.getRider() != null && entity.isControllable()) {
|
|
+ purpurTick(entity.getRider());
|
|
+ } else {
|
|
+ vanillaTick();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ protected void purpurTick(Player rider) {
|
|
+ setYawPitch(rider.getYRot(), rider.getXRot());
|
|
+ }
|
|
+
|
|
+ public void vanillaTick() {
|
|
+ super.tick();
|
|
+ }
|
|
+
|
|
+ public void setYawPitch(float yRot, float xRot) {
|
|
+ entity.setXRot(normalizePitch(xRot + xOffset));
|
|
+ entity.setYRot(normalizeYaw(yRot + yOffset));
|
|
+ entity.setYHeadRot(entity.getYRot());
|
|
+ entity.xRotO = entity.getXRot();
|
|
+ entity.yRotO = entity.getYRot();
|
|
+
|
|
+ ClientboundMoveEntityPacket.PosRot entityPacket = new ClientboundMoveEntityPacket.PosRot(
|
|
+ entity.getId(),
|
|
+ (short) 0, (short) 0, (short) 0,
|
|
+ (byte) Mth.floor(entity.getYRot() * 256.0F / 360.0F),
|
|
+ (byte) Mth.floor(entity.getXRot() * 256.0F / 360.0F),
|
|
+ entity.onGround
|
|
+ );
|
|
+ ((ServerLevel) entity.level()).getChunkSource().broadcast(entity, entityPacket);
|
|
+ }
|
|
+
|
|
+ public void setOffsets(float yaw, float pitch) {
|
|
+ yOffset = yaw;
|
|
+ xOffset = pitch;
|
|
+ }
|
|
+
|
|
+ public float normalizeYaw(float yaw) {
|
|
+ yaw %= 360.0f;
|
|
+ if (yaw >= 180.0f) {
|
|
+ yaw -= 360.0f;
|
|
+ } else if (yaw < -180.0f) {
|
|
+ yaw += 360.0f;
|
|
+ }
|
|
+ return yaw;
|
|
+ }
|
|
+
|
|
+ public float normalizePitch(float pitch) {
|
|
+ if (pitch > 90.0f) {
|
|
+ pitch = 90.0f;
|
|
+ } else if (pitch < -90.0f) {
|
|
+ pitch = -90.0f;
|
|
+ }
|
|
+ return pitch;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/controller/MoveControllerWASD.java b/src/main/java/org/purpurmc/purpur/controller/MoveControllerWASD.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..21fd6ea2a482758a3016e3bc2cdebe2d89267481
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/controller/MoveControllerWASD.java
|
|
@@ -0,0 +1,89 @@
|
|
+package org.purpurmc.purpur.controller;
|
|
+
|
|
+import net.minecraft.world.entity.Mob;
|
|
+import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
+import net.minecraft.world.entity.ai.control.MoveControl;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+import org.purpurmc.purpur.event.entity.RidableSpacebarEvent;
|
|
+
|
|
+public class MoveControllerWASD extends MoveControl {
|
|
+ protected final Mob entity;
|
|
+ private final double speedModifier;
|
|
+
|
|
+ public MoveControllerWASD(Mob entity) {
|
|
+ this(entity, 1.0D);
|
|
+ }
|
|
+
|
|
+ public MoveControllerWASD(Mob entity, double speedModifier) {
|
|
+ super(entity);
|
|
+ this.entity = entity;
|
|
+ this.speedModifier = speedModifier;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasWanted() {
|
|
+ return entity.getRider() != null ? strafeForwards != 0 || strafeRight != 0 : super.hasWanted();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ if (entity.getRider() != null && entity.isControllable()) {
|
|
+ purpurTick(entity.getRider());
|
|
+ } else {
|
|
+ vanillaTick();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void vanillaTick() {
|
|
+ super.tick();
|
|
+ }
|
|
+
|
|
+ public void purpurTick(Player rider) {
|
|
+ float forward = rider.getForwardMot() * 0.5F;
|
|
+ float strafe = rider.getStrafeMot() * 0.25F;
|
|
+
|
|
+ if (forward <= 0.0F) {
|
|
+ forward *= 0.5F;
|
|
+ }
|
|
+
|
|
+ float yawOffset = 0;
|
|
+ if (strafe != 0) {
|
|
+ if (forward == 0) {
|
|
+ yawOffset += strafe > 0 ? -90 : 90;
|
|
+ forward = Math.abs(strafe * 2);
|
|
+ } else {
|
|
+ yawOffset += strafe > 0 ? -30 : 30;
|
|
+ strafe /= 2;
|
|
+ if (forward < 0) {
|
|
+ yawOffset += strafe > 0 ? -110 : 110;
|
|
+ forward *= -1;
|
|
+ }
|
|
+ }
|
|
+ } else if (forward < 0) {
|
|
+ yawOffset -= 180;
|
|
+ forward *= -1;
|
|
+ }
|
|
+
|
|
+ ((LookControllerWASD) entity.getLookControl()).setOffsets(yawOffset, 0);
|
|
+
|
|
+ if (rider.jumping && spacebarEvent(entity) && !entity.onSpacebar() && entity.onGround) {
|
|
+ entity.jumpFromGround();
|
|
+ }
|
|
+
|
|
+ setSpeedModifier(entity.getAttributeValue(Attributes.MOVEMENT_SPEED) * speedModifier);
|
|
+
|
|
+ entity.setSpeed((float) getSpeedModifier());
|
|
+ entity.setForwardMot(forward);
|
|
+
|
|
+ setForward(entity.getForwardMot());
|
|
+ setStrafe(entity.getStrafeMot());
|
|
+ }
|
|
+
|
|
+ public static boolean spacebarEvent(Mob entity) {
|
|
+ if (RidableSpacebarEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
|
+ return new RidableSpacebarEvent(entity.getBukkitEntity()).callEvent();
|
|
+ } else {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/controller/WaterMoveControllerWASD.java b/src/main/java/org/purpurmc/purpur/controller/WaterMoveControllerWASD.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..ba2a37dad43e238e54632975abea8ee6fafaa9e0
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/controller/WaterMoveControllerWASD.java
|
|
@@ -0,0 +1,50 @@
|
|
+package org.purpurmc.purpur.controller;
|
|
+
|
|
+import net.minecraft.world.entity.Mob;
|
|
+import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+
|
|
+public class WaterMoveControllerWASD extends MoveControllerWASD {
|
|
+ private final double speedModifier;
|
|
+
|
|
+ public WaterMoveControllerWASD(Mob entity) {
|
|
+ this(entity, 1.0D);
|
|
+ }
|
|
+
|
|
+ public WaterMoveControllerWASD(Mob entity, double speedModifier) {
|
|
+ super(entity);
|
|
+ this.speedModifier = speedModifier;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void purpurTick(Player rider) {
|
|
+ float forward = rider.getForwardMot();
|
|
+ float strafe = rider.getStrafeMot() * 0.5F; // strafe slower by default
|
|
+ float vertical = -(rider.xRotO / 90);
|
|
+
|
|
+ if (forward == 0.0F) {
|
|
+ // strafe slower if not moving forward
|
|
+ strafe *= 0.5F;
|
|
+ // do not move vertically if not moving forward
|
|
+ vertical = 0.0F;
|
|
+ } else if (forward < 0.0F) {
|
|
+ // water animals can't swim backwards
|
|
+ forward = 0.0F;
|
|
+ vertical = 0.0F;
|
|
+ }
|
|
+
|
|
+ if (rider.jumping && spacebarEvent(entity)) {
|
|
+ entity.onSpacebar();
|
|
+ }
|
|
+
|
|
+ setSpeedModifier(entity.getAttributeValue(Attributes.MOVEMENT_SPEED) * speedModifier);
|
|
+ entity.setSpeed((float) getSpeedModifier() * 0.1F);
|
|
+
|
|
+ entity.setForwardMot(forward * (float) speedModifier);
|
|
+ entity.setStrafeMot(strafe * (float) speedModifier);
|
|
+ entity.setVerticalMot(vertical * (float) speedModifier);
|
|
+
|
|
+ setForward(entity.getForwardMot());
|
|
+ setStrafe(entity.getStrafeMot());
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java b/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..f25abee6dbf99c8d08f8e09db02b41df86115faa
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java
|
|
@@ -0,0 +1,107 @@
|
|
+package org.purpurmc.purpur.entity;
|
|
+
|
|
+import net.minecraft.core.particles.ParticleTypes;
|
|
+import net.minecraft.server.level.ServerLevel;
|
|
+import net.minecraft.util.Mth;
|
|
+import net.minecraft.world.damagesource.DamageSource;
|
|
+import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.world.entity.EntityType;
|
|
+import net.minecraft.world.entity.LivingEntity;
|
|
+import net.minecraft.world.entity.animal.Dolphin;
|
|
+import net.minecraft.world.entity.projectile.LlamaSpit;
|
|
+import net.minecraft.world.entity.projectile.ProjectileUtil;
|
|
+import net.minecraft.world.level.Level;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.phys.BlockHitResult;
|
|
+import net.minecraft.world.phys.EntityHitResult;
|
|
+import net.minecraft.world.phys.HitResult;
|
|
+import net.minecraft.world.phys.Vec3;
|
|
+import org.bukkit.event.entity.EntityRemoveEvent;
|
|
+
|
|
+public class DolphinSpit extends LlamaSpit {
|
|
+ public LivingEntity dolphin;
|
|
+ public int ticksLived;
|
|
+
|
|
+ public DolphinSpit(EntityType<? extends LlamaSpit> type, Level world) {
|
|
+ super(type, world);
|
|
+ }
|
|
+
|
|
+ public DolphinSpit(Level world, Dolphin dolphin) {
|
|
+ this(EntityType.LLAMA_SPIT, world);
|
|
+ setOwner(dolphin.getRider() != null ? dolphin.getRider() : dolphin);
|
|
+ this.dolphin = dolphin;
|
|
+ this.setPos(
|
|
+ dolphin.getX() - (double) (dolphin.getBbWidth() + 1.0F) * 0.5D * (double) Mth.sin(dolphin.yBodyRot * 0.017453292F),
|
|
+ dolphin.getEyeY() - 0.10000000149011612D,
|
|
+ dolphin.getZ() + (double) (dolphin.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(dolphin.yBodyRot * 0.017453292F));
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean canSaveToDisk() {
|
|
+ return false;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ public void tick() {
|
|
+ super_tick();
|
|
+
|
|
+ Vec3 mot = this.getDeltaMovement();
|
|
+ HitResult hitResult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity);
|
|
+
|
|
+ this.preHitTargetOrDeflectSelf(hitResult);
|
|
+
|
|
+ double x = this.getX() + mot.x;
|
|
+ double y = this.getY() + mot.y;
|
|
+ double z = this.getZ() + mot.z;
|
|
+
|
|
+ this.updateRotation();
|
|
+
|
|
+ Vec3 motDouble = mot.scale(2.0);
|
|
+ for (int i = 0; i < 5; i++) {
|
|
+ ((ServerLevel) level()).sendParticles(null, ParticleTypes.BUBBLE,
|
|
+ getX() + random.nextFloat() / 2 - 0.25F,
|
|
+ getY() + random.nextFloat() / 2 - 0.25F,
|
|
+ getZ() + random.nextFloat() / 2 - 0.25F,
|
|
+ 0, motDouble.x(), motDouble.y(), motDouble.z(), 0.1D, true);
|
|
+ }
|
|
+
|
|
+ if (++ticksLived > 20) {
|
|
+ this.discard(EntityRemoveEvent.Cause.DISCARD);
|
|
+ } else {
|
|
+ this.setDeltaMovement(mot.scale(0.99D));
|
|
+ if (!this.isNoGravity()) {
|
|
+ this.setDeltaMovement(this.getDeltaMovement().add(0.0D, -0.06D, 0.0D));
|
|
+ }
|
|
+
|
|
+ this.setPos(x, y, z);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void shoot(double x, double y, double z, float speed, float inaccuracy) {
|
|
+ setDeltaMovement(new Vec3(x, y, z).normalize().add(
|
|
+ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy,
|
|
+ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy,
|
|
+ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy)
|
|
+ .scale(speed));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void onHitEntity(EntityHitResult entityHitResult) {
|
|
+ Entity shooter = this.getOwner();
|
|
+ if (shooter instanceof LivingEntity) {
|
|
+ entityHitResult.getEntity().hurt(entityHitResult.getEntity().damageSources().mobProjectile(this, (LivingEntity) shooter), level().purpurConfig.dolphinSpitDamage);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void onHitBlock(BlockHitResult blockHitResult) {
|
|
+ if (this.hitCancelled) {
|
|
+ return;
|
|
+ }
|
|
+ BlockState state = this.level().getBlockState(blockHitResult.getBlockPos());
|
|
+ state.onProjectileHit(this.level(), state, blockHitResult, this);
|
|
+ this.discard(EntityRemoveEvent.Cause.DISCARD);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java b/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..58957b0bd3cd2c37fd4a6766a02e2506d9f51010
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java
|
|
@@ -0,0 +1,129 @@
|
|
+package org.purpurmc.purpur.entity;
|
|
+
|
|
+import net.minecraft.core.particles.ParticleTypes;
|
|
+import net.minecraft.server.level.ServerLevel;
|
|
+import net.minecraft.util.Mth;
|
|
+import net.minecraft.world.damagesource.DamageSource;
|
|
+import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.world.entity.EntityType;
|
|
+import net.minecraft.world.entity.LivingEntity;
|
|
+import net.minecraft.world.entity.decoration.ArmorStand;
|
|
+import net.minecraft.world.entity.monster.Phantom;
|
|
+import net.minecraft.world.entity.projectile.LlamaSpit;
|
|
+import net.minecraft.world.entity.projectile.ProjectileUtil;
|
|
+import net.minecraft.world.level.Level;
|
|
+import net.minecraft.world.level.block.state.BlockBehaviour;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.phys.BlockHitResult;
|
|
+import net.minecraft.world.phys.EntityHitResult;
|
|
+import net.minecraft.world.phys.HitResult;
|
|
+import net.minecraft.world.phys.Vec3;
|
|
+
|
|
+public class PhantomFlames extends LlamaSpit {
|
|
+ public Phantom phantom;
|
|
+ public int ticksLived;
|
|
+ public boolean canGrief = false;
|
|
+
|
|
+ public PhantomFlames(EntityType<? extends LlamaSpit> type, Level world) {
|
|
+ super(type, world);
|
|
+ }
|
|
+
|
|
+ public PhantomFlames(Level world, Phantom phantom) {
|
|
+ this(EntityType.LLAMA_SPIT, world);
|
|
+ setOwner(phantom.getRider() != null ? phantom.getRider() : phantom);
|
|
+ this.phantom = phantom;
|
|
+ this.setPos(
|
|
+ phantom.getX() - (double) (phantom.getBbWidth() + 1.0F) * 0.5D * (double) Mth.sin(phantom.yBodyRot * 0.017453292F),
|
|
+ phantom.getEyeY() - 0.10000000149011612D,
|
|
+ phantom.getZ() + (double) (phantom.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(phantom.yBodyRot * 0.017453292F));
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ public boolean canSaveToDisk() {
|
|
+ return false;
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
+ public void tick() {
|
|
+ super_tick();
|
|
+
|
|
+ Vec3 mot = this.getDeltaMovement();
|
|
+ HitResult hitResult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity);
|
|
+
|
|
+ this.preHitTargetOrDeflectSelf(hitResult);
|
|
+
|
|
+ double x = this.getX() + mot.x;
|
|
+ double y = this.getY() + mot.y;
|
|
+ double z = this.getZ() + mot.z;
|
|
+
|
|
+ this.updateRotation();
|
|
+
|
|
+ Vec3 motDouble = mot.scale(2.0);
|
|
+ for (int i = 0; i < 5; i++) {
|
|
+ ((ServerLevel) level()).sendParticles(null, ParticleTypes.FLAME,
|
|
+ getX() + random.nextFloat() / 2 - 0.25F,
|
|
+ getY() + random.nextFloat() / 2 - 0.25F,
|
|
+ getZ() + random.nextFloat() / 2 - 0.25F,
|
|
+ 0, motDouble.x(), motDouble.y(), motDouble.z(), 0.1D, true);
|
|
+ }
|
|
+
|
|
+ if (++ticksLived > 20) {
|
|
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
|
+ } else if (this.level().getBlockStates(this.getBoundingBox()).noneMatch(BlockBehaviour.BlockStateBase::isAir)) {
|
|
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
|
+ } else if (this.isInWaterOrBubble()) {
|
|
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
|
+ } else {
|
|
+ this.setDeltaMovement(mot.scale(0.99D));
|
|
+ if (!this.isNoGravity()) {
|
|
+ this.setDeltaMovement(this.getDeltaMovement().add(0.0D, -0.06D, 0.0D));
|
|
+ }
|
|
+
|
|
+ this.setPos(x, y, z);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void shoot(double x, double y, double z, float speed, float inaccuracy) {
|
|
+ setDeltaMovement(new Vec3(x, y, z).normalize().add(
|
|
+ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy,
|
|
+ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy,
|
|
+ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy)
|
|
+ .scale(speed));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void onHitEntity(EntityHitResult entityHitResult) {
|
|
+ Level world = this.level();
|
|
+
|
|
+ if (world instanceof ServerLevel worldserver) {
|
|
+ Entity shooter = this.getOwner();
|
|
+ if (shooter instanceof LivingEntity) {
|
|
+ Entity target = entityHitResult.getEntity();
|
|
+ if (canGrief || (target instanceof LivingEntity && !(target instanceof ArmorStand))) {
|
|
+ boolean hurt = target.hurtServer(worldserver, target.damageSources().mobProjectile(this, (LivingEntity) shooter), worldserver.purpurConfig.phantomFlameDamage);
|
|
+ if (hurt && worldserver.purpurConfig.phantomFlameFireTime > 0) {
|
|
+ target.igniteForSeconds(worldserver.purpurConfig.phantomFlameFireTime);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void onHitBlock(BlockHitResult blockHitResult) {
|
|
+ Level world = this.level();
|
|
+
|
|
+ if (world instanceof ServerLevel worldserver) {
|
|
+ if (this.hitCancelled) {
|
|
+ return;
|
|
+ }
|
|
+ if (this.canGrief) {
|
|
+ BlockState state = worldserver.getBlockState(blockHitResult.getBlockPos());
|
|
+ state.onProjectileHit(worldserver, state, blockHitResult, this);
|
|
+ }
|
|
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/entity/PurpurStoredBee.java b/src/main/java/org/purpurmc/purpur/entity/PurpurStoredBee.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..7608bf0981fa0d37031e51e57e4086cb5ec4c88b
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/entity/PurpurStoredBee.java
|
|
@@ -0,0 +1,106 @@
|
|
+package org.purpurmc.purpur.entity;
|
|
+
|
|
+import io.papermc.paper.adventure.PaperAdventure;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.minecraft.nbt.CompoundTag;
|
|
+import net.minecraft.nbt.Tag;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.world.item.component.CustomData;
|
|
+import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
|
+import org.bukkit.block.EntityBlockStorage;
|
|
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer;
|
|
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry;
|
|
+import org.bukkit.entity.Bee;
|
|
+import org.bukkit.entity.EntityType;
|
|
+import org.bukkit.persistence.PersistentDataContainer;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+
|
|
+import java.util.Locale;
|
|
+
|
|
+public class PurpurStoredBee implements StoredEntity<Bee> {
|
|
+ private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
|
|
+
|
|
+ private final EntityBlockStorage<Bee> blockStorage;
|
|
+ private final BeehiveBlockEntity.BeeData handle;
|
|
+ private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(PurpurStoredBee.DATA_TYPE_REGISTRY);
|
|
+
|
|
+ private Component customName;
|
|
+
|
|
+ public PurpurStoredBee(BeehiveBlockEntity.BeeData data, EntityBlockStorage<Bee> blockStorage) {
|
|
+ this.handle = data;
|
|
+ this.blockStorage = blockStorage;
|
|
+
|
|
+ CompoundTag customData = handle.occupant.entityData().copyTag();
|
|
+ this.customName = customData.contains("CustomName")
|
|
+ ? PaperAdventure.asAdventure(net.minecraft.network.chat.Component.Serializer.fromJson(customData.getString("CustomName"), MinecraftServer.getDefaultRegistryAccess()))
|
|
+ : null;
|
|
+
|
|
+ if(customData.contains("BukkitValues", Tag.TAG_COMPOUND)) {
|
|
+ this.persistentDataContainer.putAll(customData.getCompound("BukkitValues"));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public BeehiveBlockEntity.BeeData getHandle() {
|
|
+ return handle;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @Nullable Component customName() {
|
|
+ return customName;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void customName(@Nullable Component customName) {
|
|
+ this.customName = customName;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @Nullable String getCustomName() {
|
|
+ return PaperAdventure.asPlain(customName, Locale.US);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setCustomName(@Nullable String name) {
|
|
+ customName(name != null ? Component.text(name) : null);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @NotNull PersistentDataContainer getPersistentDataContainer() {
|
|
+ return persistentDataContainer;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasBeenReleased() {
|
|
+ return !blockStorage.getEntities().contains(this);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @Nullable Bee release() {
|
|
+ return blockStorage.releaseEntity(this);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @Nullable EntityBlockStorage<Bee> getBlockStorage() {
|
|
+ if(hasBeenReleased()) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ return blockStorage;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @NotNull EntityType getType() {
|
|
+ return EntityType.BEE;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void update() {
|
|
+ handle.occupant.entityData().copyTag().put("BukkitValues", this.persistentDataContainer.toTagCompound());
|
|
+ if(customName == null) {
|
|
+ handle.occupant.entityData().copyTag().remove("CustomName");
|
|
+ } else {
|
|
+ handle.occupant.entityData().copyTag().putString("CustomName", net.minecraft.network.chat.Component.Serializer.toJson(PaperAdventure.asVanilla(customName), MinecraftServer.getDefaultRegistryAccess()));
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/entity/ai/HasRider.java b/src/main/java/org/purpurmc/purpur/entity/ai/HasRider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..8babdaddd8b33278aea0369dbbeeb445abe45016
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/entity/ai/HasRider.java
|
|
@@ -0,0 +1,20 @@
|
|
+package org.purpurmc.purpur.entity.ai;
|
|
+
|
|
+import net.minecraft.world.entity.Mob;
|
|
+import net.minecraft.world.entity.ai.goal.Goal;
|
|
+
|
|
+import java.util.EnumSet;
|
|
+
|
|
+public class HasRider extends Goal {
|
|
+ public final Mob entity;
|
|
+
|
|
+ public HasRider(Mob entity) {
|
|
+ this.entity = entity;
|
|
+ setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK, Flag.TARGET, Flag.UNKNOWN_BEHAVIOR));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canUse() {
|
|
+ return entity.getRider() != null && entity.isControllable();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/entity/ai/HorseHasRider.java b/src/main/java/org/purpurmc/purpur/entity/ai/HorseHasRider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..432f4f3d82af2f19820890b68d33189a9f2c69f9
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/entity/ai/HorseHasRider.java
|
|
@@ -0,0 +1,17 @@
|
|
+package org.purpurmc.purpur.entity.ai;
|
|
+
|
|
+import net.minecraft.world.entity.animal.horse.AbstractHorse;
|
|
+
|
|
+public class HorseHasRider extends HasRider {
|
|
+ public final AbstractHorse horse;
|
|
+
|
|
+ public HorseHasRider(AbstractHorse entity) {
|
|
+ super(entity);
|
|
+ this.horse = entity;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canUse() {
|
|
+ return super.canUse() && horse.isSaddled();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/entity/ai/LlamaHasRider.java b/src/main/java/org/purpurmc/purpur/entity/ai/LlamaHasRider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..18a95e043cbffa65eeaaf65ff7695e5dc939820c
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/entity/ai/LlamaHasRider.java
|
|
@@ -0,0 +1,17 @@
|
|
+package org.purpurmc.purpur.entity.ai;
|
|
+
|
|
+import net.minecraft.world.entity.animal.horse.Llama;
|
|
+
|
|
+public class LlamaHasRider extends HasRider {
|
|
+ public final Llama llama;
|
|
+
|
|
+ public LlamaHasRider(Llama entity) {
|
|
+ super(entity);
|
|
+ this.llama = entity;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canUse() {
|
|
+ return super.canUse() && llama.isSaddled() && llama.isControllable();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/entity/ai/ReceiveFlower.java b/src/main/java/org/purpurmc/purpur/entity/ai/ReceiveFlower.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..9660716f4162a4441c6e1b0baddef8f5086566c5
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/entity/ai/ReceiveFlower.java
|
|
@@ -0,0 +1,91 @@
|
|
+package org.purpurmc.purpur.entity.ai;
|
|
+
|
|
+import net.minecraft.server.level.ServerLevel;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import net.minecraft.world.InteractionHand;
|
|
+import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.world.entity.ai.goal.Goal;
|
|
+import net.minecraft.world.entity.animal.IronGolem;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.level.block.Blocks;
|
|
+
|
|
+import java.util.EnumSet;
|
|
+import java.util.UUID;
|
|
+
|
|
+public class ReceiveFlower extends Goal {
|
|
+ private final IronGolem irongolem;
|
|
+ private ServerPlayer target;
|
|
+ private int cooldown;
|
|
+
|
|
+ public ReceiveFlower(IronGolem entity) {
|
|
+ this.irongolem = entity;
|
|
+ setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canUse() {
|
|
+ if (this.irongolem.getOfferFlowerTick() > 0) {
|
|
+ return false;
|
|
+ }
|
|
+ if (!this.irongolem.isAngry()) {
|
|
+ return false;
|
|
+ }
|
|
+ UUID uuid = this.irongolem.getPersistentAngerTarget();
|
|
+ if (uuid == null) {
|
|
+ return false;
|
|
+ }
|
|
+ Entity target = ((ServerLevel) this.irongolem.level()).getEntity(uuid);
|
|
+ if (!(target instanceof ServerPlayer player)) {
|
|
+ return false;
|
|
+ }
|
|
+ InteractionHand hand = getPoppyHand(player);
|
|
+ if (hand == null) {
|
|
+ return false;
|
|
+ }
|
|
+ removeFlower(player, hand);
|
|
+ this.target = player;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canContinueToUse() {
|
|
+ return this.cooldown > 0;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void start() {
|
|
+ this.cooldown = 100;
|
|
+ this.irongolem.stopBeingAngry();
|
|
+ this.irongolem.offerFlower(true);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void stop() {
|
|
+ this.irongolem.offerFlower(false);
|
|
+ this.target = null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ this.irongolem.getLookControl().setLookAt(this.target, 30.0F, 30.0F);
|
|
+ --this.cooldown;
|
|
+ }
|
|
+
|
|
+ private InteractionHand getPoppyHand(ServerPlayer player) {
|
|
+ if (isPoppy(player.getMainHandItem())) {
|
|
+ return InteractionHand.MAIN_HAND;
|
|
+ }
|
|
+ if (isPoppy(player.getOffhandItem())) {
|
|
+ return InteractionHand.OFF_HAND;
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ private void removeFlower(ServerPlayer player, InteractionHand hand) {
|
|
+ player.setItemInHand(hand, ItemStack.EMPTY);
|
|
+ }
|
|
+
|
|
+ private boolean isPoppy(ItemStack item) {
|
|
+ return item.getItem() == Blocks.POPPY.asItem();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/gui/GUIColor.java b/src/main/java/org/purpurmc/purpur/gui/GUIColor.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..550222758bf0e7deff26a6e813a860b7be365e87
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/gui/GUIColor.java
|
|
@@ -0,0 +1,58 @@
|
|
+package org.purpurmc.purpur.gui;
|
|
+
|
|
+import net.md_5.bungee.api.ChatColor;
|
|
+
|
|
+import java.awt.Color;
|
|
+import java.util.HashMap;
|
|
+import java.util.Map;
|
|
+
|
|
+public enum GUIColor {
|
|
+ BLACK(ChatColor.BLACK, new Color(0x000000)),
|
|
+ DARK_BLUE(ChatColor.DARK_BLUE, new Color(0x0000AA)),
|
|
+ DARK_GREEN(ChatColor.DARK_GREEN, new Color(0x00AA00)),
|
|
+ DARK_AQUA(ChatColor.DARK_AQUA, new Color(0x009999)),
|
|
+ DARK_RED(ChatColor.DARK_RED, new Color(0xAA0000)),
|
|
+ DARK_PURPLE(ChatColor.DARK_PURPLE, new Color(0xAA00AA)),
|
|
+ GOLD(ChatColor.GOLD, new Color(0xBB8800)),
|
|
+ GRAY(ChatColor.GRAY, new Color(0x888888)),
|
|
+ DARK_GRAY(ChatColor.DARK_GRAY, new Color(0x444444)),
|
|
+ BLUE(ChatColor.BLUE, new Color(0x5555FF)),
|
|
+ GREEN(ChatColor.GREEN, new Color(0x55FF55)),
|
|
+ AQUA(ChatColor.AQUA, new Color(0x55DDDD)),
|
|
+ RED(ChatColor.RED, new Color(0xFF5555)),
|
|
+ LIGHT_PURPLE(ChatColor.LIGHT_PURPLE, new Color(0xFF55FF)),
|
|
+ YELLOW(ChatColor.YELLOW, new Color(0xFFBB00)),
|
|
+ WHITE(ChatColor.WHITE, new Color(0xBBBBBB));
|
|
+
|
|
+ private final ChatColor chat;
|
|
+ private final Color color;
|
|
+
|
|
+ private static final Map<ChatColor, GUIColor> BY_CHAT = new HashMap<>();
|
|
+
|
|
+ GUIColor(ChatColor chat, Color color) {
|
|
+ this.chat = chat;
|
|
+ this.color = color;
|
|
+ }
|
|
+
|
|
+ public Color getColor() {
|
|
+ return color;
|
|
+ }
|
|
+
|
|
+ public ChatColor getChatColor() {
|
|
+ return chat;
|
|
+ }
|
|
+
|
|
+ public String getCode() {
|
|
+ return chat.toString();
|
|
+ }
|
|
+
|
|
+ public static GUIColor getColor(ChatColor chat) {
|
|
+ return BY_CHAT.get(chat);
|
|
+ }
|
|
+
|
|
+ static {
|
|
+ for (GUIColor color : values()) {
|
|
+ BY_CHAT.put(color.chat, color);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/gui/JColorTextPane.java b/src/main/java/org/purpurmc/purpur/gui/JColorTextPane.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..d75fb5e77eff27d86135ed7d605dbc250b660f7d
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/gui/JColorTextPane.java
|
|
@@ -0,0 +1,83 @@
|
|
+package org.purpurmc.purpur.gui;
|
|
+
|
|
+import com.google.common.collect.Sets;
|
|
+import javax.swing.UIManager;
|
|
+import net.md_5.bungee.api.chat.BaseComponent;
|
|
+import net.md_5.bungee.api.chat.TextComponent;
|
|
+
|
|
+import javax.swing.JTextPane;
|
|
+import javax.swing.Timer;
|
|
+import javax.swing.text.AttributeSet;
|
|
+import javax.swing.text.BadLocationException;
|
|
+import javax.swing.text.SimpleAttributeSet;
|
|
+import javax.swing.text.StyleConstants;
|
|
+import javax.swing.text.StyleContext;
|
|
+import java.util.Set;
|
|
+
|
|
+public class JColorTextPane extends JTextPane {
|
|
+ private static final GUIColor DEFAULT_COLOR;
|
|
+ static {
|
|
+ DEFAULT_COLOR = UIManager.getSystemLookAndFeelClassName().equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel")
|
|
+ ? GUIColor.WHITE : GUIColor.BLACK;
|
|
+ }
|
|
+
|
|
+
|
|
+ public void append(String msg) {
|
|
+ // TODO: update to use adventure instead
|
|
+ BaseComponent[] components = TextComponent.fromLegacyText(DEFAULT_COLOR.getCode() + msg, DEFAULT_COLOR.getChatColor());
|
|
+ for (BaseComponent component : components) {
|
|
+ String text = component.toPlainText();
|
|
+ if (text == null || text.isEmpty()) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ GUIColor guiColor = GUIColor.getColor(component.getColor());
|
|
+
|
|
+ StyleContext context = StyleContext.getDefaultStyleContext();
|
|
+ AttributeSet attr = context.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, guiColor.getColor());
|
|
+ attr = context.addAttribute(attr, StyleConstants.CharacterConstants.Bold, component.isBold() || guiColor != DEFAULT_COLOR);
|
|
+ attr = context.addAttribute(attr, StyleConstants.CharacterConstants.Italic, component.isItalic());
|
|
+ attr = context.addAttribute(attr, StyleConstants.CharacterConstants.Underline, component.isUnderlined());
|
|
+ attr = context.addAttribute(attr, StyleConstants.CharacterConstants.StrikeThrough, component.isStrikethrough());
|
|
+ //attr = context.addAttribute(attr, StyleConstants.CharacterConstants.Blink, component.isObfuscated()); // no such thing as Blink, sadly
|
|
+
|
|
+ try {
|
|
+ int pos = getDocument().getLength();
|
|
+ getDocument().insertString(pos, text, attr);
|
|
+
|
|
+ if (component.isObfuscated()) {
|
|
+ // dirty hack to blink some text
|
|
+ Blink blink = new Blink(pos, text.length(), attr, context.addAttribute(attr, StyleConstants.Foreground, getBackground()));
|
|
+ BLINKS.add(blink);
|
|
+ }
|
|
+ } catch (BadLocationException ignore) {
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static final Set<Blink> BLINKS = Sets.newHashSet();
|
|
+ private static boolean SYNC_BLINK;
|
|
+
|
|
+ static {
|
|
+ new Timer(500, e -> {
|
|
+ SYNC_BLINK = !SYNC_BLINK;
|
|
+ BLINKS.forEach(Blink::blink);
|
|
+ }).start();
|
|
+ }
|
|
+
|
|
+ public class Blink {
|
|
+ private final int start, length;
|
|
+ private final AttributeSet attr1, attr2;
|
|
+
|
|
+ private Blink(int start, int length, AttributeSet attr1, AttributeSet attr2) {
|
|
+ this.start = start;
|
|
+ this.length = length;
|
|
+ this.attr1 = attr1;
|
|
+ this.attr2 = attr2;
|
|
+ }
|
|
+
|
|
+ private void blink() {
|
|
+ getStyledDocument().setCharacterAttributes(start, length, SYNC_BLINK ? attr1 : attr2, true);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/item/GlowBerryItem.java b/src/main/java/org/purpurmc/purpur/item/GlowBerryItem.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..b257f35caa13b660854cf17f41fd8fba1d56c458
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/item/GlowBerryItem.java
|
|
@@ -0,0 +1,26 @@
|
|
+package org.purpurmc.purpur.item;
|
|
+
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import net.minecraft.world.effect.MobEffectInstance;
|
|
+import net.minecraft.world.effect.MobEffects;
|
|
+import net.minecraft.world.entity.LivingEntity;
|
|
+import net.minecraft.world.item.BlockItem;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.level.Level;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import org.bukkit.event.entity.EntityPotionEffectEvent;
|
|
+
|
|
+public class GlowBerryItem extends BlockItem {
|
|
+ public GlowBerryItem(Block block, Properties settings) {
|
|
+ super(block, settings);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ItemStack finishUsingItem(ItemStack stack, Level world, LivingEntity user) {
|
|
+ ItemStack result = super.finishUsingItem(stack, world, user);
|
|
+ if (world.purpurConfig.glowBerriesEatGlowDuration > 0 && user instanceof ServerPlayer player) {
|
|
+ player.addEffect(new MobEffectInstance(MobEffects.GLOWING, world.purpurConfig.glowBerriesEatGlowDuration), EntityPotionEffectEvent.Cause.FOOD);
|
|
+ }
|
|
+ return result;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/item/SpawnerItem.java b/src/main/java/org/purpurmc/purpur/item/SpawnerItem.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..ed50cb2115401c9039df4136caf5a087a5f5991c
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/item/SpawnerItem.java
|
|
@@ -0,0 +1,40 @@
|
|
+package org.purpurmc.purpur.item;
|
|
+
|
|
+import net.minecraft.core.BlockPos;
|
|
+import net.minecraft.core.component.DataComponents;
|
|
+import net.minecraft.nbt.CompoundTag;
|
|
+import net.minecraft.world.entity.EntityType;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+import net.minecraft.world.item.BlockItem;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.item.component.CustomData;
|
|
+import net.minecraft.world.level.Level;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import net.minecraft.world.level.block.entity.BlockEntity;
|
|
+import net.minecraft.world.level.block.entity.SpawnerBlockEntity;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+
|
|
+public class SpawnerItem extends BlockItem {
|
|
+
|
|
+ public SpawnerItem(Block block, Properties settings) {
|
|
+ super(block, settings);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected boolean updateCustomBlockEntityTag(BlockPos pos, Level level, Player player, ItemStack stack, BlockState state) {
|
|
+ boolean handled = super.updateCustomBlockEntityTag(pos, level, player, stack, state);
|
|
+ if (level.purpurConfig.silkTouchEnabled && player.getBukkitEntity().hasPermission("purpur.place.spawners")) {
|
|
+ BlockEntity blockEntity = level.getBlockEntity(pos);
|
|
+ if (blockEntity instanceof SpawnerBlockEntity spawner) {
|
|
+ CompoundTag customData = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
|
|
+ if (customData.contains("Purpur.mob_type")) {
|
|
+ EntityType.byString(customData.getString("Purpur.mob_type")).ifPresent(type -> spawner.getSpawner().setEntityId(type, level, level.random, pos));
|
|
+ } else if (customData.contains("Purpur.SpawnData")) {
|
|
+ net.minecraft.world.level.SpawnData.CODEC.parse(net.minecraft.nbt.NbtOps.INSTANCE, customData.getCompound("Purpur.SpawnData")).result()
|
|
+ .ifPresent(spawnData -> spawner.getSpawner().nextSpawnData = spawnData);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return handled;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/network/ClientboundBeehivePayload.java b/src/main/java/org/purpurmc/purpur/network/ClientboundBeehivePayload.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..793a3ea45fe04e84725926f17615c26e008b0ce4
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/network/ClientboundBeehivePayload.java
|
|
@@ -0,0 +1,27 @@
|
|
+package org.purpurmc.purpur.network;
|
|
+
|
|
+import net.minecraft.core.BlockPos;
|
|
+import net.minecraft.network.FriendlyByteBuf;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+
|
|
+public record ClientboundBeehivePayload(BlockPos pos, int numOfBees) implements CustomPacketPayload {
|
|
+ public static final StreamCodec<FriendlyByteBuf, ClientboundBeehivePayload> STREAM_CODEC = CustomPacketPayload.codec(ClientboundBeehivePayload::write, ClientboundBeehivePayload::new);
|
|
+ public static final Type<ClientboundBeehivePayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath("purpur", "beehive_s2c"));
|
|
+
|
|
+ public ClientboundBeehivePayload(FriendlyByteBuf friendlyByteBuf) {
|
|
+ this(friendlyByteBuf.readBlockPos(), friendlyByteBuf.readInt());
|
|
+ }
|
|
+
|
|
+ private void write(FriendlyByteBuf friendlyByteBuf) {
|
|
+ friendlyByteBuf.writeBlockPos(this.pos);
|
|
+ friendlyByteBuf.writeInt(this.numOfBees);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @NotNull Type<? extends CustomPacketPayload> type() {
|
|
+ return TYPE;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java b/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..fa72769e06061609e1e658a0250e99c8cb026c0e
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java
|
|
@@ -0,0 +1,26 @@
|
|
+package org.purpurmc.purpur.network;
|
|
+
|
|
+import net.minecraft.core.BlockPos;
|
|
+import net.minecraft.network.FriendlyByteBuf;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+
|
|
+public record ServerboundBeehivePayload(BlockPos pos) implements CustomPacketPayload {
|
|
+ public static final StreamCodec<FriendlyByteBuf, ServerboundBeehivePayload> STREAM_CODEC = CustomPacketPayload.codec(ServerboundBeehivePayload::write, ServerboundBeehivePayload::new);
|
|
+ public static final Type<ServerboundBeehivePayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath("purpur", "beehive_c2s"));
|
|
+
|
|
+ public ServerboundBeehivePayload(FriendlyByteBuf friendlyByteBuf) {
|
|
+ this(friendlyByteBuf.readBlockPos());
|
|
+ }
|
|
+
|
|
+ private void write(FriendlyByteBuf friendlyByteBuf) {
|
|
+ friendlyByteBuf.writeBlockPos(this.pos);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @NotNull Type<? extends CustomPacketPayload> type() {
|
|
+ return TYPE;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java b/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..664f9d5e1ce5e2787bf699bd11758b9e3aa8ed3a
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java
|
|
@@ -0,0 +1,67 @@
|
|
+package org.purpurmc.purpur.task;
|
|
+
|
|
+import io.netty.buffer.Unpooled;
|
|
+import net.minecraft.network.FriendlyByteBuf;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.BlockEntity;
|
|
+import org.bukkit.Bukkit;
|
|
+import org.bukkit.craftbukkit.entity.CraftPlayer;
|
|
+import org.bukkit.entity.Player;
|
|
+import org.bukkit.plugin.PluginBase;
|
|
+import org.bukkit.plugin.messaging.PluginMessageListener;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.purpurmc.purpur.network.ClientboundBeehivePayload;
|
|
+import org.purpurmc.purpur.network.ServerboundBeehivePayload;
|
|
+import org.purpurmc.purpur.util.MinecraftInternalPlugin;
|
|
+
|
|
+public class BeehiveTask implements PluginMessageListener {
|
|
+
|
|
+ private static BeehiveTask instance;
|
|
+
|
|
+ public static BeehiveTask instance() {
|
|
+ if (instance == null) {
|
|
+ instance = new BeehiveTask();
|
|
+ }
|
|
+ return instance;
|
|
+ }
|
|
+
|
|
+ private final PluginBase plugin = new MinecraftInternalPlugin();
|
|
+
|
|
+ private BeehiveTask() {
|
|
+ }
|
|
+
|
|
+ public void register() {
|
|
+ Bukkit.getMessenger().registerOutgoingPluginChannel(this.plugin, ClientboundBeehivePayload.TYPE.id().toString());
|
|
+ Bukkit.getMessenger().registerIncomingPluginChannel(this.plugin, ServerboundBeehivePayload.TYPE.id().toString(), this);
|
|
+ }
|
|
+
|
|
+ public void unregister() {
|
|
+ Bukkit.getMessenger().unregisterOutgoingPluginChannel(this.plugin, ClientboundBeehivePayload.TYPE.id().toString());
|
|
+ Bukkit.getMessenger().unregisterIncomingPluginChannel(this.plugin, ServerboundBeehivePayload.TYPE.id().toString());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte[] bytes) {
|
|
+ FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.copiedBuffer(bytes));
|
|
+ ServerboundBeehivePayload payload = ServerboundBeehivePayload.STREAM_CODEC.decode(byteBuf);
|
|
+
|
|
+ ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
|
|
+
|
|
+ // targeted block info max range specified in client at net.minecraft.client.gui.hud.DebugHud#render
|
|
+ if (!payload.pos().getCenter().closerThan(serverPlayer.position(), 20)) return; // Targeted Block info max range is 20
|
|
+ if (serverPlayer.level().getChunkIfLoaded(payload.pos()) == null) return;
|
|
+
|
|
+ BlockEntity blockEntity = serverPlayer.level().getBlockEntity(payload.pos());
|
|
+ if (!(blockEntity instanceof BeehiveBlockEntity beehive)) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ClientboundBeehivePayload customPacketPayload = new ClientboundBeehivePayload(payload.pos(), beehive.getOccupantCount());
|
|
+ FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer());
|
|
+ ClientboundBeehivePayload.STREAM_CODEC.encode(friendlyByteBuf, customPacketPayload);
|
|
+ byte[] byteArray = new byte[friendlyByteBuf.readableBytes()];
|
|
+ friendlyByteBuf.readBytes(byteArray);
|
|
+ player.sendPluginMessage(this.plugin, customPacketPayload.type().id().toString(), byteArray);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/task/BossBarTask.java b/src/main/java/org/purpurmc/purpur/task/BossBarTask.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..3c3d4cd52db93b97a40321030a70ebc282c9636b
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/task/BossBarTask.java
|
|
@@ -0,0 +1,121 @@
|
|
+package org.purpurmc.purpur.task;
|
|
+
|
|
+import net.kyori.adventure.bossbar.BossBar;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import org.bukkit.Bukkit;
|
|
+import org.bukkit.entity.Player;
|
|
+import org.bukkit.scheduler.BukkitRunnable;
|
|
+
|
|
+import java.util.HashMap;
|
|
+import java.util.HashSet;
|
|
+import java.util.Iterator;
|
|
+import java.util.Map;
|
|
+import java.util.UUID;
|
|
+import org.purpurmc.purpur.util.MinecraftInternalPlugin;
|
|
+
|
|
+public abstract class BossBarTask extends BukkitRunnable {
|
|
+ private final Map<UUID, BossBar> bossbars = new HashMap<>();
|
|
+ private boolean started;
|
|
+
|
|
+ abstract BossBar createBossBar();
|
|
+
|
|
+ abstract void updateBossBar(BossBar bossbar, Player player);
|
|
+
|
|
+ @Override
|
|
+ public void run() {
|
|
+ Iterator<Map.Entry<UUID, BossBar>> iter = bossbars.entrySet().iterator();
|
|
+ while (iter.hasNext()) {
|
|
+ Map.Entry<UUID, BossBar> entry = iter.next();
|
|
+ Player player = Bukkit.getPlayer(entry.getKey());
|
|
+ if (player == null) {
|
|
+ iter.remove();
|
|
+ continue;
|
|
+ }
|
|
+ updateBossBar(entry.getValue(), player);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void cancel() {
|
|
+ super.cancel();
|
|
+ new HashSet<>(this.bossbars.keySet()).forEach(uuid -> {
|
|
+ Player player = Bukkit.getPlayer(uuid);
|
|
+ if (player != null) {
|
|
+ removePlayer(player);
|
|
+ }
|
|
+ });
|
|
+ this.bossbars.clear();
|
|
+ }
|
|
+
|
|
+ public boolean removePlayer(Player player) {
|
|
+ BossBar bossbar = this.bossbars.remove(player.getUniqueId());
|
|
+ if (bossbar != null) {
|
|
+ player.hideBossBar(bossbar);
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ public void addPlayer(Player player) {
|
|
+ removePlayer(player);
|
|
+ BossBar bossbar = createBossBar();
|
|
+ this.bossbars.put(player.getUniqueId(), bossbar);
|
|
+ this.updateBossBar(bossbar, player);
|
|
+ player.showBossBar(bossbar);
|
|
+ }
|
|
+
|
|
+ public boolean hasPlayer(UUID uuid) {
|
|
+ return this.bossbars.containsKey(uuid);
|
|
+ }
|
|
+
|
|
+ public boolean togglePlayer(Player player) {
|
|
+ if (removePlayer(player)) {
|
|
+ return false;
|
|
+ }
|
|
+ addPlayer(player);
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ public void start() {
|
|
+ stop();
|
|
+ this.runTaskTimerAsynchronously(new MinecraftInternalPlugin(), 1, 1);
|
|
+ started = true;
|
|
+ }
|
|
+
|
|
+ public void stop() {
|
|
+ if (started) {
|
|
+ cancel();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static void startAll() {
|
|
+ RamBarTask.instance().start();
|
|
+ TPSBarTask.instance().start();
|
|
+ CompassTask.instance().start();
|
|
+ }
|
|
+
|
|
+ public static void stopAll() {
|
|
+ RamBarTask.instance().stop();
|
|
+ TPSBarTask.instance().stop();
|
|
+ CompassTask.instance().stop();
|
|
+ }
|
|
+
|
|
+ public static void addToAll(ServerPlayer player) {
|
|
+ Player bukkit = player.getBukkitEntity();
|
|
+ if (player.ramBar()) {
|
|
+ RamBarTask.instance().addPlayer(bukkit);
|
|
+ }
|
|
+ if (player.tpsBar()) {
|
|
+ TPSBarTask.instance().addPlayer(bukkit);
|
|
+ }
|
|
+ if (player.compassBar()) {
|
|
+ CompassTask.instance().addPlayer(bukkit);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static void removeFromAll(Player player) {
|
|
+ RamBarTask.instance().removePlayer(player);
|
|
+ TPSBarTask.instance().removePlayer(player);
|
|
+ CompassTask.instance().removePlayer(player);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/task/CompassTask.java b/src/main/java/org/purpurmc/purpur/task/CompassTask.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..bece7eefc8ba8822b433835526251d2fb916c025
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/task/CompassTask.java
|
|
@@ -0,0 +1,68 @@
|
|
+package org.purpurmc.purpur.task;
|
|
+
|
|
+import net.kyori.adventure.bossbar.BossBar;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.world.item.Items;
|
|
+import org.bukkit.entity.Player;
|
|
+import org.purpurmc.purpur.PurpurConfig;
|
|
+
|
|
+public class CompassTask extends BossBarTask {
|
|
+ private static CompassTask instance;
|
|
+
|
|
+ private int tick = 0;
|
|
+
|
|
+ public static CompassTask instance() {
|
|
+ if (instance == null) {
|
|
+ instance = new CompassTask();
|
|
+ }
|
|
+ return instance;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void run() {
|
|
+ if (++tick < PurpurConfig.commandCompassBarTickInterval) {
|
|
+ return;
|
|
+ }
|
|
+ tick = 0;
|
|
+
|
|
+ MinecraftServer.getServer().getAllLevels().forEach((level) -> {
|
|
+ if (level.purpurConfig.compassItemShowsBossBar) {
|
|
+ level.players().forEach(player -> {
|
|
+ if (!player.compassBar()) {
|
|
+ if (player.getMainHandItem().getItem() != Items.COMPASS && player.getOffhandItem().getItem() != Items.COMPASS) {
|
|
+ removePlayer(player.getBukkitEntity());
|
|
+ } else if (!hasPlayer(player.getUUID())) {
|
|
+ addPlayer(player.getBukkitEntity());
|
|
+ }
|
|
+ }
|
|
+ });
|
|
+ }
|
|
+ });
|
|
+
|
|
+ super.run();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ BossBar createBossBar() {
|
|
+ return BossBar.bossBar(Component.text(""), PurpurConfig.commandCompassBarProgressPercent, PurpurConfig.commandCompassBarProgressColor, PurpurConfig.commandCompassBarProgressOverlay);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ void updateBossBar(BossBar bossbar, Player player) {
|
|
+ float yaw = player.getLocation().getYaw();
|
|
+ int length = PurpurConfig.commandCompassBarTitle.length();
|
|
+ int pos = (int) ((normalize(yaw) * (length / 720F)) + (length / 2F));
|
|
+ bossbar.name(Component.text(PurpurConfig.commandCompassBarTitle.substring(pos - 25, pos + 25)));
|
|
+ }
|
|
+
|
|
+ private float normalize(float yaw) {
|
|
+ while (yaw < -180.0F) {
|
|
+ yaw += 360.0F;
|
|
+ }
|
|
+ while (yaw > 180.0F) {
|
|
+ yaw -= 360.0F;
|
|
+ }
|
|
+ return yaw;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/task/RamBarTask.java b/src/main/java/org/purpurmc/purpur/task/RamBarTask.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..8e98c0ae73e2c40002a72b5d0d246ffa0c3ab38f
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/task/RamBarTask.java
|
|
@@ -0,0 +1,117 @@
|
|
+package org.purpurmc.purpur.task;
|
|
+
|
|
+import net.kyori.adventure.bossbar.BossBar;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
|
+import org.bukkit.entity.Player;
|
|
+import org.purpurmc.purpur.PurpurConfig;
|
|
+
|
|
+import java.lang.management.ManagementFactory;
|
|
+import java.lang.management.MemoryUsage;
|
|
+
|
|
+public class RamBarTask extends BossBarTask {
|
|
+ private static RamBarTask instance;
|
|
+ private long allocated = 0L;
|
|
+ private long used = 0L;
|
|
+ private long xmx = 0L;
|
|
+ private long xms = 0L;
|
|
+ private float percent = 0F;
|
|
+ private int tick = 0;
|
|
+
|
|
+ public static RamBarTask instance() {
|
|
+ if (instance == null) {
|
|
+ instance = new RamBarTask();
|
|
+ }
|
|
+ return instance;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ BossBar createBossBar() {
|
|
+ return BossBar.bossBar(Component.text(""), 0.0F, instance().getBossBarColor(), PurpurConfig.commandRamBarProgressOverlay);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ void updateBossBar(BossBar bossbar, Player player) {
|
|
+ bossbar.progress(getBossBarProgress());
|
|
+ bossbar.color(getBossBarColor());
|
|
+ bossbar.name(MiniMessage.miniMessage().deserialize(PurpurConfig.commandRamBarTitle,
|
|
+ Placeholder.component("allocated", format(this.allocated)),
|
|
+ Placeholder.component("used", format(this.used)),
|
|
+ Placeholder.component("xmx", format(this.xmx)),
|
|
+ Placeholder.component("xms", format(this.xms)),
|
|
+ Placeholder.unparsed("percent", ((int) (this.percent * 100)) + "%")
|
|
+ ));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void run() {
|
|
+ if (++this.tick < PurpurConfig.commandRamBarTickInterval) {
|
|
+ return;
|
|
+ }
|
|
+ this.tick = 0;
|
|
+
|
|
+ MemoryUsage heap = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
|
|
+
|
|
+ this.allocated = heap.getCommitted();
|
|
+ this.used = heap.getUsed();
|
|
+ this.xmx = heap.getMax();
|
|
+ this.xms = heap.getInit();
|
|
+ this.percent = Math.max(Math.min((float) this.used / this.xmx, 1.0F), 0.0F);
|
|
+
|
|
+ super.run();
|
|
+ }
|
|
+
|
|
+ private float getBossBarProgress() {
|
|
+ return this.percent;
|
|
+ }
|
|
+
|
|
+ private BossBar.Color getBossBarColor() {
|
|
+ if (this.percent < 0.5F) {
|
|
+ return PurpurConfig.commandRamBarProgressColorGood;
|
|
+ } else if (this.percent < 0.75F) {
|
|
+ return PurpurConfig.commandRamBarProgressColorMedium;
|
|
+ } else {
|
|
+ return PurpurConfig.commandRamBarProgressColorLow;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public Component format(long v) {
|
|
+ String color;
|
|
+ if (this.percent < 0.60F) {
|
|
+ color = PurpurConfig.commandRamBarTextColorGood;
|
|
+ } else if (this.percent < 0.85F) {
|
|
+ color = PurpurConfig.commandRamBarTextColorMedium;
|
|
+ } else {
|
|
+ color = PurpurConfig.commandRamBarTextColorLow;
|
|
+ }
|
|
+ String value;
|
|
+ if (v < 1024) {
|
|
+ value = v + "B";
|
|
+ } else {
|
|
+ int z = (63 - Long.numberOfLeadingZeros(v)) / 10;
|
|
+ value = String.format("%.1f%s", (double) v / (1L << (z * 10)), "BKMGTPE".charAt(z));
|
|
+ }
|
|
+ return MiniMessage.miniMessage().deserialize(color, Placeholder.unparsed("text", value));
|
|
+ }
|
|
+
|
|
+ public long getAllocated() {
|
|
+ return this.allocated;
|
|
+ }
|
|
+
|
|
+ public long getUsed() {
|
|
+ return this.used;
|
|
+ }
|
|
+
|
|
+ public long getXmx() {
|
|
+ return this.xmx;
|
|
+ }
|
|
+
|
|
+ public long getXms() {
|
|
+ return this.xms;
|
|
+ }
|
|
+
|
|
+ public float getPercent() {
|
|
+ return this.percent;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/task/TPSBarTask.java b/src/main/java/org/purpurmc/purpur/task/TPSBarTask.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..8769993e7ca59da309087051a3cd38fc562c15d1
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/task/TPSBarTask.java
|
|
@@ -0,0 +1,142 @@
|
|
+package org.purpurmc.purpur.task;
|
|
+
|
|
+import net.kyori.adventure.bossbar.BossBar;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
|
+import org.purpurmc.purpur.PurpurConfig;
|
|
+import org.bukkit.Bukkit;
|
|
+import org.bukkit.entity.Player;
|
|
+
|
|
+public class TPSBarTask extends BossBarTask {
|
|
+ private static TPSBarTask instance;
|
|
+ private double tps = 20.0D;
|
|
+ private double mspt = 0.0D;
|
|
+ private int tick = 0;
|
|
+
|
|
+ public static TPSBarTask instance() {
|
|
+ if (instance == null) {
|
|
+ instance = new TPSBarTask();
|
|
+ }
|
|
+ return instance;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ BossBar createBossBar() {
|
|
+ return BossBar.bossBar(Component.text(""), 0.0F, instance().getBossBarColor(), PurpurConfig.commandTPSBarProgressOverlay);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ void updateBossBar(BossBar bossbar, Player player) {
|
|
+ bossbar.progress(getBossBarProgress());
|
|
+ bossbar.color(getBossBarColor());
|
|
+ bossbar.name(MiniMessage.miniMessage().deserialize(PurpurConfig.commandTPSBarTitle,
|
|
+ Placeholder.component("tps", getTPSColor()),
|
|
+ Placeholder.component("mspt", getMSPTColor()),
|
|
+ Placeholder.component("ping", getPingColor(player.getPing()))
|
|
+ ));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void run() {
|
|
+ if (++tick < PurpurConfig.commandTPSBarTickInterval) {
|
|
+ return;
|
|
+ }
|
|
+ tick = 0;
|
|
+
|
|
+ this.tps = Math.max(Math.min(Bukkit.getTPS()[0], 20.0D), 0.0D);
|
|
+ this.mspt = Bukkit.getAverageTickTime();
|
|
+
|
|
+ super.run();
|
|
+ }
|
|
+
|
|
+ private float getBossBarProgress() {
|
|
+ if (PurpurConfig.commandTPSBarProgressFillMode == FillMode.MSPT) {
|
|
+ return Math.max(Math.min((float) mspt / 50.0F, 1.0F), 0.0F);
|
|
+ } else {
|
|
+ return Math.max(Math.min((float) tps / 20.0F, 1.0F), 0.0F);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private BossBar.Color getBossBarColor() {
|
|
+ if (isGood(PurpurConfig.commandTPSBarProgressFillMode)) {
|
|
+ return PurpurConfig.commandTPSBarProgressColorGood;
|
|
+ } else if (isMedium(PurpurConfig.commandTPSBarProgressFillMode)) {
|
|
+ return PurpurConfig.commandTPSBarProgressColorMedium;
|
|
+ } else {
|
|
+ return PurpurConfig.commandTPSBarProgressColorLow;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private boolean isGood(FillMode mode) {
|
|
+ return isGood(mode, 0);
|
|
+ }
|
|
+
|
|
+ private boolean isGood(FillMode mode, int ping) {
|
|
+ if (mode == FillMode.MSPT) {
|
|
+ return mspt < 40;
|
|
+ } else if (mode == FillMode.TPS) {
|
|
+ return tps >= 19;
|
|
+ } else if (mode == FillMode.PING) {
|
|
+ return ping < 100;
|
|
+ } else {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private boolean isMedium(FillMode mode) {
|
|
+ return isMedium(mode, 0);
|
|
+ }
|
|
+
|
|
+ private boolean isMedium(FillMode mode, int ping) {
|
|
+ if (mode == FillMode.MSPT) {
|
|
+ return mspt < 50;
|
|
+ } else if (mode == FillMode.TPS) {
|
|
+ return tps >= 15;
|
|
+ } else if (mode == FillMode.PING) {
|
|
+ return ping < 200;
|
|
+ } else {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private Component getTPSColor() {
|
|
+ String color;
|
|
+ if (isGood(FillMode.TPS)) {
|
|
+ color = PurpurConfig.commandTPSBarTextColorGood;
|
|
+ } else if (isMedium(FillMode.TPS)) {
|
|
+ color = PurpurConfig.commandTPSBarTextColorMedium;
|
|
+ } else {
|
|
+ color = PurpurConfig.commandTPSBarTextColorLow;
|
|
+ }
|
|
+ return MiniMessage.miniMessage().deserialize(color, Placeholder.parsed("text", String.format("%.2f", tps)));
|
|
+ }
|
|
+
|
|
+ private Component getMSPTColor() {
|
|
+ String color;
|
|
+ if (isGood(FillMode.MSPT)) {
|
|
+ color = PurpurConfig.commandTPSBarTextColorGood;
|
|
+ } else if (isMedium(FillMode.MSPT)) {
|
|
+ color = PurpurConfig.commandTPSBarTextColorMedium;
|
|
+ } else {
|
|
+ color = PurpurConfig.commandTPSBarTextColorLow;
|
|
+ }
|
|
+ return MiniMessage.miniMessage().deserialize(color, Placeholder.parsed("text", String.format("%.2f", mspt)));
|
|
+ }
|
|
+
|
|
+ private Component getPingColor(int ping) {
|
|
+ String color;
|
|
+ if (isGood(FillMode.PING, ping)) {
|
|
+ color = PurpurConfig.commandTPSBarTextColorGood;
|
|
+ } else if (isMedium(FillMode.PING, ping)) {
|
|
+ color = PurpurConfig.commandTPSBarTextColorMedium;
|
|
+ } else {
|
|
+ color = PurpurConfig.commandTPSBarTextColorLow;
|
|
+ }
|
|
+ return MiniMessage.miniMessage().deserialize(color, Placeholder.parsed("text", String.format("%s", ping)));
|
|
+ }
|
|
+
|
|
+ public enum FillMode {
|
|
+ TPS, MSPT, PING
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/tool/Actionable.java b/src/main/java/org/purpurmc/purpur/tool/Actionable.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..e18c37f06730da9d3055d5215e813b1477c1e70e
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/tool/Actionable.java
|
|
@@ -0,0 +1,24 @@
|
|
+package org.purpurmc.purpur.tool;
|
|
+
|
|
+import net.minecraft.world.item.Item;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+
|
|
+import java.util.Map;
|
|
+
|
|
+public abstract class Actionable {
|
|
+ private final Block into;
|
|
+ private final Map<Item, Double> drops;
|
|
+
|
|
+ public Actionable(Block into, Map<Item, Double> drops) {
|
|
+ this.into = into;
|
|
+ this.drops = drops;
|
|
+ }
|
|
+
|
|
+ public Block into() {
|
|
+ return into;
|
|
+ }
|
|
+
|
|
+ public Map<Item, Double> drops() {
|
|
+ return drops;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/tool/Flattenable.java b/src/main/java/org/purpurmc/purpur/tool/Flattenable.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..345d4ee4ff0b78bd1050959711a4f5d16a5e8aee
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/tool/Flattenable.java
|
|
@@ -0,0 +1,12 @@
|
|
+package org.purpurmc.purpur.tool;
|
|
+
|
|
+import net.minecraft.world.item.Item;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+
|
|
+import java.util.Map;
|
|
+
|
|
+public class Flattenable extends Actionable {
|
|
+ public Flattenable(Block into, Map<Item, Double> drops) {
|
|
+ super(into, drops);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/tool/Strippable.java b/src/main/java/org/purpurmc/purpur/tool/Strippable.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..bf5402214f41af9c09bd6c5c4f45d330516d742e
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/tool/Strippable.java
|
|
@@ -0,0 +1,12 @@
|
|
+package org.purpurmc.purpur.tool;
|
|
+
|
|
+import net.minecraft.world.item.Item;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+
|
|
+import java.util.Map;
|
|
+
|
|
+public class Strippable extends Actionable {
|
|
+ public Strippable(Block into, Map<Item, Double> drops) {
|
|
+ super(into, drops);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/tool/Tillable.java b/src/main/java/org/purpurmc/purpur/tool/Tillable.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..715f6dd44480347eebced43c11bc364e05727498
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/tool/Tillable.java
|
|
@@ -0,0 +1,50 @@
|
|
+package org.purpurmc.purpur.tool;
|
|
+
|
|
+import net.minecraft.world.item.HoeItem;
|
|
+import net.minecraft.world.item.Item;
|
|
+import net.minecraft.world.item.context.UseOnContext;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+
|
|
+import java.util.HashMap;
|
|
+import java.util.Map;
|
|
+import java.util.function.Predicate;
|
|
+
|
|
+public class Tillable extends Actionable {
|
|
+ private final Condition condition;
|
|
+
|
|
+ public Tillable(Condition condition, Block into, Map<Item, Double> drops) {
|
|
+ super(into, drops);
|
|
+ this.condition = condition;
|
|
+ }
|
|
+
|
|
+ public Condition condition() {
|
|
+ return condition;
|
|
+ }
|
|
+
|
|
+ public enum Condition {
|
|
+ AIR_ABOVE(HoeItem::onlyIfAirAbove),
|
|
+ ALWAYS((useOnContext) -> true);
|
|
+
|
|
+ private final Predicate<UseOnContext> predicate;
|
|
+
|
|
+ Condition(Predicate<UseOnContext> predicate) {
|
|
+ this.predicate = predicate;
|
|
+ }
|
|
+
|
|
+ public Predicate<UseOnContext> predicate() {
|
|
+ return predicate;
|
|
+ }
|
|
+
|
|
+ private static final Map<String, Condition> BY_NAME = new HashMap<>();
|
|
+
|
|
+ static {
|
|
+ for (Condition condition : values()) {
|
|
+ BY_NAME.put(condition.name(), condition);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static Condition get(String name) {
|
|
+ return BY_NAME.get(name.toUpperCase(java.util.Locale.ROOT));
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/tool/Waxable.java b/src/main/java/org/purpurmc/purpur/tool/Waxable.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..64adb13b29b6757dcf227a55588da70ecabe083f
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/tool/Waxable.java
|
|
@@ -0,0 +1,12 @@
|
|
+package org.purpurmc.purpur.tool;
|
|
+
|
|
+import net.minecraft.world.item.Item;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+
|
|
+import java.util.Map;
|
|
+
|
|
+public class Waxable extends Actionable {
|
|
+ public Waxable(Block into, Map<Item, Double> drops) {
|
|
+ super(into, drops);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/tool/Weatherable.java b/src/main/java/org/purpurmc/purpur/tool/Weatherable.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..b7586f494528f30eb0da82420d3bcf5b83a1a902
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/tool/Weatherable.java
|
|
@@ -0,0 +1,12 @@
|
|
+package org.purpurmc.purpur.tool;
|
|
+
|
|
+import net.minecraft.world.item.Item;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+
|
|
+import java.util.Map;
|
|
+
|
|
+public class Weatherable extends Actionable {
|
|
+ public Weatherable(Block into, Map<Item, Double> drops) {
|
|
+ super(into, drops);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/purpurmc/purpur/util/MinecraftInternalPlugin.java b/src/main/java/org/purpurmc/purpur/util/MinecraftInternalPlugin.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..129acb8ad139decc6b1c023cb10bc32dc91d64d1
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/purpurmc/purpur/util/MinecraftInternalPlugin.java
|
|
@@ -0,0 +1,152 @@
|
|
+package org.purpurmc.purpur.util;
|
|
+
|
|
+import org.bukkit.Server;
|
|
+import org.bukkit.command.Command;
|
|
+import org.bukkit.command.CommandSender;
|
|
+import org.bukkit.configuration.file.FileConfiguration;
|
|
+import org.bukkit.generator.BiomeProvider;
|
|
+import org.bukkit.generator.ChunkGenerator;
|
|
+import org.bukkit.plugin.PluginBase;
|
|
+import org.bukkit.plugin.PluginDescriptionFile;
|
|
+import org.bukkit.plugin.PluginLoader;
|
|
+import org.bukkit.plugin.PluginLogger;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+
|
|
+import java.io.File;
|
|
+import java.io.InputStream;
|
|
+import java.util.List;
|
|
+
|
|
+public class MinecraftInternalPlugin extends PluginBase {
|
|
+ private boolean enabled = true;
|
|
+
|
|
+ private final String pluginName;
|
|
+ private PluginDescriptionFile pdf;
|
|
+
|
|
+ public MinecraftInternalPlugin() {
|
|
+ this.pluginName = "Minecraft";
|
|
+ pdf = new PluginDescriptionFile(pluginName, "1.0", "nms");
|
|
+ }
|
|
+
|
|
+ public void setEnabled(boolean enabled) {
|
|
+ this.enabled = enabled;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public File getDataFolder() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public PluginDescriptionFile getDescription() {
|
|
+ return pdf;
|
|
+ }
|
|
+ // Paper start
|
|
+ @Override
|
|
+ public io.papermc.paper.plugin.configuration.PluginMeta getPluginMeta() {
|
|
+ return pdf;
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
+ @Override
|
|
+ public FileConfiguration getConfig() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public InputStream getResource(String filename) {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void saveConfig() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void saveDefaultConfig() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void saveResource(String resourcePath, boolean replace) {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void reloadConfig() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public PluginLogger getLogger() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public PluginLoader getPluginLoader() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Server getServer() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEnabled() {
|
|
+ return enabled;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onDisable() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onLoad() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onEnable() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isNaggable() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setNaggable(boolean canNag) {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @Nullable BiomeProvider getDefaultBiomeProvider(@NotNull String worldName, @Nullable String id) {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+
|
|
+ // Paper start - lifecycle events
|
|
+ @Override
|
|
+ public @NotNull io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager<org.bukkit.plugin.Plugin> getLifecycleManager() {
|
|
+ throw new UnsupportedOperationException("Not supported.");
|
|
+ }
|
|
+ // Paper end - lifecycle events
|
|
+}
|
|
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
|
|
index 133bcf639a45bd7fa1a2d02410ea3e8568265007..66e7b1966602f6d9f5978d66df7cb81b8c89e75b 100644
|
|
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
|
+++ b/src/main/java/org/spigotmc/ActivationRange.java
|
|
@@ -198,6 +198,8 @@ public class ActivationRange
|
|
continue;
|
|
}
|
|
|
|
+ if (!player.level().purpurConfig.idleTimeoutTickNearbyEntities && player.isAfk()) continue; // Purpur
|
|
+
|
|
// Paper start
|
|
int worldHeight = world.getHeight();
|
|
ActivationRange.maxBB = player.getBoundingBox().inflate( maxRange, worldHeight, maxRange );
|
|
@@ -375,6 +377,7 @@ public class ActivationRange
|
|
*/
|
|
public static boolean checkIfActive(Entity entity)
|
|
{
|
|
+ if (entity.level().purpurConfig.squidImmuneToEAR && entity instanceof net.minecraft.world.entity.animal.Squid) return true; // Purpur
|
|
// Never safe to skip fireworks or entities not yet added to chunk
|
|
if ( entity instanceof FireworkRocketEntity ) {
|
|
return true;
|
|
diff --git a/src/main/java/org/spigotmc/TicksPerSecondCommand.java b/src/main/java/org/spigotmc/TicksPerSecondCommand.java
|
|
index 9eb2823cc8f83bad2626fc77578b0162d9ed5782..f144a08e88f8268b84eb188a36bf470457f59958 100644
|
|
--- a/src/main/java/org/spigotmc/TicksPerSecondCommand.java
|
|
+++ b/src/main/java/org/spigotmc/TicksPerSecondCommand.java
|
|
@@ -39,7 +39,7 @@ public class TicksPerSecondCommand extends Command
|
|
}
|
|
|
|
net.kyori.adventure.text.TextComponent.Builder builder = net.kyori.adventure.text.Component.text();
|
|
- builder.append(net.kyori.adventure.text.Component.text("TPS from last 1m, 5m, 15m: ", net.kyori.adventure.text.format.NamedTextColor.GOLD));
|
|
+ builder.append(net.kyori.adventure.text.Component.text("TPS from last 5s, 1m, 5m, 15m: ", net.kyori.adventure.text.format.NamedTextColor.GOLD)); // Purpur
|
|
builder.append(net.kyori.adventure.text.Component.join(net.kyori.adventure.text.JoinConfiguration.commas(true), tpsAvg));
|
|
sender.sendMessage(builder.asComponent());
|
|
if (args.length > 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) {
|
|
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
|
index f7a4fee9bb25ff256dc2e5ea26bfbceca6a49167..f51cc3de3ca935ef90f7f0e9dd0506b856fc55f3 100644
|
|
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
|
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
|
@@ -96,7 +96,7 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
|
|
|
private WatchdogThread(long timeoutTime, boolean restart)
|
|
{
|
|
- super( "Paper Watchdog Thread" );
|
|
+ super( "Watchdog Thread" ); // Purpur - use a generic name
|
|
this.timeoutTime = timeoutTime;
|
|
this.restart = restart;
|
|
earlyWarningEvery = Math.min(io.papermc.paper.configuration.GlobalConfiguration.get().watchdog.earlyWarningEvery, timeoutTime); // Paper
|
|
@@ -155,14 +155,14 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
|
if (isLongTimeout) {
|
|
// Paper end
|
|
log.log( Level.SEVERE, "------------------------------" );
|
|
- log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug." ); // Paper
|
|
+ log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Purpur bug." ); // Paper // Purpur
|
|
log.log( Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author" );
|
|
log.log( Level.SEVERE, "\t *Especially* if it looks like HTTP or MySQL operations are occurring" );
|
|
log.log( Level.SEVERE, "If you see a world save or edit, then it means you did far more than your server can handle at once" );
|
|
log.log( Level.SEVERE, "\t If this is the case, consider increasing timeout-time in spigot.yml but note that this will replace the crash with LARGE lag spikes" );
|
|
- log.log( Level.SEVERE, "If you are unsure or still think this is a Paper bug, please report this to https://github.com/PaperMC/Paper/issues" );
|
|
+ log.log( Level.SEVERE, "If you are unsure or still think this is a Purpur bug, please report this to https://github.com/PurpurMC/Purpur/issues" ); // Purpur
|
|
log.log( Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports" );
|
|
- log.log( Level.SEVERE, "Paper version: " + Bukkit.getServer().getVersion() );
|
|
+ log.log( Level.SEVERE, "Purpur version: " + Bukkit.getServer().getVersion() ); // Purpur
|
|
//
|
|
if ( net.minecraft.world.level.Level.lastPhysicsProblem != null )
|
|
{
|
|
@@ -184,12 +184,12 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
|
// Paper end
|
|
} else
|
|
{
|
|
- log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH - " + Bukkit.getServer().getVersion() + " ---");
|
|
+ log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PURPUR - THIS IS NOT A BUG OR A CRASH - " + Bukkit.getServer().getVersion() + " ---"); // Purpur
|
|
log.log(Level.SEVERE, "The server has not responded for " + (currentTime - lastTick) / 1000 + " seconds! Creating thread dump");
|
|
}
|
|
// Paper end - Different message for short timeout
|
|
log.log( Level.SEVERE, "------------------------------" );
|
|
- log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
|
+ log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Purpur!):" ); // Paper // Purpur
|
|
ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(MinecraftServer.getServer(), isLongTimeout); // Paper - rewrite chunk system
|
|
this.dumpTickingInfo(); // Paper - log detailed tick information
|
|
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
|
@@ -205,7 +205,7 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
|
WatchdogThread.dumpThread( thread, log );
|
|
}
|
|
} else {
|
|
- log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH ---");
|
|
+ log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PURPUR - THIS IS NOT A BUG OR A CRASH ---"); // Purpur
|
|
}
|
|
|
|
log.log( Level.SEVERE, "------------------------------" );
|
|
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
|
|
index d2a75850af9c6ad2aca66a5f994f1b587d73eac4..a056aa167887abef9e6d531a9edd2cda433567d2 100644
|
|
--- a/src/main/resources/log4j2.xml
|
|
+++ b/src/main/resources/log4j2.xml
|
|
@@ -2,7 +2,16 @@
|
|
<Configuration status="WARN" shutdownHook="disable">
|
|
<Appenders>
|
|
<Queue name="ServerGuiConsole">
|
|
- <PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg{nolookups}%n" />
|
|
+ <!-- Purpur start - copied from TerminalConsole -->
|
|
+ <PatternLayout>
|
|
+ <LoggerNamePatternSelector defaultPattern="%highlightGUIError{[%d{HH:mm:ss} %level]: [%logger] %stripAnsi{%msg}%n%xEx{full}}">
|
|
+ <!-- Log root, Minecraft, Mojang and Bukkit loggers without prefix -->
|
|
+ <!-- Disable prefix for various plugins that bypass the plugin logger -->
|
|
+ <PatternMatch key=",net.minecraft.,Minecraft,com.mojang.,com.sk89q.,ru.tehkode.,Minecraft.AWE"
|
|
+ pattern="%highlightGUIError{[%d{HH:mm:ss} %level]: %stripAnsi{%msg}%n%xEx{full}}" />
|
|
+ </LoggerNamePatternSelector>
|
|
+ </PatternLayout>
|
|
+ <!-- Purpur end -->
|
|
</Queue>
|
|
<TerminalConsole name="TerminalConsole">
|
|
<PatternLayout>
|
|
diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png
|
|
index 8b924977b7886df9ab8790b1e4ff9b1c04a2af45..518591dd83289e041a16e2c2e7d7e7640d4b2e1b 100644
|
|
GIT binary patch
|
|
literal 9260
|
|
zcmWksbyU<{5M5yDS~|W3b}1=IK|*5bk`9p$r5ov78WvbWX=y<kL;*o0bwRqMa}kh~
|
|
zQ2O^B{&?rid-LYby)!paPe+ZMgqZ{c0+DN|D;t17Ak6(C!UKUod2v>?AQ0}Yp0<$+
|
|
z2n70|0E9aM1Hym>3UG)5o+kstyg;EopqB~EvfpJ`0IyyF`Z>TV(_M%s;1&uXoq-)H
|
|
z;F}=ODg(TT1R4>5S0IpY2)Km+#_2%4GEk`jbcq9_JOJ7f=obdWYJprMphypx-~uK&
|
|
zfGKuhnfb0%2k;C6T*B}FJWm2#LxEc5`?y0ASYiPxHGw7sut5i8nE^^g_qFCpK(#86
|
|
zU=R5D0q-;c>o{N$dUr?$<d^{O)qs2>K&}+{{t)O91>PFm^B>^>UPJ-mZueCg=74SV
|
|
z-76o!H4G@%0&L>$C3pt{V-J8Y;`e|##z2Y<ppgqix&c^PpidM~ECTGJfnX1y&;YQG
|
|
z2V^P$)0BHM?b7!z&y(*JWtaoWw!jw&V45AM&;ka80P{p3!{T1Mbv)n^2q+W-*{1iY
|
|
z6=tAa5{PjG%Cv!KN1$8m9$%#HK4qSG5At3OkgNn0itj$i-Q(zG+<AoDr*^6Cbt#kp
|
|
zVea==-&gk<J01h>AwaY<&?5%eA%O$(`;HN=zzH!R+z9BrzEdm$hWPHMEnN<X*WAy4
|
|
ziUW954ak-Q+S!2eTj1&IJ1i}*OLezL2?*B%3())E4+*f$1dKiae(>JY_6!DIn*qN5
|
|
z_nap=0k432lC>)L25=4s0)2p&k@rF>wC=4^sR6w51u*=8Z46)^eeaD_OQ2KYesLu_
|
|
z_bnO}fnYCS27b@YJPA<G1)iaRjOReQ#l3Udq=EPsz@r*Kz7z=a08lpf8~G@EKStx!
|
|
zyJe<3%Y=K4y&}Lb8bIb9@LBSHg91(Ws*g#4HHJHtLO}Zs&@2xm+TC03oB%LL2V!0V
|
|
zn{>cFIq<j=n1|l!W&wG|z>_k-G5l_q3J8e2Q;oLp0f9h`eg-;*AYux9f;(z{1P3K;
|
|
zAc-1FB9Ge>Zs~zfp~6f|1AZ>jJ+E!xyI=H$h0b;xyj={nw3zKSrn7|FQR-*=+fyUr
|
|
z=Su_V?H60K!yRe<UeEPa&vqO0{PowDzNUB?DLpwmK5Pj%9v^H7H#%5bn0;-od%n3o
|
|
zUs8;;KHZ<08u{E<niuY(rz&ywbNGGf^O^p>o|fvWvfRwHX!FDE%^}p;&O(2o^WU?*
|
|
zrjt*BXMa}vSHgZ%pMyX!K@DYuQQ*RKzN>boDdTtRg-Ly9JO}n{XVhl_+MZ?HDs@~A
|
|
z5j=z*z2Hk^FS|?cBMa?*B1y~c$eczr6DJ<~8sS%-R$89I?xCD+Tq0C5SucGjXE7<a
|
|
zGVJBpX#qRQ*})<`-JSKXe7Dh}?VGWnw}9{3%I7C#qYoVU+r)*o=XwhYuv$yZ*^jC_
|
|
zeeLW@J35YqTi?94Tp@;na6j{I&Q?<}__M36r(iv%9i|ujk{-2ZO4`xcT=Z&;CpQ}|
|
|
zEf~7-dechpnLMCTu<C3(9ISiDGRmZ!S`a&>xnV*8Gc?TRT3SfozC^6$@Qj6@!n%l|
|
|
z#bi{is#y61XyM%?*IpJew5-hAwU2LJMPXt&j8*u}Z=<E1ot@k3_P<LmKi3s4QvcY6
|
|
znYKGPE`{m+e8JnAw^bk^L&TT7bsdoEzkKwYIoW^Hq>i(xqCeej&2w>uP~qD*iWsjN
|
|
z!^cTPWqL1jBqhDw+#HnmHv8-3f_{;eCN)dJ4f@ki&gLx-FPHc-{eE0r?C;w+3p_At
|
|
zj%=5ztJvcEFqBgI$80>PjARKtETWa7n%NSZx{*B42;KZ(L&33iNW$szF`A{7nN#aO
|
|
z!V)P|HjhBCPMyimc<&?YyQwLsG>62*2y&d?S65d<!2yT2d>u|u$!}x%`h`aUbq!#y
|
|
zFJooT^6+RQZLQ=5o5>q$YfX$7eU6?=eW=*nR52euv~h1X;xm4AE`BJhVSpkv$QsV&
|
|
z5Anq6bv=fRwwKeUSOrdWo?{Hz<NsZ+wLP=Qsx7w0qU@tysJc|3`T32jvu7wIF1RSu
|
|
zq%ICgLRA*JyU))2YQYf))|v;fGktDePA&Xu?S(Wp9a8{I&a$zR$a#kc12GA8VFdf<
|
|
ziHEi9q&8n{>m@>0e5gE{qRIP3&NzQr(q7Etqj1H49H#Y2Wj%OfEqb+NY+_Q)$A9W%
|
|
ziZ4N<Mi%)b*l!>&q~k<@NrBE1YnNCqW)_#6WvSET^sZ9>^_ynuGtnQ3^(sekadGnT
|
|
z^>b!Fik{$Ps1dI64bk`JaF@vx6&2zKkQqSu&X3*}8yQ`s=c_OT2MRCRkz=TQQ{*Uc
|
|
zF{j%dt9izpO|6l3{-2cp@WtX4QR-xg)hrbh?7uA#@TKwh+MeNv*Gy%bwT=1XICtaO
|
|
zdAW4DJ$8Mq8$R@f+>+13la0|ysO?O3AywkY!KB^qO9(Y5C*4P5>hH!6{E|8X#C$sS
|
|
zhuNeT(~_1xZ7?=JDrbDQgsXXr1J2q<Y0=B8;2b^8?GdFi3Ytlk%g9UTSaO~~K-&IO
|
|
zcq@DS%&dmz(^Bsi;~cvsH>*mKZdSVndXGEOhL3MuXbGVy8lQq^8z{6%n2&KBdn+3_
|
|
z&fJ28J|<a6FH`<>^Y%x{?)O&<zRgSeD3wj*Io)uOZ$A}xsri@BOo+2H<9uB?5PBtH
|
|
zgrANTDHU1vEP|BLoB)>DR)OKmIZC|}&|+yY8pDZ;rYZco-tVpA`GB25dU;`C@mgTO
|
|
zPNlccf4c73T?xggH}``wr#<}dwp}6eKZ7)6H>Bek1w6cls#R0HR?L?c${5sxgP#oR
|
|
z9QQ!09_5zgQxiz-P`-Rk2HySc6XH7+EoEcPyUca*kH*9@1?CfNtj+0VWLzleVfEVl
|
|
zm{CNN%(n4itXxD?t4u{{72YA~cRe{QS7SpjXRRb0RimgmqN@v1R~ZO+x60R?@xAyj
|
|
zZplHM`TR5wPhYOwhVUwjMoX@4_%C6h!Cp(QdA52*GM*rOjs10VoV?4S1!dnS-?jof
|
|
zRoHLj+oh5|e>F_H=8piE&n#$mL*<ysBS8dodow(q-4H%~P2+*%<6%@8aebP51PbQ-
|
|
z_FJJ>?jwwCWrIL~oATnM4@|z>K&(=qf7vWc<u=H-*!%Ct<ec2yy}i?Amrg0Yfp4~r
|
|
z9Lb@hFAe@Cg6y2%<BV)gZ5`EvQ?rFwP;#;T=Kubli%YC%y%OR6r4h13@xyyBPUGVX
|
|
zRSSkudBGnTKEebg78^Ai0YT!`v0NCb8pzp|^eKe6Ud>5-p*05@V5yp)ru>~B&CjM_
|
|
zp@e}3@nub7uR<3^VDH}(%W}}0q(RgYrQYXfQlgzcCc>#L2o`N_;>pX&=H}w&y|}g9
|
|
zUN0CK8u|u|362&|5^;<`$%0we%4S^5ONkLbqig^w!N+1j3`cW;4AW<^J+3L<JJqBg
|
|
z=<&l2%K~SRu=pXIu94}~@s6iYpN11OAkB#k&@T^x<1Ae*tz^~ACJ?<<q8z2zzsGkt
|
|
zQZBClh!YsbcLMEl;m&byMlCzZq%;yxA6Y@AwH_;Dxh3va;%%%YGBIvPT3oemk8dyE
|
|
znm_Vx#G7NeLd<@Pb1>#Faie@3G|MeLH5~(uqg+ciGU2r|lYeHHXShGO{ZMWnGgOMu
|
|
zsi;e+SMqcrDyb1wvA&pD!cR?+->7KbLy?XRk{-4pRQ!EpDiX&RnEAJVJjXWrmG!cx
|
|
z2`lhfMp3H=4HiXxD{FJBMWjw!1}5ILmDC^pcy*Oe$>;x}LLf1pAmzXRV!o+y5H1=U
|
|
zwAU~zWSLqHZkz3!bSgGEq0&t*dA`&UAVw2*%j)aP%IyD>CwiryV1VMp!;epqs-Zxk
|
|
zaMVDz1U(uq*ltddXYYIOqPY&Q?c-qdVLk&1CKjRZ$a!5R<$D{#LLg<EyTNj3f9epI
|
|
zS7m<8@7M~F+Xc-_RC+(6Y`pN!qJ4eGDL)U*i_jB5VN!)%QOfL3=w!RH-`JPYEpvpw
|
|
zg5kls^_S#8c9jjiMJqUDSNz~yd$PqeCv$w+i5$bPQURYj7M4IswkDU(J5&Un4B*_&
|
|
z8VQTE@w#E&nDy3@O=m(%B7rz%6NO6;3U}VIUNa~*%Q}nkk=hdDU;R_HdIBjg(}zwG
|
|
zl9xA2FE^zB5#g<TAh<U5?v=$>X<QJEr0ba{!-!|ELH)4|;E-xuQRxpu1MCtQsbSC5
|
|
zei7{P#1_XJ=8vjhu<mintV*gtqS+QFe&@DDpvd1?YSqu;tnD@w({bl(nU%Ul%;5Ec
|
|
z)<$A=0e4=&Aoy#@l-XCQ)YK?diZ*@CA`wCZ{;eMsGKBFMR)*uVk8O?rX<Xr*`#!7K
|
|
z@M)>YkP6p!?>#>*GrvVaAktyZH~PWR6(;*(A)Si4vXe8hKd5xsE^FC_X?C5>8pvdE
|
|
z3cq}tKvjQb^O;y?;JjL(#1h>iP;9#&Tk5JXrF571-#Ki~OtYWJUNB9Yam5ozZO#7}
|
|
zaiy@4m&`~GM;B;L>&ZKfWgZrU#U%Nare)SK9=~mQ{*F~c(&uR9%cnfB^dhxlVxOyQ
|
|
zCEn$=ryRuVaw9%WIFr48kM{UwuwdA1JaicPw|)BO=eHXTIk<z{w+?jP;~r#z=B+}9
|
|
zhDZ<|R;6{NUiRt7Vse|nGK3Siid<1bDc)=R&P;vJylCOMdg>PnB}DIayQbG1ZXcXn
|
|
z9>Pdlk_eG4f8Qlok2QRCjhS&;>_|?vXyC@qodyqfXh;&tgw5xO<&TtGbw(Ps2!w~L
|
|
z@%!Tv%yB4b%G$PYsb@Y|yDHD6UD(8WODIH!wpLg3?HJ4Y)TT@RZA#<bP=7EUOLw^^
|
|
zWQE=xV6m6F3=QYThaDRLjfa>oX)p&0mvRu^rySUXHpw#8Zm+?FRf0;0A0Ak3wMz~p
|
|
z71!ai+@;rh{M=93{pyE0M2C6iskBfTX$T44%ES+nQMt^MntnsKz$xUS<^`TgGfDgA
|
|
zqkIkg!usCGe>sIa7b~g>Vaz>HqqL=g^J6@+O@((j4owc9i|k9LOoKDuv3V!PP;IN$
|
|
z%HZJ5a;(l{{Dr88ag^}XNN?sSpmbegRO%CL|0MSa^BZx9Z=*KfAfJR@M1`Yww-k2b
|
|
z<-O3pg=SpYCzjwry~c2~FfPhNWasR_{a|-qD>lhk8Na`y?R~1GU5#xa2vQ98U~&(3
|
|
z0y$V%kLygOS?CJ5MK{n8Tp~*M2x*>%zM|@1LR2=){lSoZ<_OCde4&6&5iDRu%g^S6
|
|
zdJ{{BoQ4N=sxI2DrG26JB$x*6hzzF#{n(RNE#D}=C&)F7)JnD|FW^0{U`5NbGE*vM
|
|
z6c*(vmVH1b73#>8tl*QiNez$xYUpM$rVD9JS~r+ijre@N>+U|T9{ZazOyc$r;cAjX
|
|
z*nsKAWR5Q%4V+%G<&xT0c<wyjw}8oqBo}WMS90>9q!pS{8y7y1Inp7xm->JW+xTQ4
|
|
zw=Rn$XY-83dWSFy+(#{kj<}nk+@LfrEh#P>tts2*=VU&m*7A*T`hAg@WUH5yV7XT^
|
|
zM|s7R@c!}bY0WN-b4>YJhH~m4FNnel-ND4@Z)J>GmytL5P~Fpm6LuVZGlYjbBj~6n
|
|
zCtMe1%pMPR5-7R#B9{=i{8t4czvk{v?*J)sZxde5gra{~+PATL$o&yjCiWkQzY_Z3
|
|
zz<p3nB%mGlb%BiE#`YCi+KOdklSNGAjjJGLqF%%z-AOXQ-C59yG?Dm;=a|?P<kMAs
|
|
z((jDTecHIc94rdmyC!jnyW4EG@=UR+B@uACi?;`wcDPotr)pBNCgGD9iq<XrQ-$98
|
|
z;efaKdjA3(jFtCAq>4hYpnygr5za*1m2wD2QYPz$degfc*(^yH5SElj+n*S8nMMg-
|
|
z;K6}$aFF#=ga0;GJmfN+?EYJwGHy8&4Wlwy3urP1iyMHNsTA_SQ8$jDazma3G5XG+
|
|
zhaiKap-ClkI@w_&8XLN7bpg5>9dP2S56@9dod&Lcu#bug;nq=f6B|k0K49OT`m<D&
|
|
zJMVvle^d9-J%mhOWE)xOYAa5T-IXCi49WIn<)2I#F-QCarBR<WX@|p82YM38NkrD%
|
|
z|9;vQ|Gvvg8xnZAOXXB<Bfh3Y<_iVQ!^yA#;pjvU9N2R(RgWy@s!y1U+-?4iH0{)Q
|
|
z<ohb+uTnOq=SC`_LnrCBZbWHr70<oLELqeGVd&LB1@4%rmbIkr^a>e|LMUc?#wYlk
|
|
zEdi#ai%S>$Hho=2H1I#AUpsi>aojup7QdIdao^K`Px9wsIN%L3H6bK=KXZr0tj&X4
|
|
z<??X;#Y+QLh)oX?Ej4TV40kW;7B;9zXz&1x&0oDxD2=I8Pp;svB|?$=!Q6&5<i1wt
|
|
zYfN1K^-X?BV6F>O^DHOl*NLOzcvT`peJNhYs2<RYrZXc`Y^HE~CskRnM5Ru7USv)6
|
|
zWkvS9RA=WTT`o|4HV}Ir>QLwn3phMRYLh&p(jt$V{waoz%{9VHmA9j4%B9`vxMlF;
|
|
zkyzxtl%jG#gk6!za`<A^N%;*ra1hec;K(HrHckaGN_OiTlPAzHxkvJurMrar8kRO4
|
|
zd;@t~Q;p1Fj6Dx=-`6c)2qIEN(ZOId=}g5Ud0Vmfu8#1k!-!9}3$dA$7^uHn^2BNX
|
|
z7p=I@^x+?0wXw4(Duj3WZcDIX%8%)yf&)Z|Mm*-mn!riV_^vwHR$JvkWEXIfY9F|8
|
|
zF4N!G?&tCtLmd8IN?hIoG@U+P0+9#e@<i;t8jnO~bMn5UQuGvq(?11yNxVITXMZ+w
|
|
zS_EB*tI+i|Y!Q;syOvZHgmB`HJ*A{?@syokxLSL}l}JBMX~&l|C{0PEO(-um2aoW*
|
|
z{wu_Gf^=X8d*=}951tboJi-L2zIzt%(C7N)#&tc(qAyu+HsNJ+y%L1TJF;sAc#`;y
|
|
zO`ibqn^+kicI9Yrd%Hv7f7N`N{fj_AVB!Nii!}Nxd1UB`xKHSfRHbePP}A`<r!9$x
|
|
zV$HYx+YFZh=|>YPPLc{ayX5f;!G&>!-yO&_dh3ZRzEUSzBWgC{9CTGNkpzL<u?nmr
|
|
zR<WawIST0!)zY7koQS_Hm@lrVXda7Jr3SW#1;@Vpqe%O77AlN*iV<>rc{p5<yPhcT
|
|
zY)U(TYe+OY2tw|@hQ|m+jLW|1yQ4Ws-?Kg{39Wq)XRCUH4);}m!kADiY|B_R6t2D4
|
|
z5fL6bfP^ao$NmZw|J-JsFk7z<R6XoWn06n>8?BKd{ftze%bJ})v*q7@nFCJ-$|8i9
|
|
zKQ1_Z_nJA|o0+2yD}3`&Xt&qsZJ@&(bu;f9XsTU)@2_u!fEUYlG${&}k`k~MvFJ#g
|
|
zep<t=J<s;FWB2epz4u8Av3dg)CwpDV+sSk-k13@&hLif8%E0CL!=@aBU{B{VHM>=B
|
|
zEenK};%y~yqKax9SNTs6wV8mq@#jK<KB5t9_sq|+uv4sZ5B;@QHhw&G4b{S{ASk`m
|
|
z2U)UjTH2lE<SctEsocQh=BZXwUD~6ml~z|PD#da|Szo(eOl>W_hR0oG#RT?=gg*;^
|
|
zrZoFk7<``g{Sm&pyi#b_s~#Cb_J?o3uht$O9%^oe`_zP@_f>;l??|$7c6j%ouQ@rV
|
|
znI}Donku9gd(;PKoo`ZnB|lSfL(CcmcK9h{4K2yfdveiX*F?w{S=8l;c_!AY_HaJ*
|
|
z0oiU2PE+<Lnld>{7<F}b@!SitAS#ls?>^8nA-0?K-qZg~hyU}@*EIx{)+mOG!6$h4
|
|
z6F#K#O21)wZNhZ9b@y{kq2@|7=0~envCA>0*#=!k0tuBTLY~L#MV{d{kN#XAgk+}U
|
|
z5Wt2Zwq_K{0d5|_|K{og?TJK@O?!fe+q%nRmRs{|kh!%&5@&miK0apQ-51|j2S4pt
|
|
z&VI=fC!wW&d0H7BKK@5d!ESD*%_88DBubno!~bRugU2H@82>E4qSRJcVDvE}ZZ=i4
|
|
z5X8r%T8*m5$HSX_B@44s4P;WjPQ2c)nsl}mmyn?M#7`%zeqZ(@ugCSL?<JnOEH%>i
|
|
z$~Ug1S`kg9`+<$RurHPIKg#y^=lz&ozJ6xp*qZXC$s2MndW9}aq@>qntRZa9QE!Li
|
|
zSrJXSG5JOrD)7n3(!7}A;^MmcNS2|M@NbqUQns5pi|&Sz$2-?FY#%!HySVWPk)MaQ
|
|
z+af41N6D0bs5twkv>_pXx<M!UjCH4Ib8Fqpszy?A%-DA><!{lRH)^*xBm5WfYC#eI
|
|
zMz%I4+Z7rW9MvnumB;?P!g6qoM9yjIy!GqVFB!ZflG(_Cb1WVBf6qsx>dGUoXwOeo
|
|
zQC$|98>a_F%Te2+j3@t0@G;H|2x&SPdnF!37VmuFM$t~veq)fKhm==s)&>5HoXXVB
|
|
zQtO3|U_-3jWL)<@CB-|Fr~-ct^=#_?Xq3aFG8-+5c_}w<a%>ff-j2Wl14dG=*Ir9`
|
|
z;vz2(O;5Unr5LHNTB*VR&471*8|-qBnLX}C_xgEw_{cs><2@q7jH8*rt35VpFCY2j
|
|
zo{C<U4(k(}y(4mdjlK=wQ+P5WL*zrPpV!@C+EkF*22x@<v4<qIt)=f>NJWmlFb!fB
|
|
z+VoPrGl(o^jqOM?eXroBfTsHID*ndD;oV>?t@L*bcmz1sE7!M3!1u)Tg_tsY?&*yt
|
|
z{-g%_mIRW%x&)2xcX+vo4UJ)XO{WNsMdc`kKl(hxy=qIm^e!9ykOZys0+Uqm>(@qN
|
|
zZb-1Lj8wG=5eFuL7^|j46t_`%IbWswhBS4n<zW&olB+x!{?G(c2ThG)T>hHL_=6N}
|
|
zg#88*wIk^{8^Vsyzmz;?T4HZC#VV;-$K)tUbCnN}WVDwtrQ%2pCXEG1<7o7lhTTE>
|
|
zJ~wyXM6LZ`OAuO9z`-gRs+(rVKt*F|`vWoQ8G}y+;(qGCesq_I=;THh4U4k78ic03
|
|
z_yCm4t=c1=4uP8^<Pj9Pi2aHnR$&sYtx;1K8N|4hHr%R#2~1;E!%=4b9(|e`VR4uA
|
|
zI56!?^EYaramHreu}vIKc|{4%{}?;Xnn9R~NTTGmYnN7Cl;zx71<T6$XB>yGG0;ab
|
|
zwAc{o@me2=dAu+9sU(&HWXSXObGX&CD=$ZhdG;RmbJTB_D)n6gG`*O*1MzIMSJvKi
|
|
ze{<PH+iXdM1F06~;-ZZh8_$NOa>aZF2T{fr)a?Fi2&+vT73&Pu*HcesDu2=t4HLmX
|
|
z!$E0!OY_r{p4>*vGR-674`asP7qMmjE3Xe~PfSf;ZVr_I6P}a9nWQpoH=T{EY0~4~
|
|
z#U6eC9jnyEzz1>Q%!0>TcL~KDX?RPKsEnGSmB@N3+{1pwhgLM;rDu=G)7qD+?>(;_
|
|
z!O<VWI5mra8y>z_2=8El2)Ef>-?%HT*gKaZ52~5aN;nwVE7a)vslJ@1QkAa}tuz&*
|
|
z{}ialFW|fv&c}3_0)s!=?^0~-489@6VeM=7|Aqi5P!PZt&PFG+F45<CPkB3QpK3UJ
|
|
zf;i2oM5UR(j-!M*vos3>(Ws(78Sz*3L2+Z&?ga)D?d0Fr8GSgtNgP<D3GLLt5syy@
|
|
zox<K`c=Y+1%5s#I{bF)98YN<$702{#TCnV!SDXfcOlxXB)cDRgsDgTki(i9t-Hg9{
|
|
zaWW0km%h~_A)t8vMvX)^4kist#aHUOwj%byg``-sl0hpE_ed>{e(x)4TO9Efqd-1b
|
|
z^^JZ31`<h4;&*Cv)O}`d+wH`ToWtvS(PVjuF2kq-8=|ZB0-@i2?!B)*Q<e#>-ob|M
|
|
zLa;{8<fG>};>3e1J*hWDD{O<F@3w;YesyM|XOhr8D##d6FH`z<g9Ytg5MhKdsl3=9
|
|
z7fwXixl&xv#lyK3tq~VB?pvE=__x8{?q@ZXvp*~O9394KC#!JV*ZW0?FO3zk-uk9{
|
|
zSnmmjH7BXF@x=={ZN>c^N}f6Pq4vbrb}w-WJ$t;JoFlzdKQmA`yLEOm`=H=CHW~?J
|
|
zK?0qp%gJ-+g0LOde;XF7RK)Y)=ESrK1|9oQbwZPv3tQZcF-)lf#XikxG|WUcdS#;B
|
|
z+Dhu{<!Cgm<byu+`udaUva2R7_su`1^@N7wQty=7J_HCseH5rpq{AP|!Nlm}OO68m
|
|
zgfNA^whGB-1B0+HkqS{USO?4{kr+u?3=zSuoGWCw5luDiS~;fHrh$XJ^KKXwihw97
|
|
z=A@g}Ph^)tNqNsGY6%??P~XS`=@+>3m0&4t2svA?8N`pSfV6UN6#vHZD`Bebk_#_f
|
|
zomix$3ThRJ9kUvAF{6-o7-lvI8G<(JGEr00_6E3Jn&AO^l8Jpm_!j|HKUFV&MkoA&
|
|
zvidl_aG*eY@vG<Kg7*+N&qK$e6_v3My~g<kn1L2tV4Ni9V`&TnjP($T5NnQt*(ZaX
|
|
zT^Fm#=1CJKe7U1M<iyWTo)l4zR5L!pQ-6&3MhheEz!8xP`m3Jb8|@HzmZJoDygbMf
|
|
zww1(WXjSxptuh7$TgJgi*fRfZF09ms|6tvc9)0k`2o{1P5^@p`>+9o6|BS91B8-oh
|
|
z{*HvN+rWmjS8XHl7EAM$hGDYd>O~?k+09-yEu|E;*?T>yK2@j#8b~V>XV7CYe{OT=
|
|
z>LUB&z}7rO9^<4V1;Snvd$h(ZKs1<cs!0A6&f!6$t~db`bD^_J3Qap|V*FYcH*>js
|
|
z@$uQ*bA^~Ug$YN5&!;pcKb=+%JmIhhd;h0&CMpaOCsyR@%J}z8j#wPI&qXAt^9+He
|
|
z9j1Ov+{Ci?JipP-F~v;b(}BbHLx=MRS|G%XjaC&?e+4KpCuZ)UmM0Cmq!=9-vE3bE
|
|
zl(uDl!TRICJOw`YvN6tq0LJQ?@TrFkX(FBwO7>>{HC0sRw8dSZ=Ybn$MNYxbw1&A~
|
|
z4U*;<|8AirF7Bn$*+Sty&*Z?8JwK2eN7J?_E^D>Jkr4MPOL6Mtk_aiCs;No_w|y0j
|
|
zt<s`DO+pI=n$t#j+riNk$YPITG*zp)qUt*(H}PobH>G;ThhU2Suqk+D5nR0zmvibT
|
|
zRpibrQ#xeY)wgm?O_F7(u<uw%2dY}kElw<TfUB&Qd+P409v@?4#xDTZID{in+R-u5
|
|
zQFDcju(+FKnv>o<qW*`1NT)(e7f6~Ym`NiKM?;611;0#CTR>6SZbj$kr=PBOsJ7?4
|
|
z9G04pG&Mz?Y6l0W1i01Fr|wXPET~N10Q<nqiBx3APfc}x#G~3#x+|htHs9DlJalv6
|
|
zK943OnZecCV<CAh`_1t%7|~ehRG3cWCI-QlPcfJ3Dpqm1*RZM#m-toz1Br6OG}c5^
|
|
zM*-DJqWRnSgEQ{p!`-0{6ZZ3}l8rsrf4_msRp1=q35LX?qKfE0-kwy934ay_95I&q
|
|
z*;-v<e;|m)unKf~l$28E=BCWNz5|0Jk6tFbI)hSU#0&Do?r<5Ug*vz$JI7}KoI8!9
|
|
zu;MB*I;}7E6VxC^8E>+lLgS^HWxZsd_kk*^;~xkae4sW9p)Hr-Rq9-khPzow4)vQQ
|
|
zWLpI?ynx6^s2&+dNg9il9{dSTr~2X)ko&aY%Q%Itxe?BWpMfefGcD}Z%Ae(pS~bpt
|
|
z<P|q!1dePTyy;DTyb5EzOTQWAbzvk_yVH!A+L5>^+c*S=m)cQQPeBsXQR+GjKR6(P
|
|
z$aaour7~L<L^rN#K`gYs%z`Hc;pgWs(T$uhr(+9g2<6+z3E5o`kdX9j=*&ld@5549
|
|
zI_x%aJ`Np6;G4i|H9|40HtHUl^-~^owf0y16j^MXg67~gD>xl5JGp8P4|f+<k7nB-
|
|
zB1v2oR!seE(Zt!?l`;C_LV74#@i*}X5kV6Jc?!tDvL>;D8h>&9*bn<+IBuE{c2yhv
|
|
zRJ;;TW>1S(^yFg6RT~Lc&ew0yV1}z1<UF&pZ8$y-ip#(_ql4wkL!|pnILv1xn!tDu
|
|
z#0Vg<6SHX1e-K1tP}?I8_V}^$iu!yKZ%BCvA7{W%h+X;1_o6(dB!#ph=^x;K6}IQP
|
|
zQJ=ZytGWBEkkJhZBpor5&?&JDy-oi<eM|l~p>vaK#Yby?7*^JB*MM|;Y{8h?G`raA
|
|
zqna1<#l7B=aj1hP!|gRcx5mU%u2TNXVD|!gN_9b{3=>ZKRu;6ZR;RCaT8tf1l27DN
|
|
z6ioSFzet(1MS&w#`tLO&g>Or=Dq5~`rS$EuZD3Vt>fho{(|e9^`>7p13RWjHIVNh)
|
|
zZmVdlHYQItN;{ic9A1iG2`FVtKJi%MRn@xWbNhJ{Y(`MWo6`SbN#O^9Kp+hj9p!pO
|
|
G8|43b__*%?
|
|
|
|
literal 16900
|
|
zcmaf)RZtymu&!}kXmDLfg1h^|-QC?ixG&s2I0Sch5AG1$U4m<HKb8ON+PC{+s^+4r
|
|
zXQu0|uKD_XI#NkN5(S9>2?7EFMOsQs1p)$M^xuU52LS<5tyS|A0z!B~T1;5Y)8HZp
|
|
zUh9YE!*I`C!>au1!lt}?^7%)ymXa9F0E8%U6cA@Hs@r2|t2YjT?MMEK&sF!xR;P(1
|
|
zJxFf8OgT_&`%_^18f74-j~9B>_v*F_4QG7P$=~I&{g0k-!dKZ;dhG_Yv84aKQ7`JU
|
|
zJ^ehid=1+b=_P#o97{5v??~H!^zyIS&U_=f-+Z&XS28Q#IuJUNE}ApzE+z8$<M**`
|
|
zKIU!g_So>!_(s%I3_!)=jTdGmXzz2p&3&czvSwVkj_PR|SM`xDjT-m<)@wFKtJ!fY
|
|
z+A9f&c$RQF&Z%Ui9@S9nRjlxMs@)Z5_OxNu^|5JS^tNFPeEv!Mp+fj^Yc}Scf482J
|
|
z_jv2_UYgabd?1AMePOH(|ApkUIjM`|sON7?4||4r>}#l#)Nj}LPNV67U-a5cAqgk9
|
|
z4hA)b1i?G`_{?Is2NgH3=G*Y_oV4G*#y>w?4I7fSpx2h|vD&hsqdFVmofnVkNpM8o
|
|
zEDOkF7WVse0CrXXeH^X&Y+X5Ugeg(@8XVq_7ng<WSLc%Q<*-QIhnsE4;ZV;$Me+D-
|
|
z6O+kzkagG!u1}sMYVY^UJljV<@ZpQ$9%*p>H%kQ4q8to@(w`VD%+t{VjBlZzMA{89
|
|
z;%$e2aiD==VT$}%!%lBb<H%>Y3xicyog$jB!Djxd7vpR6bXArR{Oqv(5MfWsJg3Yy
|
|
zcUpf<i*XRQ-u8j=yfnTAd<;#}0(9p_Mh7gx&!`jRA8$wFN#<^|FB1MW+fs1Cf@q-!
|
|
zU3MIdBzL_H_z&sj^8+k=#YiQ^+$Ny8yzr0AeUGmYlYGdR`w9gb2Lx)?IbkwW&1DO6
|
|
zooAoqd!IA{afAE)J$MNE8EDL($_Qb7^jY-Tsb5DMjT&SWxeu;&{9Cq-;QIVXkZ5c-
|
|
zx=+LR*Y)a+RPIfjC{LhfzZvst38Sh@J6SdEVEDi(KywY$Y+}Jl1d*UV+;mz*KDAhz
|
|
zh)mX?^+*da+?k?h8~OJJ8$%paIkEkT+36F4*KVjH2cBc6;=dfslN%vAZH(Uy{cQfN
|
|
z<{05LX(3vHPxFA6xPb50ypE5TCZA6YBZ}<-$vEI%pfjQkh!CS-P8y7_5rEIXH{0%v
|
|
zq%!E~hwvPQHvUZ?Ef@P@;F%J@*kGou23nY?0$xpm+NOfZ`fm2Ene6n`CX^hNmZavr
|
|
z3T#cF-q`UEca4lZhb{Zv1|e5Gbiv~cN!HZn5QX1Ea4!8`@;BL;2G8GnVZc<^iZrFL
|
|
zmLJcfN#-n&{j#vj3m1P~7JF`tq<;B|g<?0_V4;>*M1f-z9ik)<Z3n&ko3>^?H|-}`
|
|
zxbJl0Xc<(adaW`;Xc^eA&$kJ4EZWH)dOO+mFzw;MBfNjA5<1ZP>E3RWzD|&L1WdK!
|
|
z2k&T-AdM3|);yD$reQ{x9G{_#6R5f}9%tdjf-W#_wS$qa(*X;ot*Gkja`g1Q_eN^=
|
|
z`0%;Ho3r-6zU-m(+)f%v8KxzXfn20UBXua$j&hd^L+a{0lv^F@IS92I<OY%c!ol*K
|
|
zo*nMA<@|~EJJV<8>L#!_sffCl2&zHVp_~j(J1np!W5n69+~xPAJ6}_zBa%4jtFt9W
|
|
z{@f*=wRJ|ZitBopGm<ha<ogQz0D}_=VefQ-dFzyrIj$n~KD=LR3L`)v>@A{J`xa&M
|
|
z)PY`TF0^X2?f!}827nOWNuI-<r$5<TE%a{e3k373M9lQ%RHs%RSr)PVP<kxBXcZnm
|
|
zgJm!x;g~C$@#FI_>}Ne-gU_A_rT89Qjihq3d_{Ugx}ge|kRq}v@?<-}sM1htR5<=}
|
|
zI1L1)$lG(bP|&c#@>`Np6h0xGHe-S%SWq_<x4Dzlch(EG5BQ%Qqe)*6^zW6~@M``#
|
|
zCDamY8s8Jaa~2g;DZ|q6lDf*tg~lJ!!^4{=$Wcp@h{Rq-YeCkqfsMBv=tV{(jCL{|
|
|
z6J7V*FaUy2Q)|?Xlq6r!8)bWEQlPx2ux5Cg5uzT>O*_rH`M&)M5xj9Un#*HS!PqE5
|
|
zISo-XF(NX8c$<8iK|uH&>qt?Q&-b}D+Tgr7t>MFp&WJTZFnPZ1>|RTVqu7iauEwTX
|
|
zVJi3CHpH3>2eq__Ox+k#@Bzl=K|7STdhX7MT{c8Ce71~q9Y&PXH}*iaRuCUgMZj4H
|
|
z)Q<sa+KPzRqz0O{-kXtzDagS<&%r}abao`SSO`yF|Lj?rpGDNntoJVWe}|8U>yHub
|
|
z_qnc(rzc$MCNk878`Sofx_>n{BwDNL?TS=$RO_S6!R*Ey=`(aG@LbB{HGQ+@MqP=h
|
|
zu&0VvO0ab!36xlai&*>Xc+6_xPmdSo9TasQ3?*TY!)%lYzD(AZ0HWie+au=#fiLo&
|
|
zU+O6Y`-6UchQAZ*C2TI_f~f(2hrMt6KE)jP36+(ZZfle23Dx>Inkk_7xY0&pkp)+N
|
|
z%^^0b-mA7bkD<)a8%J{cvSRJ2S;}#v9g(doR}TQ3QGy%7T$YWkQuW{|T0eu$!D%Gg
|
|
zhIpru$xwR_h!F-%c~|@zigH-C2m<JnIbRGUJ`o+s{0B$0h@KfxTQq^K(h!%+wnmUZ
|
|
z&+uH(<{{~AZ3;c1s&I>=8{D8VNnCdFPc6Rfz(8f#dDmuUW@`u=TQn?l6ex-ha;(``
|
|
zrS1uS-(@|j8cS+#fW*WdM9k{Fbp6f|!@JL%Gh}@yEWnT<?~y(gdk!gF4iLczhzP8A
|
|
z6eYZ;NxgqYm0WAz^WFy?M1rvTjaYzkZ-k9O0o`V+34a3+%6{bTw=UzMuGx9|_wc1E
|
|
zlzJB;CAmRbWieMfkz)5Lx6QlXVJsZCW2NX66{xtNY`ok_u9t5`tiF2O8sRN|iIjwm
|
|
zStm2P{thW%Q3u7>jE-<YhsXZGBt`Inuklb3vv0q7ty;K7T}G$@6MPS5K4N^c{Wc--
|
|
z!(-|(z>DYfVpx0s5?hF9Qzi@Lf>~6Pm?DX{;HP^Q242(r1D1_=jrbppWF;PQk_!Ls
|
|
zS?3Zy6SOYNhA^`C9Gr`$aM+kF+PqIpNc~b)YOTag^;@K{!LHyR#-D?kKh>QZn&JHs
|
|
z(S}LQ;l-T8IWrlT$vDeig`Pf3fs);`cyZgTesw;vUk*#=1ZlB5zS``R@)U;`I^|DW
|
|
z?`Wu5^KI6hZo2(M-a~zF#>3kiX?zjyY=f@)xk3s24jF8WN!RqnV5qMC{5IS-?p~l`
|
|
z*Od<2Atam`NRWyKlq2%T>WdXRFci|p)_QD!{us*BG6#&@1J>-ygf`d(+Yt%AR?$|m
|
|
zG2&h}ZNhe<x)?3<qMqjG%(&Ex)~h>;3iL&t-&Bo~bSQvwc_uqFF*q*u<%r&3Io&Jc
|
|
z8X3Bs8jXqH@NHmV7BRmCYCHHs=Nrep*-}>qojz9eD&96O%Es8n$%gaSnOL~VE%6i@
|
|
z&N;!@pfy%G7dw?+2y1|uMDE?45uzNTNB_7>aX);UvtG>N2^CK4jXJOIypMJdF8LKU
|
|
zTYqIdp7&|wl19M2-A~xsFLDE9e-nocdK3)_YdtcQ)W%k7bx|ihJbIc=Z5ZyZ^yh9L
|
|
zz(%H87tSJzNkw!4yq5hajBkYU#kO&cksLk7!K-`GO(iyvT=U{|HBlNQU1VB|)w$-~
|
|
z!`vE~Br`P8J<1%ly9{1OIZc%XlCTOPAdcit!jhpR;%=Zn+J^5sT)?#vtC4a+pY5iB
|
|
zJDz5Ru-Z>~+fH$VWPdd~FVQ(AT}O25HPC_wANYArttZij2ISLx>m75xSQO6+R*;0g
|
|
zmeuq!90F_}HX%kFZpuj4@q)SDa3k?+Bb2PrSZjTt%acFjLT3$4HPduPZ4Sfv?#~)_
|
|
z*x>rvxpNnXh2P;_1YzBnVcqa9VK{mn1MhEaK>}|FhPXm?dB28(cqh2<aQ(E5eBk$f
|
|
zXhOu5zd5gn#=c+vTG>Ag&XIAnbGh%w38mufD688Vg0{`stk3i+PA1e~X7W%o(N09G
|
|
z(V+dK5Ra`6>fQc$6V4g$Mc;jTrbmt|ZcfPDi&luFxnBGk{2GGnMACo~C5VWy9A^BK
|
|
z%9O|VK>O{=o7e@%H==p}Gh9?4J3)S(^K@|@-bpGMlMM#a6u}N>;hDZ{$m0w+?{P+i
|
|
zv!bb`WN0Gnx5bB0s;!iJeK(?<LJ-dXRu>O@&xo_Yr==8dbs9N^gw0u(XK<y5w?dyc
|
|
z)a$+g&xyOCWn;D<z-4)I7QKFvmV)ZQ@wBYI#3q%m)W*lhSISyiCsazEGS1p8lE1)#
|
|
z_^8FfD5K8oA3|kPpdN8v1L{mwC|fV!*`NrE)?hzJDcwO>a5#%g4gLt%5d9^x&bUp+
|
|
zI*CuQXb^F)LGcsTq00ke&-aZbA7<pGjOF(_S|Pt5M)lu5W;92@!*xG|2lh*QeQxy~
|
|
z$g!BuyQ8D9vma$My_5FGv532J!R?oH!Re~vD^o8a1UK~>b?Ow}kNZFJJuWYsoo#JJ
|
|
zd^|iHd;0^2Lk8)L=de&2-C9OWIvMMW>WH|w6pe<w(C{@#n$-IGNY&KruO7Hu)T8vC
|
|
z*muol#eb?iAulS}{q(0Y{Ez0Ya)G=5Wyw?cgMz+VY-tLjPQJb|z9k2(@WFTc)Ok2)
|
|
zwsm$+w2;kT>Ak$qJ4MH%Wu;|h=~A6+4h{@J3knK0*pJ@vag9^60=vvWcI&Lb_(VX2
|
|
zy)N7VOA=(g{REg_f)&_ekDo9i1vl8j0R0zl47}1}4kDqz)m%np1-97YCtx<!sT41J
|
|
zaJTs_DdiJUL7Q}@LegMCL2ZF9>X^_8E<IMcJZHX3{+Yv$8*d!QPI)Zy<6{N3SZ2Y(
|
|
zRHQnRbDzsDSYt-;?hd4D7AO=(Pd?VXhDTW<-~l7PGp?<CgEsMLp#f=K2gL1M^CDQY
|
|
z2YE5P`rx>b1U&2>fjdHvFw8)9n=P<XR)vYwTQ}=fjxb9Dv{WAW=&PJ?Qd0Xk00<jz
|
|
zJE+ilN7%&?0!w`K)fPCZi))*i)-kTY{*@khj$U3|wErJ%b?gHGck`onT`i&xz~QEN
|
|
z`fI}tw%DtJ6F{2I8G-#PUVX+U6p;UNz)MLLE_qH4(ZTki+;mr_0Y;Hc9334!y}Tkx
|
|
zpFe#J)=7Z*@<ezrJ%5$(vUJwZmBzt8JY<a)%2nYRbX&xN;ZW#NBQGE^aULLpcYtW2
|
|
z_2r-Qj9iZR3E%CYD7d-t_J?B!#*(RS&T4!1-kxvq*sT)8$?63_#~NxKPqP5Lq;lys
|
|
zK@UUv+ON<mTXIHE&(Haaxq>T=mS{*wNJdpIN5Au>lfU5v4<160<tyx?ddd-t5JQ-Q
|
|
z#^Y&r#;SFi`y0$BoL(O;OpK&no{w^8i)C@Sd3Yk3Z?=!D?X$oO4toeT!H#f%v4wA{
|
|
za7E|xN}k@{1^(|ZQu6ZR?(Uq^Vl4XY-(h!mcgxhuF^PzYbNP~2D1qypy#5)QwS8VB
|
|
zNT#`WcWJf>teocH-d>QHxOk-7@IW}47m1u$uA~w=(B0jA`kk+l2DCPaOxmP~ndvI$
|
|
zYkm8H%IFn;s^>pUrvz6NLyr<`Ro3Korg8A+&kfO!G6vn2h>XJTf5yvnnk!b`Vn06=
|
|
zO|u}x(#U)>eRZq|c{Ep6$&^P+2{n)IUvm+$hJWpRp@dc$Pc5;};;;?#x;>0!Q&lV!
|
|
z`h5GsX89Y7O)`a6U8!1!!`XBAGrQC|6pr$y?Yi~{n@H;dTYvsSV}Guzrbl=`^4UoI
|
|
z8~S7M#L3iCl4D&LZY7p{pxhZgK`flMwzluNP~zogXL!BoNYnrwRFOn1!FLoBg%hgK
|
|
zT2%$)cYHjmbW$l?<>3q586J5ELJKn1OZfwK6zZEGypC8YxWSi_nBA+Z_&{j*y_tMb
|
|
z6C6(s<>8a1YQkTymwXrrI?Xm2Z(XHsp-_~6s;*Hc@MZxKw?mh=jIMvB--jM9zQDT5
|
|
z_##%J(qN!>z*rOmA{Oc8*IOL7NzRt42R1uBo;?F>^ndx{qY!eko1xoqPknBbx`jeg
|
|
zBK1!If?!CHwgxmCjWr7V)0^wAxV{-lm1HGp@U)MCwN_MeX3LZ*<Z=axg+87rNROr|
|
|
zGk1Bt@5+qfq9O9P@jq{KmxjSJf5d$^x|QZ~Fy8QBT0N;L=b3Ha98v{T?!a<*H!Oco
|
|
zIhX^3<(4C7)s0wzsf{-e=xaD8((gATq$_pC!Q52^`1G=JH%YOOh)Awkup!<3Bb&&D
|
|
zPqzKKb`i}X@B=H-Bd~YbHMOEI@}9^-?1=1qlLdT_OT6u-ZGcf1-8B+SeEi66pT|r)
|
|
zwEB=TP-zV1l#zO^!F#)9-6$r|HF`OsuObU}`MndmLi2gW$9S+oiWz#B5iP79o{6bK
|
|
z6t&rf0~tYIu6;`z?!b$F5x-iubvO!}PG*C|1o8c0-4Tz?B1YV@ZWIor_al#w4Eg(_
|
|
z$KQrUKc~@M4#5WlgcH^f4=o(+5mB;?FztPJgyXV#w8m61e_JT{jLWsH<2^Fyzkt-!
|
|
zn7TS<xomEX_V#vPeqA-SfVb-bwBxnrN@KWa9OUPbdwNDVsU`%3zb*?Nw~g=NK-v3m
|
|
zqybDJa|+12fG~a%)UilOSl3+gJO)Aw>jEL+Um3h1ahneA%41;uV#JudJYWnF4<<f7
|
|
zzG9QWf!F;`AGBVZlQ7I&5}VcmCIs2hpQ8%N-OLGH-?tPW>o}yV;v9^YzeZ9DJPbxV
|
|
zCaJ<J%(kHO^{0C0gfV8icm-@)esj>z8JMuzS|;y@^GISocc73^ZoFw_q)lcpJX%zS
|
|
z?3#&5BtAW>(BMlU0{VA<|F{5pf0gcm5u<ioLW^c2W~^(c1nYDT?@BPLUBn{Kt~rr?
|
|
zB|BshuqfYiwi_^7$beF+(_|Gm6pb6*46=?!a@CQozXRZ`;wAJY%541p%ki81znPfy
|
|
z=$%(ueBbx#JD2|Oa?8+7exd?=;MxFGhrEe)2ufq>eT^9u0&(YN^<63?O&=!S{pn(`
|
|
zLg_%W?ebF_1IK2E8}fXKJRN7Sd1NEd3=zE}{Ff-5<hkKhjL-603?!M*=!CN3Ajdtt
|
|
zFHx$lpNhxfi2h+m%}kE>5EeRtg*n1;E66aMQp_*vt;2W-BHy(2b;Flg4sLL8j`MDJ
|
|
zAbfu?@{0+Il12eRII46kiNKmt05><cmKj{M9Y888Rc2DYHcpi<g&%kjUiB@*`KV)i
|
|
z#Fsvm&u^Vx_(p$zP`;Tr_Q_@N@e?y#jURaDNWq0<H65l6ZTcCMOR&h8Do(;m>iU=h
|
|
z$<m-^Ib(-mPuCOhDM(sd%(&JmzB)m`re%hRt{Dmi$-qm&$ODM}woZ0d2QRdc)U|VI
|
|
zesAe3mx|o3@cdkhnrPdhY4g*wTICkTcbOhTK3P<LCjlZ-2$(0!%T_5G*XqoLZ$W&2
|
|
zoeX(H^9#lA<L$Z4c^{6n)cji}fZON6t{$Hr7TMy1hrjYG=tm8sQ*?wxW60O^^z$fe
|
|
zwu_s6>)Irsw!hHw5wf7*gjxln_O`c8!(m4}pSsbqKLIVrd=!}5jW}+WPlzQ;+_e-&
|
|
z?Dy<48J&+h3*<q_`1T<r8T08<b#zDwj5C{&*BATm8$AI5_4xE$TwKXVH&vW)g90Yp
|
|
zT}^2-bk0N;#}&r&dzo!1C#EDxcK2(q%kRGq_L~;|B={e5pvha9PCrco6sNv2OYQJK
|
|
z`KU!nh5QiLDT2-HCCe24(ww?TW|yAA|3*r^bDA*!6OvQ6=nEbsBqScI8A2Qpk4lN#
|
|
zaG@CN%UZK-^psJ#8g25?Z51b+*lZma|2I8w&jZXbWo!TW589RPVSJC;OstCn<nM2-
|
|
z2S+b{6C-xz(kY(1hP3h}VS&z)XyIEV^+!tGw?v{i%6E7{&OU<dW8`;_h(55cGGCZI
|
|
z-}s)s^0#T>@LUmFxqzh_g>rb^`iEl)hiDf5($dZZJpaL!%i&d@Buf3+M~(|w0IKfQ
|
|
za3X0Srk%nLvE~Ab9|gBtt2_H<(fw_Zha@}t^K>=dbE+8{uYX2|#N=bmI)Wc;T*rwV
|
|
zwd<qQF5ZwXK5Ad`lnx=HAV`+CET<7}W!P7~L^1@?exSN;0g-qLIHlq6d9Y)-9`7sz
|
|
zmD<xUW&V5W9@6p*v)UCq_9aWHcDBC6$RNAiJdaUdkxiRt@8+A5?3EuZ&nbZ~g04Qv
|
|
z+N93Un>5A@i2kamPB6hHF1AG?W!pUo_~vz+3wdlN<%QSGe!5}^qJ59h?#udS@qUf7
|
|
zv-9ZW<iY;T-pl*r_RYMakia7+7VXT5XUz=&=YC)>cl%ZgYEV62Ov?klP4Ypq+COVB
|
|
zzbpQbKJ4p#FTFlCeU?M~M)FWg!L^__)A~q8ym6&0c0f4_^d1Qsf;q;YQPHwFTKQaY
|
|
z@}^_vfdLrw7oSN5$O~22BEUP<N7?!egjAd%LV+GFBk%{yaT{IpneWzqjUui0h+&Vv
|
|
zfWubT*yplpG>Fgd#kF2FBsIH_Toz2Nw=v^=tZBu!NT|Lp7qp(fZ&&7q@7C0rFJD6;
|
|
z(%|4PztN>6GF#&@{I1tbNIIaALQ8ulFL8_Y1vGk-QMPKSZe0HpMtxgqkoct%kuq`w
|
|
z#x-}Cb*!ytPr?%+STtAMUu{{K-N%@g062$UWI7UOQm3=mc9wknbhD2q<j>Ej-!b^P
|
|
z%oYhuwx~lumz_3B^a7bYyyq-71@Fw*7ULPhNJocwr5CvLRsE<~sh>maF=R1p!hO**
|
|
zh+7MfH?17kb@`xEls`270@5OICG>$(UstdYt%lJ^wwiJK8I1@$5SE2?UF-^CtL8@;
|
|
zs4{#zGZBM@8f^QW&S9I{2Bl9>kdJkdQs6??R6c{5q%l*?6D-aNSM(>Zc4);q<1&7n
|
|
zVSb1AZyvYG&77Xtb`dpP1hGZw+U_-uc%-;be&gSUcbi*hJ9V!?LnI5O4d&1TOrlrE
|
|
z1<S+|>1&b|=uC<L8aTvvuX9dFVpk|m*IEmR0}GHqjEWingb*`V#YU;@E+Z@ZMRRAl
|
|
zN_*h*ku5qb*cEQj6K-N_YpZ}w>!5&O5GB^zm!T#ncJ-bmy8|`YuXV_zy3)jPFmR0m
|
|
zFLy&N`z42~p5XU|+fn|GAIE2AfPi3JbxB>QXQ+7$3m_ug7v}~qfMAh#5*_)0mSKO^
|
|
z)R>_thix1PNC=^T>X5@o5Ik^s!>_0nb%0+Qu?l@fMu||fRMI8(eq@a06~$a6goXp4
|
|
zTc(!CW&GU`Z?7*~C%0!|`Po;Y-B>bq8(=^Pt<rP<iQcM7$|SG7sZ1jRpJv=SL@y#*
|
|
zEwQ#JwOl^vZ8pa4W0vb_HmmSKCN$E@LOP+5th*N)ua+rG_zVzH1RvJYNm52?iwQI#
|
|
zW5#vU2r46D@>0w>CW3cOKf|^OmN3o|I)zb~mlpR!VZ<ufcwLW;>RWgf3r$DjB6U@%
|
|
zJ!v9xOZ<+LBarT*ahaknq^miC#W^ANPQ%<$&RHDpEBCU_M(sbvsugC-mYh-fO{Sw9
|
|
z2eEARzci;On#5;xRA{kHL-zc9^rxh(B6&XXZ*i0bo|+5(tR}B*i$>CjH@i(J`<5N<
|
|
zm*!QawcKB`2qVVWN|!2bmCj+qMz_>lyQe41<ecu-<Bn%yzzizlEp*-=HX&5VRA7)-
|
|
z4%2D>Uc6GYo8|ZmgRouOWH<`fPtitAzEwsVe{gYe@!;OmfY1hA^J^GP2Zh7jc0#tW
|
|
zV;K{f-a2?ll{FjAo&kmu**_ByBXvrN+H7%pUgwrk*v>}T<%nfg$(O1#f`vAf;$Wwj
|
|
zK4OU>ekZ7*cXG`zK^{1Jk?6U1Z!$nXMaDUqNo}Oc<%5yn3pWZ=j1+|nlh9DXMmgJp
|
|
zw$>=#X^n__>L<R8p{2vFMsa-tMZAw+b!4w*{~Hs?ILY$MKb`ll%OHuFsPn@iLGzz&
|
|
zr(<R$^>z7RpGg`FbOM{jMF-I&Mx~Gtq{nwcJ*VwE0OFOdSNksknPO9!AjUy9a^u};
|
|
zl{GfA#HVPd<MtoQxnP@W)7b#^ViRq#kuCg}NnB>@8C*|vf;gcdLXrJL?MukrGr%c^
|
|
z`dR^O=T^5*G@CU0fpX=d2?dv}l#Z}rvrURI+yrK9#ndWZg69>4-LW#tEa5!`s{Zgq
|
|
z8R@zhQOojaXAAXjJW6}a5>uV1LhgG$u5JQ_EBF0C=A-S5S2BuoH^CBy68!ST^VMKp
|
|
z5t!x0xnCI*Lk$t%?=aM?bAC5Sk&8&Qiu@hZj7DiJ;6#WZd1Z764c#+#;>O(U9%lfW
|
|
z>suxqZ)SVz&lYoFmEAcgM7u2vPU$2e-Hjzv>AJy1PeOk$DMk`K`~^i^seLl#HX2s@
|
|
z&vS?_kECyji(-+eKdk1750r)$2U(RhTgkZT@l<$kC`GSck-TzG(h{pKG1aJhxkqgZ
|
|
zItykNw;mTU?xiP8Q;PAKW4yNPGkd;&0<^_8y4rHh6AzZ1@<X}MHxR~1w*H_dG}N$B
|
|
z&IXplBIDqN@xUP57Z!||jp5Tt&pmdz9L2TW`!AF!hrJB^PxZJR12(Mif-n#R#NUkl
|
|
zx+rtKvE7DS(6^neT}2A9{BXuZ>@Og1z$t3+RoVK`LOEWpvj)dqZ+bn-ZI_R@g2TDm
|
|
zUOXS$8{AioF8c*Kd%<K<R-Azr*inn*=YgH^e2AUys)JPOj=rj?w9#>YqEKoqkyqA=
|
|
z;h>9H=F|lLAffO3sj^3_YLHV~t7o60Afgf+&g?fx9El~tAP}$YS=MFe<j5P)$*$lf
|
|
zAPRmwH9CkE0Y0fD{A=Muw)Eg@o^ck}2J2opVQXezQM5xOn5HmOO_CJGfU}lKQ?fR@
|
|
zOT{BN7o*eaxOLMRMu~Ds9z(B{K}7c!FZs)gKE}_J1be~x@F^v?Vr}mBH~BchgVsA1
|
|
zYBoPZ2rfp9R!W$n8HiA|DU42gKOx-uSytz3^&m|2EPpKhDo+x7&9!omIz@pJU9%AM
|
|
zyf&(ISER(CT)2K&C|4a)z|b-MrvQ;;u1X&@@z1X>#gI{HMPF+3A4XgD2y6V7pZ8*{
|
|
zm8;APEKL9wC2F|aO=CXGJo^TSmQpb}X_X3Im%nsfn-Yr)Ip(;&N*#Ay_m3?ila&Xh
|
|
zA6V?kP!$WD1kP``H7hg@QY|w7?54~1UuB*oXqD_ePJg`i3GPV0EM`;%joWPh;8C{7
|
|
zYdmIemNAl|da??P+nTE06i%eXK303w@_~!CLz4QEZFdnUm~0^2U*Dh4GePdBsTQhV
|
|
zsihVr6*e(LETK(_Y=c5vXJenfn3=4BLe-LG|E6?ccR#tlx)pG=|6cC;SaBt^!li5R
|
|
zcPgX&c2MsDL}~N-O+3=a0$|oiwZm$c)<&SyI4_0A<srpSW;AoK?9|@QWZ?t*0}=T4
|
|
z95c7ZrJhu_jm;5WGD6vHJD(60#@Pgv(k^DF#6E7aA6jG6GBX94bT68~J@fG6iGF*7
|
|
zHT5{&R-&=MjO#)CG|n01+OQ$E>@|JEcP=7FY3^?#Of0zNSfD^&A$%$p{mSW|9&i*6
|
|
zj(_qDpxvBQ=^ptttH-vj$9~Va*80<33lpe5w3*6)d5BABGb>2&T7!J8KM%t$O}n*W
|
|
zJo+7yk8gR<_bN{XJ|u{lon5UfZc>HMFjulERk&KL*jqG{qadfz)xhuQcg|aymb_Y?
|
|
zVYhel3JJX|M+K*)DQMX1IZ`*_*vfscZkpLiT)9gL=cKs}uA(KzRP<4d8#RxOLcE#D
|
|
zJP9@OB>kt#JaeOXaqm4Kc^GYiehxcy4(-(f*^`-a9<3OAl0lXjMU<hs234e~Ga6{D
|
|
zJ?J(F>1<h|nzoDAyszrFJH(&a%{NK>hK=(Co4O{$8%UM|E#&*;l(B?QsiT<hhRy3Q
|
|
zdo`!hEqt}nWSdHIHdieB%+y#>24bqlr*B{Z7V`VuFjMMHlGAysOT^==1z=5qZQ_2R
|
|
z<o0b2(u?qoT2pz=0&G$}du^;#nCdx8xE!J;?vZWx4u|^LC|6ILAHTl|9+|#ph|70a
|
|
zRi!G*cglbdjvBYLI6BL$O5vr@7Os2u*>-1qLb)#p6A6j}B#jg`CWg~=F5uJg4=mk4
|
|
zMbEFlbNEc>OXUCT5piF*6@<3E+@D1YQ`=LOmdxBa$alJ^s;X9Vnwl%91RCi4CyD~~
|
|
zEfY~;r~^+zF4y_)m=yu>0s3+B%|pI?8RS^ct^$kP#XRzE>S#R+#~GhIc~p)Cii4cW
|
|
z9H*m(D~n23;e5HIw0*7&$Qv-cSkS?#GB%E4^9a4Zdg>n0VB=s|P>wkUFR@1Py;++p
|
|
zX;6LW6tT+67ZSct6f1(Z{;9<&8!$Q%dsr@?heJCLyu$kE{QNwMcpba!S7M2R5q^_F
|
|
z1m`x@%z~KA<YbD=KGvUo1=}c}9XjK~V8HD)rtTajaKXxH=c$#&F7^XOeVqIzd^^zc
|
|
zbIWe!=coxS%D8ek3T!6~BFeq>D3f^-kF`7BW3BU>kYEeLw+hLBNDUxD$O}Z7ySX3c
|
|
zb)wd!i4k24w<bSyiZSAUc0Wb@?Uf)*n?=`9#OzE)13Dy(y2(Mw;6+{;LZx1wLEPH1
|
|
z>W1_C2@tbyw%f-8qhJmP`&caiZ`w$^LAjZS5Sn#m^9yX>OCkC~g$Cc7>RooBAs^cU
|
|
zIlTk#)OXQ82-Til1rliQ85sNCA>X3OzZ4b&8XPSua_&2S?i?lbG}vKCBGdB|nXS>g
|
|
zJ0*+o--w^syM8BpvQ@ycNTP2WG0U^*#8-MC0N=cB;m&`}!LXiv%vI8XM1O%D865l(
|
|
z{g6XRuw=jeOMjz9WK|@yzj!yA9i}KA0|SHG<q+`sr<i<Pi`^JhieTLjCMhhg(V-g~
|
|
z1_PW_$(Y*eJP0Pp7w)=LJ3hRf2biP%Vg#-kH(u|)=qji?<Oh@6prwi5!B<IqYZl^Q
|
|
zy6<`LrPq}oMe*koT6dHaWLV6?x2bm~X<_g%6J^i<7ORO)4?2sRit)0sdJ<9yVGvuC
|
|
z0S2mC3WdJ#>1bi12L)S{x7e=_kAN~FN)m7xbSP^arS9Rd{|t-bdQUEl`8{54zNMvQ
|
|
zmVu~1GPeH>P7JxwZV*CX5cIQzmo3E{siDMziZ<Dq{2I|y#mgkKMnYVM8W2_`T`s}4
|
|
zlZye@&UWgvbNqB0;W!R2tbqs1w}M)H)52AfR>%<cunA#0ca#-wneg$WQgYl+Tt&IK
|
|
zGZYz+dp2I6vM2opv&cowpQK+;Q>E7Tl9Q4KN4`#}D9_*vX?k}pO!=)gn7_4Bb4bJT
|
|
zqDaOnV(7U1_j;to@cwADU9mBc-@BdBUmAHSzyI{7YGVPi_y~b*r-e;$%CQnDe?9;8
|
|
zfw~{4mSb>(|FgeRQE<@@i1>JZxfuACaFBgBIQO3(xsqo~Se?tnEhWOPgi|!6k69%H
|
|
zBXMEw6q@;gX1q%5b}P&*(QhwjwHm7%kJPg>aV1XSsKm6t<)rE6*j;x$hUQ|hu`kT)
|
|
zV+}ADC0AEh_W-HRr1Y}-%^FExK~@Y^t(ANZuuEJ`p#^k<`-MWnN77L2@X=9jV+>R;
|
|
zXOQ`#-WMm65hugihkOgXY4OID(WpNU{=B$ZDs8X^hCKKCdranviTkKK>$2J_;-Ga6
|
|
z>WBEX7GD$0K(CoP7J96eYCwj_U5&HrOXJSWm=N0MQ^#7X5>(8zV6XiWLH3_Zh<aeV
|
|
z8Ndz-#X*$y8IDR*%bV{Gp97?Rt^H4qcV^AUv0!gF&}cM84>nV9@qF1Eb95#jw+CTK
|
|
zcnC_X6?w!ouwb8!t?ZeXbU*`_*tn=L1`tKaPq~o#XH-LT(pdaeEr(+5o7_BF^YP^9
|
|
z=s=xqrRelm)Z^rj$VCV;RnXkG!NaMn=)gAL=kN77LMYwzIqFtY;-;Q!9U{UKkl*Z;
|
|
zxmwdAck=k)YYlsT2UM!0spVa*x7IFL)Qt{<T{YYOnY`lQI^(7M2P9V+PsDdz9D4(H
|
|
z_uC&kBA}+QFqdK2PUEuTsqE4@^B*7j;oxh`V9FrWk=ulg?!EAw%IrbyYD#^ur<#gk
|
|
z{LJ1iL0Pzm1nz~Vk`4y?*c=}hc7M0`eSeX3@*qVqdyY+Hm54oWxpS6AC3d*SaOK{i
|
|
zMIb_4DueFcM!U;fEA1C)Sl)|&O>!?hIJJcZxQPc`eiw~~Oj@Tz_oM0xtx3Lb{5kxu
|
|
zyBD?uz>WN#g_E*U&crG80;MCX-DnFuJuz_nIeOw6$6c?&s+F|L2zU?5G!ekeS!llo
|
|
zFPgW-3Pcj<t6*$wk~%olXuylH29jeB{WFT%ocHUz?`>`}O?5W?ab_h%Gy97f=v~(o
|
|
zy&qFFhNcAIGR5-l!~O!ti+&6tBv?y$VCZ!G*COZC^Rd=v3DD{<mn-8DDFj7)a(=aD
|
|
z-Y`eYO%W4BP7x;!8f&Czl<z%!bI}fYCg336HEmrGi|zPZZj1{*hK6sTB{)Db@Ahz<
|
|
zT1Mkrr|m@4hL3vR(STca2f@Pm{<j=dva8hN|ITbW45+Uwv0kNGEfo(G4`o1Ew-Ule
|
|
zDL&3gJ4JO7r9H94%%;<*+Ue2Hkfxn^#;2DxXx2!Ig*@qp$PYUl1}EU&y$jvc$e#Wl
|
|
zL#szfFJmz5&EKaM?Q__+&mY^%Pvr8lW%BDEaVV#`$}|M|w*-7clRhNl6*UQG&ylf%
|
|
zkPu~fTxoQ&W7V_sGsFQ)r8dZ1tToU6^7C;{W7^ylj>VK&YZV`0rM0q-=5@nOTtcx@
|
|
z-`GfyVTF_)=xoTY-xG)BHAl-#;@k>0Kap5G)B~X77JGh`U;(W#+Xleny2|+?3X~v9
|
|
z@j4(Oa(GxV=hv@n1U4Y(PY6pg$c&Ot;)efq)~zTw>;uHy`pS!hYaNUHxEYhbgRg4R
|
|
z+}+}7o`g)4OPEQ|;tiYeawTA$%HmQyClOH{QqjoI$3uxnpv;6|Hoy*8NC^3e-^$N*
|
|
zqqby_w*0S5T>t%`@v?z_`@m;FByBE`COSJ7m_~uq^-Bim*HTzq_chCA9jeHpXN(2n
|
|
zwRqW7h)`1w=SY~Q#F+#wWc43wU)ql>D-{W#MMi*+Rc<(sqj$1IsI?*Vo~~JX4iGFY
|
|
zSjVn{Ia}(<$;mhGkK6li&$laGUX5+PgyS=U#yks+rN3QUeb1{R0P)Mr;duDNP0Yns
|
|
zOl80yG--mz(9cLJmrW%6skc}}J*KYlL*%B2MMfm>8W3{uoeA1tCC<ou*r+;3^qV%^
|
|
zACDHhZT%GhF@?jT47^G`Uefaah!pcZkv5Mk6-LNJdXye&)fqvWHFMeba%$acLKIon
|
|
zKH)D=>=;U0l+}4z>%rz1`1Gu3qlk(DUqGWSub-M#qTbUB+d9M0<eVN_uP7C*u^78~
|
|
z_zX5gA}C@jN@oBD9F3^)Is>69OLgJ6ct8Id?;aM)g-r9s^V6BrQ}Q;SCiP`udh7DC
|
|
zQX$nG;n1i3pom{#4@R?{E?z&>^3sL?I2rH<Wis|q@F<NBuC69-5#ZnDFFs7q#yC7D
|
|
zlpG#bra#0nk!-|k49aBMY~DA!rYSnil)LO^5t1e()wKAhNCbSmBV(ftVL(5Zu#AL-
|
|
zh4=c({?h97ka3R=vuQ0^soDSL2f}Z@U(W!5npx$ud><%HigVl9la73e4N^TR>PE}F
|
|
zsi<mye3$v_EsN{Q<_w8^ag+@iY>3VDlCxI}2NOm!ndIQSbW~gNZ4rN(jki^a>Fbq!
|
|
z<l)or3uqOy1dAU+uAUth3aO6@e{U5Qh#`It<erSmrigfqxCSSjXavqUPoep)0*hU1
|
|
zO&UYWdT?@(8G{DVlAA6~EU%*A5X|H2O-E9#3G=Bi7{1TBx@%AV8+f|Ybl;aE@qnl+
|
|
zCkd`O*1jPhCouv)!2infb-#EBne0c8_r5gc!|J#)6BUR=Pt)|q^$ICN*h)UM<!6Fb
|
|
zPM}6bb^Yg=mw0r+8vw_?%6DThxOft}VRI2VARRI!Oq-8ySp+^+c$5N}Q18|W>qTN5
|
|
zzb`nx8&_h%Jrt7lQxR^o;6yE0jUGfj6BHag<YA6kT{yFf)v+ARIMlT8QG1l)3YU}H
|
|
z*Pu~o<8lbOdU_i9)^FO%4@}E?&DVT8vzm^&_rIl4O$Qr0t>GKnEIbC?*Yeh-mN_p6
|
|
zlP<F1%HMh`B|_%M)VrN&(Cf7+ZT#VL-V?hCQq(DLU8>omN>R(3=k&0Ki-xElR=54S
|
|
ziifTvy<Mb)okM#dm%}X??{BDwcET$SeyB5Q(PFxbKfw?BLh8Zv1L7W@BHWWc4|fy?
|
|
zf^44i3vaFngI^iA^p~c2in^6}?rD5OW*_-2*v{#ucM}uBON)w#4bGqDC)&v<zr`6v
|
|
zxVDr4Ly?#;bx!4S)mKf;<+v6ogdEw@^Tebil}Xo3r{CE;Cew^-9|k(wp*7kRpeKBK
|
|
z+kZzqk_5NkByAMLoqwjnwAVWpux!x@EKt~Oob-cST=7NR1P=|U+uPgS8oq*#f1yDI
|
|
zg@?#3^QaEM@Mih%^g>ozV0-H|T?}miG^F_wtBpw#IDTI~O&zZ=pp6zI7~U;(eX9v~
|
|
z%_Rrklp$gbO-9{o@iq>QY$8+WLWjtqUprlw=!9l&&i<-B;;B?gDuUYF04x={Q|PYo
|
|
z11qyPuIW6^msVN_PE8KdAMXa}bHL6LC^fQ9sh369#H1cfF?JZ}v`b#V$&6F1HA?9-
|
|
z8rMp!9QAw;KUupJE(75s%Q_j;=twh?gcLwR?pti!=J%3LhEmj*cmxEL#xOjNHpVeK
|
|
zJkF%}PF#r=gweO>TUjCt`~eJ7()chG!YE-`x^-8vG;ltjSQ*{>Exm{gthe@Wqr_;)
|
|
z0wt5sLc;HhZgRcM=_rjYuGPk6qTcdMHcs}#u#-NnrJ>ijEn2POpi%bVAyH$%NC@JW
|
|
z!9x#~LZ0#)=w{X8oW39GR&eJl^`<7%yQQ1IMRYe1(f#2jGXHCzX6=QT%WeN8>DptC
|
|
zHdSdtJVzrAI(JAmUV3k0>(|f-Xp$15@*N%7K>n%=8xkhRkB3QAUtf=ah{(e3zoSSq
|
|
z_gFfN{zLz`jCqlr&;1<zEHX&}L?FAirvU!(2Y|Cm1k|>O+r(+F_Z0oUu;MXftO1`Y
|
|
z9;O;>OCXbj;jbt_S7jVfllzmVYhq*#nMM~j1j#8VFg%#?vdErxSYKI2XR#z#^jrF|
|
|
z60VzCe$K!`P7W(fGZ`zDbu=Gj|Fluc!xb3b3?KS{Jm5T)ZILV)F5q8zrZN3x1!?Fl
|
|
zj24#65txQAH>pypq52gcF^Lw8LkW1LoMwVHld&c-soCEOJ`7#g5|?z#rkMgkK7BD?
|
|
zv5)5fIFMR6Y+7b6;Ou);_P~PlRc2e$)>HPum(WG>M&1%61LbYx=>T1OuOHP=A_2Ml
|
|
zUJa0_6*NB&eSM@;e}$dm67YWg_RVCo!)>o6Rkzh4GG20Rk8#RK+5<zUQ@NQZ3;N(k
|
|
z=}G<i9?t87fyDrQ?!$@5$-^dt{VFZcEK`7-dpHK))QVHmNvnXg##tkOmFbjLy3w);
|
|
zLi&t$Avg^pe@MEVBD$GSJ&O%(R0VF7CFR+)b*NFQ&{m1-m5EdlTcHJjaKBrCPsyt#
|
|
z?lhxT$$?5cyPuyctpD}o<31z==H_T#4APvyTFMfUId|z0g6BNHXY!VX5o9&+;>)kj
|
|
zy-EvI3s#yE&SmNou7&*UrnmOiQ_-c!M98x?rSX}WW}0I7mNW&~u)Vo_w^FUmMKUp>
|
|
z8k)=i)!=z!;!K+sl(Lhz*Vd$PEuCsaMon#-vS>REEy6K+i5a(<$=x(75fa)xG@=%o
|
|
zR1GQOG=s!5g(EG{JieFH*|kCh<dflcw;k5Rz|^QeL)V20*~xQ=nQNl8Co89(e%7`}
|
|
zO|Y*q2%F$1-S^d~3cqGi&sR%?%qO&$UU<%F2zNfrqgkBeeboPHkD9=Mq<A2J4`k2c
|
|
z2#PO9Dvm-x$SAQduVt#{QR-CD`BQQv>7=CEGG~xLSIY@MDuIiAnc`G2Ge{P@B(m6G
|
|
z!ibqfOA9p9!7d%@C@Z6Oj!J3yF%OjokW8F{Y}gut?pbEsRm(4LL??RqN~(!1fsK#O
|
|
zx=08kW?ie)L(K_4s$=P~flB)?<W{NF82DcZG5TtJ3lB(x4deiq>RT~0m>*m4)K<a#
|
|
zkFUE0&$xT=s%xFIDmJ3_jGe}tmd$%|o`x+S?pO5xBkt@`6R-gZq_Ir5RrAMWx3z#M
|
|
zQ9wjFASMn0)k6ZbB3aez!=i{JSpJXQ8wSsO{Rx9`8*Jw`It_?=2ZXtDhS&@UE{Sb+
|
|
z1cYBhc~E=d{G<22g7h+UX?|#?E~|WFa&xtJ?xX4@5tiRN+8;Wkgf>}Eg&^ysOF8lN
|
|
zUHK0Q90oI&{$mRN4;~O7eZ2)RYWiOSNUxax118K@axIASH?!$hWN<QDk2~>TeE-m<
|
|
z9|d2NgO0N~GYHc0yR$}HApgS_*(Si(CRarIKe5r*$mNd^46r(X7=_aLFxEIYsbgvH
|
|
znrzh|J#4IY*379ZTcw$}tG6{QE7PnE4Rz`3%NtHKG_U~aaSk@Sx>k@6ej8+~c|Yc1
|
|
zO&By$u_ANpr;D`5D&%W#Fdl9`BhvdZ5`UZwLv{1Hpy9lA>ut_To&@^KV8eBInUrO5
|
|
zh52}zCbS}L24&AucCm_(e?;?E_ef|R)nd$k+BOlW94v|UU~blRLjQ0ZP-4r2%|3Mn
|
|
z>o)c|#p9v2Mo^cLhvg|xC^b2rL@3y2qYKOs?@M}`_`2q==9(4=kTk_PZBIhX-PBrZ
|
|
zr~4n>by9I>XJ-@K+>o8|G;Pd^cW)?r)m~#|TJhd}QmeX{jlF$FjtCHM4zkU<60>Zs
|
|
z%Hys(I^Fbs!^Li)<*(mdMDF~twQ_bC9DMnUdoO<&F-3^A3(9GW4<SRa*?EWyZ`Gfy
|
|
ztp;_7>BH?t7v#5rXa(*RMsaFXpk@rOtgnql#(8*wa~=>H&U<Q|@mQPKi>=;wN0Q<%
|
|
z=~0Qf+>{j>5oC?u{)Ajpd<^k1GgPzB2_X<j6XAKG=I2Pun==pwKj6K56E|&82n<!N
|
|
z*gZh~dZ~XuK-zADh1K|J_h2NrXDF+Utt5Mn{b>=HLz81#(ra*Wz}OO-za_H(wqrv+
|
|
zz0y`v?a{P}lFJz=@BUy(A)pd~b{ghG$JJ7r@AlNxR+>kt6nYMil7}v99Ja?<@UZ3T
|
|
zeP1&kMRSM{5+R84Gc9j#ct$;ly+^es_n)lXhG>_EcB%`8iYCWLpCv8)3~8MaxHrGc
|
|
zWH36`!Flt6p(JJsBEPqrE&gHZ?iZtxyx?@fgPx*GS)g<DtR!|7O#4C3-<&26BCuWt
|
|
zerw17XD^zR2rv@=1^LIVEv%k??XiUQAMc54pe<X1gXwY}D}AUS!dY+~%?)~iLq63N
|
|
zz8@MkUC4>o(Nf7>mW01|;SB);nF)3s-o4wF7D!)tc}@L$K1~NQ<I#C`<^M5#IaG+p
|
|
zY=)o(ILI##h*E;uL~w`+KjxW?7ajugykzXTJqV*@roI?2`+v(0w+pxF_kxqaQOlgT
|
|
zUd)zQ7Gs!mqn%VJ4?;n<-SZAhOQ(_B8C9<RxBSTSNibfqBO+C}`wi089v4cu?tLqd
|
|
zq=x-=;8Gzjeg3ltkL&d6_{$?4@3*dy2VO}1QiS6ksot_FD0X<*W7a!#r)8YzfwCVl
|
|
zX&BA-$m|MbXd}O8pK7$BDw;B&Mm`94Sw7e&aI^~$<2u$ZA{0)8PI!GLrK_X#D|4>b
|
|
z#Yr2Tunx+&wm$nlh2CtbCg8*b5`pf^Y+pukoQ>UqK#>9GQek~Po6Bh899xq^a4oaN
|
|
z9sDuzXNM=T^ExFYu?oyxI-}8y%D;slDQ*$`e5+$KKq!pF-*Qc6*L_WdXk^K$IEown
|
|
zc`-GIjJQlcjeh%cL}$EWcnajL%v-BuW@70M(BzzY-<$NJlWQg2rNIpwvZO(rx6c;G
|
|
z_UBD)7Cj+GP^Rw?)N_Nikx*qcIPWa%MBy?TL-6TWG;|5d3z|f%7il*;Ac9f={o<JQ
|
|
zl^wF%vccP=_}`iM9tJHGMq+Mknc3=s3xOCnkl<o?M;A__7=hTv)ez>-sOWXfH2ow&
|
|
z+F%t%kw65bbTBi=kaCFWiK~y^%2iyKohma@H`Ql2SmxhqN|;zqx3*C&8_FG(8wPqn
|
|
z80VlP%Gr)DvZLLlMf_OsXDo*4wm909tv4{~9yF8NS%e&sJ#dPsVWzk;(a?)XK|KjU
|
|
zmKml2h#A~>%-bFxM<7`wSX>`I?z8$Ca++fy%HqqV=8QYYD~bl^Hz_tBVxFF`f!?T6
|
|
z!OC4>a={OOkbTFV#ew8k2GrG${kNo(r<D-Tit;v+1#X*VhOyM~G7)_|P3Jyv5sQ5#
|
|
z?65T~=4%^@K1D?6sQN|m>cXXA_NWUqI*@?8f!7jnu3$bUg%u}bhY5Q));;cCAc0gS
|
|
zHeTk{K!dAfJ6}@_zTLUn#qe2z2>ZdYkePg(!A+9v>R>`9$hU~PuED*xe7hANwC~xc
|
|
zzMc7YMmZr7Iy0P~w;nbL>dml8nV{FL;+xs}qjWkGV5~K1I6DPEC&#K9z5E?@9vBT9
|
|
zvo#L&#*9687;Wd0D#-M4&3F8(7sFq)qrj$;8%`og3#@6+hSB^|^UtXtP#SOBvdY^G
|
|
znH{rdVJq%P=QxzF3KPx3etK`XD%|1rVH#OZ35YdYtyAh8`vg5MW<WWkk;SsEjw~)f
|
|
z>d_yI4)jPAmo4j_!3e<(RzCocf`Y+$BAs988hq->eMY}S?z>|#t_c*3a#|wBAi{r!
|
|
z{dW0rO)!J3t~1!Um(@E{ATxo*eW!!k$}$1~;aQ@PPH8`A%_SDxVmA)U!Hw)$KXA7$
|
|
zqdYbaY15D(b-OI$URl0+-TYf+!wm}Fwiu|ApRr6t288`7`y!ZbjuZgH`OF0cwYAez
|
|
zqS<wgQ~5PjMPN1qd)3bZ5wArDbnc+RFC;BsJd7!}|JWV>Ft2_caUMO6L4Xk>1Be-C
|
|
zNHX4bgVd8eU&h^$7@$FnL%%Qp$e+fZ(4dAotr#y7!RrZ>u)-F!F&*jOE8kA5rqU||
|
|
zkg!kLmDxaol3FWgZ=YGJwHYE#cf7j}8z24RotEJKC)?r64}@x}^89m-1nf<nRE9gF
|
|
z84<(gIJR9@J1V-~dt|?%zR{qxLvnIV98j`eTA;GJVNB_Y@tKO`o9{#7JseMXJL>0~
|
|
z*_bz@JP+Ml3hd*HWuOR@sNVh74L-Sw?LaYKwKo+rvy}#|aFc!~jT1o|KFR)cI+)Bn
|
|
z7Gg?S>|0zfR!%gT?WBBV*!!8j6W>|lJse7F&5>m#;ooWbRQhP@izf8nK?3n;AClTI
|
|
z6#M340iQgXluMzeY19}<(0FQ=O$wq@ql-?Y9&<2A-S>4Nw#z1Z-(e<j76&JVo#?Yw
|
|
zh)dmRov$*VhlD6Tzkg;rvVHK3C7HAQV{hy8K7WSiQJ%3H_%qwhr-@f?5#goio+=fN
|
|
zU{XsGGr~dTa#)e7rwzgso$wD;2@lXXH||yuwD}&?-@{=a^kD0$wnE#T{{m<i|Krq=
|
|
zao%A00ohlLP`<Yz?^o_stJZ@W6--fq7>OaL`iCMI&1sAHP4i1wfU%}{TH10ti=qYU
|
|
zDz0-eM;$$6p`VP-jrsMCM}MB&A!(m3WE#f9F_{oZS)?8^0-?^g11w23S(X*2v9^k*
|
|
zKU)$N`g+?WLff<~UDFNP<{vgF`ivNrY!#|!D3|%nvN;axyiKQdEH}n|UAvW!JH2@P
|
|
z6TzqIA6}zL<{b4pMQp)4ffz(REKD*y3@}3^xF7ui{>6upo0Tm&dOIrt&>JXx_VQrn
|
|
z?-nhZdK!u;m!%$urT+S%i$tA>aj?l1`%j#jH%{|kdYyAos^NAM25jH<6TePW$nes=
|
|
z1!HeZ;$v}XEv4u4(RnINU~U}<DXJ9z?(o<cCd#Ts`xxm<Y#vf|sb4vLXez4MX3R3~
|
|
z`Lh=&>A*?<y`}>wwCqU9m|k--nxsx^vf5AeRn$pVh?0Mnuc`C!uLu2;Vg{7)wfw`U
|
|
zX;*Wa;BHUq-TwcZ=lb=LAJ!W;9=uX-aQwln)6svvPf%SQ<1JdhQIPpzpQJ_KDid+%
|
|
z!(xv_|7G`-+M9p4uk#~(Mx)cG<|di_EPs|%wf~Qb+;nQM%q9N4&z7FNB6Z+G+^+MR
|
|
zj)|=QD8BER{dSeRdtd$LH*1N?VC!qI+*y}-;)|d<d&<cw#iye6@8<LL%{>!tvt|0N
|
|
zm5Vlct%>!zH1~C#{PXnRXO%R17-p8ep7o3QUvcWms)tYH$`9TvKIF>&@BVzZ?VI=h
|
|
zpErH+ydwvGOs@R*Hs)&kpXVngrCvTXb;0-d@xj~oPM7_l|L;HY`3dlY6p$IBU;poR
|
|
XXyugpZ1#qMfq}u()z4*}Q$iB}^Bg|U
|
|
|
|
diff --git a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java
|
|
index 75ed5050f72c001d6eab117a2c0b352a413548bd..180c0a532bbac10a8280b63eb7aa783a1bfbb237 100644
|
|
--- a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java
|
|
+++ b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java
|
|
@@ -46,6 +46,7 @@ public class MinecraftCommandPermissionsTest {
|
|
Set<String> foundPerms = new HashSet<>();
|
|
for (CommandNode<CommandSourceStack> child : root.getChildren()) {
|
|
final String vanillaPerm = VanillaCommandWrapper.getPermission(child);
|
|
+ if (TO_SKIP.contains(vanillaPerm)) continue; // Purpur
|
|
if (!perms.contains(vanillaPerm)) {
|
|
missing.add("Missing permission for " + child.getName() + " (" + vanillaPerm + ") command");
|
|
} else {
|
|
@@ -58,6 +59,25 @@ public class MinecraftCommandPermissionsTest {
|
|
}
|
|
|
|
private static final List<String> TO_SKIP = List.of(
|
|
+ // Purpur start
|
|
+ "minecraft.command.compass",
|
|
+ "minecraft.command.credits",
|
|
+ "minecraft.command.demo",
|
|
+ "minecraft.command.ping",
|
|
+ "minecraft.command.ram",
|
|
+ "minecraft.command.rambar",
|
|
+ "minecraft.command.tpsbar",
|
|
+ "minecraft.command.uptime",
|
|
+ "minecraft.command.debug",
|
|
+ "minecraft.command.gamemode.adventure",
|
|
+ "minecraft.command.gamemode.adventure.other",
|
|
+ "minecraft.command.gamemode.creative",
|
|
+ "minecraft.command.gamemode.creative.other",
|
|
+ "minecraft.command.gamemode.spectator",
|
|
+ "minecraft.command.gamemode.spectator.other",
|
|
+ "minecraft.command.gamemode.survival",
|
|
+ "minecraft.command.gamemode.survival.other",
|
|
+ // Purpur end
|
|
"minecraft.command.selector"
|
|
);
|
|
|