mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-28 07:20:24 +01:00
Inital remap of patches
This commit is contained in:
parent
c1aacf62b5
commit
73bcb74f23
759 changed files with 87847 additions and 0 deletions
291
Remapped-Spigot-Server-Patches/0001-POM-Changes.patch
Normal file
291
Remapped-Spigot-Server-Patches/0001-POM-Changes.patch
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Mon, 29 Feb 2016 20:40:33 -0600
|
||||||
|
Subject: [PATCH] POM Changes
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/pom.xml b/pom.xml
|
||||||
|
index 3fc047371e8f8a626e69697fad549d689c5dce89..a5d87d22cb1588d15e08da3b37e51c5e261c7799 100644
|
||||||
|
--- a/pom.xml
|
||||||
|
+++ b/pom.xml
|
||||||
|
@@ -1,15 +1,14 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
- <groupId>org.spigotmc</groupId>
|
||||||
|
- <artifactId>spigot</artifactId>
|
||||||
|
+ <artifactId>paper</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>1.16.5-R0.1-SNAPSHOT</version>
|
||||||
|
- <name>Spigot</name>
|
||||||
|
- <url>https://www.spigotmc.org/</url>
|
||||||
|
+ <name>Paper</name>
|
||||||
|
+ <url>https://papermc.io</url>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
- <skipTests>true</skipTests>
|
||||||
|
+ <!-- <skipTests>true</skipTests> Paper - This [was] not going to end well -->
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<api.version>unknown</api.version>
|
||||||
|
<bt.name>git</bt.name>
|
||||||
|
@@ -20,21 +19,39 @@
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
- <groupId>org.spigotmc</groupId>
|
||||||
|
- <artifactId>spigot-parent</artifactId>
|
||||||
|
+ <groupId>com.destroystokyo.paper</groupId>
|
||||||
|
+ <artifactId>paper-parent</artifactId>
|
||||||
|
<version>dev-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
+ <dependencyManagement>
|
||||||
|
+ <dependencies>
|
||||||
|
+ <dependency>
|
||||||
|
+ <groupId>org.apache.logging.log4j</groupId>
|
||||||
|
+ <artifactId>log4j-bom</artifactId>
|
||||||
|
+ <version>2.11.2</version>
|
||||||
|
+ <type>pom</type>
|
||||||
|
+ <scope>import</scope>
|
||||||
|
+ </dependency>
|
||||||
|
+ </dependencies>
|
||||||
|
+ </dependencyManagement>
|
||||||
|
+
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
- <groupId>org.spigotmc</groupId>
|
||||||
|
- <artifactId>spigot-api</artifactId>
|
||||||
|
+ <groupId>com.destroystokyo.paper</groupId>
|
||||||
|
+ <artifactId>paper-api</artifactId>
|
||||||
|
+ <version>${project.version}</version>
|
||||||
|
+ <scope>compile</scope>
|
||||||
|
+ </dependency>
|
||||||
|
+ <dependency>
|
||||||
|
+ <groupId>com.destroystokyo.paper</groupId>
|
||||||
|
+ <artifactId>paper-mojangapi</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
- <groupId>org.spigotmc</groupId>
|
||||||
|
+ <groupId>io.papermc</groupId>
|
||||||
|
<artifactId>minecraft-server</artifactId>
|
||||||
|
<version>${minecraft.version}-SNAPSHOT</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
@@ -45,18 +62,15 @@
|
||||||
|
<version>2.12.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
+ <dependency>
|
||||||
|
+ <groupId>org.apache.logging.log4j</groupId>
|
||||||
|
+ <artifactId>log4j-api</artifactId>
|
||||||
|
+ <scope>compile</scope>
|
||||||
|
+ </dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-iostreams</artifactId>
|
||||||
|
- <version>2.8.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
- <exclusions>
|
||||||
|
- <!-- included in minecraft-server -->
|
||||||
|
- <exclusion>
|
||||||
|
- <groupId>org.apache.logging.log4j</groupId>
|
||||||
|
- <artifactId>log4j-api</artifactId>
|
||||||
|
- </exclusion>
|
||||||
|
- </exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ow2.asm</groupId>
|
||||||
|
@@ -64,12 +78,23 @@
|
||||||
|
<version>9.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
+ <dependency>
|
||||||
|
+ <!-- wrapper to use either java 8 sun cleaner or java9+ official cleaner -->
|
||||||
|
+ <groupId>co.aikar</groupId>
|
||||||
|
+ <artifactId>cleaner</artifactId>
|
||||||
|
+ <version>1.0-SNAPSHOT</version>
|
||||||
|
+ </dependency>
|
||||||
|
+ <dependency>
|
||||||
|
+ <groupId>io.netty</groupId>
|
||||||
|
+ <artifactId>netty-all</artifactId>
|
||||||
|
+ <version>4.1.50.Final</version>
|
||||||
|
+ </dependency>
|
||||||
|
<!-- deprecated API depend -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.json-simple</groupId>
|
||||||
|
<artifactId>json-simple</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
- <scope>runtime</scope>
|
||||||
|
+ <scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xerial</groupId>
|
||||||
|
@@ -80,7 +105,7 @@
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
- <version>5.1.49</version>
|
||||||
|
+ <version>8.0.23</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- add these back in as they are not exposed by the API -->
|
||||||
|
@@ -105,7 +130,7 @@
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-slf4j-impl</artifactId>
|
||||||
|
- <version>2.8.1</version>
|
||||||
|
+ <!--<version>2.8.1</version>--> <!--handled by bom-->
|
||||||
|
<scope>runtime</scope>
|
||||||
|
<exclusions>
|
||||||
|
<!-- included in minecraft-server -->
|
||||||
|
@@ -132,34 +157,22 @@
|
||||||
|
|
||||||
|
<!-- This builds a completely 'ready to start' jar with all dependencies inside -->
|
||||||
|
<build>
|
||||||
|
+ <finalName>paper-${minecraft.version}</finalName>
|
||||||
|
+ <defaultGoal>clean install</defaultGoal> <!-- Paper -->
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
- <groupId>net.md-5</groupId>
|
||||||
|
- <artifactId>scriptus</artifactId>
|
||||||
|
- <version>0.4.1</version>
|
||||||
|
+ <groupId>com.lukegb.mojo</groupId>
|
||||||
|
+ <artifactId>gitdescribe-maven-plugin</artifactId>
|
||||||
|
+ <version>1.3</version>
|
||||||
|
+ <configuration>
|
||||||
|
+ <outputPrefix>git-Paper-</outputPrefix>
|
||||||
|
+ <scmDirectory>..</scmDirectory>
|
||||||
|
+ </configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
- <id>ex-spigot</id>
|
||||||
|
- <configuration>
|
||||||
|
- <format>${bt.name}-Spigot-%s</format>
|
||||||
|
- <scmDirectory>../</scmDirectory>
|
||||||
|
- <descriptionProperty>spigot.desc</descriptionProperty>
|
||||||
|
- </configuration>
|
||||||
|
- <phase>initialize</phase>
|
||||||
|
- <goals>
|
||||||
|
- <goal>describe</goal>
|
||||||
|
- </goals>
|
||||||
|
- </execution>
|
||||||
|
- <execution>
|
||||||
|
- <id>ex-craftbukkit</id>
|
||||||
|
- <configuration>
|
||||||
|
- <format>-%s</format>
|
||||||
|
- <scmDirectory>../../CraftBukkit</scmDirectory>
|
||||||
|
- <descriptionProperty>craftbukkit.desc</descriptionProperty>
|
||||||
|
- </configuration>
|
||||||
|
- <phase>initialize</phase>
|
||||||
|
+ <phase>compile</phase>
|
||||||
|
<goals>
|
||||||
|
- <goal>describe</goal>
|
||||||
|
+ <goal>gitdescribe</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
@@ -169,6 +182,7 @@
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<configuration>
|
||||||
|
+ <forceCreation>true</forceCreation> <!-- Required to prevent shading the jar multiple times -->
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<addDefaultEntries>false</addDefaultEntries>
|
||||||
|
@@ -176,11 +190,13 @@
|
||||||
|
<manifestEntries>
|
||||||
|
<Main-Class>org.bukkit.craftbukkit.Main</Main-Class>
|
||||||
|
<Implementation-Title>CraftBukkit</Implementation-Title>
|
||||||
|
- <Implementation-Version>${spigot.desc}${craftbukkit.desc}</Implementation-Version>
|
||||||
|
- <Implementation-Vendor>${project.build.outputTimestamp}</Implementation-Vendor>
|
||||||
|
+ <!--suppress MavenModelInspection -->
|
||||||
|
+ <Implementation-Version>${describe}</Implementation-Version>
|
||||||
|
+ <Implementation-Vendor>${maven.build.timestamp}</Implementation-Vendor>
|
||||||
|
<Specification-Title>Bukkit</Specification-Title>
|
||||||
|
<Specification-Version>${api.version}</Specification-Version>
|
||||||
|
<Specification-Vendor>Bukkit Team</Specification-Vendor>
|
||||||
|
+ <Multi-Release>true</Multi-Release>
|
||||||
|
</manifestEntries>
|
||||||
|
<manifestSections>
|
||||||
|
<manifestSection>
|
||||||
|
@@ -216,14 +232,24 @@
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
+ <dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation> <!-- Paper -->
|
||||||
|
<createSourcesJar>${shadeSourcesJar}</createSourcesJar>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
- <artifact>org.spigotmc:minecraft-server</artifact>
|
||||||
|
+ <artifact>io.papermc:minecraft-server</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>com/google/common/**</exclude>
|
||||||
|
<exclude>com/google/gson/**</exclude>
|
||||||
|
<exclude>com/google/thirdparty/**</exclude>
|
||||||
|
+ <!-- paper -->
|
||||||
|
+ <exclude>io/netty/**</exclude>
|
||||||
|
+ <exclude>META-INF/native/libnetty*</exclude>
|
||||||
|
+ <exclude>com/mojang/brigadier/**</exclude>
|
||||||
|
+ <exclude>META-INF/MANIFEST.MF</exclude>
|
||||||
|
+ <exclude>com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.class</exclude>
|
||||||
|
+ <exclude>com/mojang/datafixers/util/Either*</exclude>
|
||||||
|
+ <exclude>org/apache/logging/log4j/**</exclude>
|
||||||
|
+ <exclude>META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
@@ -245,10 +271,11 @@
|
||||||
|
<pattern>jline</pattern>
|
||||||
|
<shadedPattern>org.bukkit.craftbukkit.libs.jline</shadedPattern>
|
||||||
|
</relocation>
|
||||||
|
- <relocation>
|
||||||
|
- <pattern>it.unimi</pattern>
|
||||||
|
- <shadedPattern>org.bukkit.craftbukkit.libs.it.unimi</shadedPattern>
|
||||||
|
- </relocation>
|
||||||
|
+ <!-- Paper - Don't relocate fastutil in order to prevent api breakage -->
|
||||||
|
+ <!--<relocation>-->
|
||||||
|
+ <!--<pattern>it.unimi</pattern>-->
|
||||||
|
+ <!--<shadedPattern>org.bukkit.craftbukkit.libs.it.unimi</shadedPattern>-->
|
||||||
|
+ <!--</relocation>-->
|
||||||
|
<relocation>
|
||||||
|
<pattern>org.apache.commons.codec</pattern>
|
||||||
|
<shadedPattern>org.bukkit.craftbukkit.libs.org.apache.commons.codec</shadedPattern>
|
||||||
|
@@ -316,10 +343,6 @@
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
- <configuration>
|
||||||
|
- <!-- we use the Eclipse compiler as it doesn't need a JDK -->
|
||||||
|
- <compilerId>eclipse</compilerId>
|
||||||
|
- </configuration>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.plexus</groupId>
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
index 4452427d0a8298d119ca29ef397b7a94f19eec28..46a16e31775b28c44f95a8ac5545ebcb656c74b6 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
@@ -186,7 +186,7 @@ public class Main {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false && Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) {
|
||||||
|
- Date buildDate = new Date(Integer.parseInt(Main.class.getPackage().getImplementationVendor()) * 1000L);
|
||||||
|
+ Date buildDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").parse(Main.class.getPackage().getImplementationVendor()); // Paper
|
||||||
|
|
||||||
|
Calendar deadline = Calendar.getInstance();
|
||||||
|
deadline.add(Calendar.DAY_OF_YEAR, -28);
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
||||||
|
index 93046379d0cefd5d3236fc59e698809acdc18f80..674096cab190d62622f9947853b056f57d43a2a5 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/org.spigotmc/spigot-api/pom.properties");
|
||||||
|
+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/com.destroystokyo.paper/paper-api/pom.properties");
|
||||||
|
Properties properties = new Properties();
|
||||||
|
|
||||||
|
if (stream != null) {
|
820
Remapped-Spigot-Server-Patches/0002-Paper-config-files.patch
Normal file
820
Remapped-Spigot-Server-Patches/0002-Paper-config-files.patch
Normal file
|
@ -0,0 +1,820 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Mon, 29 Feb 2016 21:02:09 -0600
|
||||||
|
Subject: [PATCH] Paper config files
|
||||||
|
|
||||||
|
Loads each yml file for early init too so it can be used for early options
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..d05eeaa711a09bb121b530654821894e795ff4ea
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||||
|
@@ -0,0 +1,286 @@
|
||||||
|
+package com.destroystokyo.paper;
|
||||||
|
+
|
||||||
|
+import com.google.common.base.Functions;
|
||||||
|
+import com.google.common.base.Joiner;
|
||||||
|
+import com.google.common.collect.ImmutableSet;
|
||||||
|
+import com.google.common.collect.Iterables;
|
||||||
|
+import com.google.common.collect.Lists;
|
||||||
|
+import com.google.common.collect.Maps;
|
||||||
|
+import net.minecraft.resources.ResourceLocation;
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
+import net.minecraft.server.level.ServerChunkCache;
|
||||||
|
+import net.minecraft.server.level.ServerLevel;
|
||||||
|
+import net.minecraft.world.entity.Entity;
|
||||||
|
+import net.minecraft.world.entity.EntityType;
|
||||||
|
+import net.minecraft.world.level.ChunkPos;
|
||||||
|
+import org.apache.commons.lang3.tuple.MutablePair;
|
||||||
|
+import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
+import org.bukkit.Bukkit;
|
||||||
|
+import org.bukkit.ChatColor;
|
||||||
|
+import org.bukkit.Location;
|
||||||
|
+import org.bukkit.World;
|
||||||
|
+import org.bukkit.command.Command;
|
||||||
|
+import org.bukkit.command.CommandSender;
|
||||||
|
+import org.bukkit.craftbukkit.CraftServer;
|
||||||
|
+import org.bukkit.craftbukkit.CraftWorld;
|
||||||
|
+import org.bukkit.entity.Player;
|
||||||
|
+
|
||||||
|
+import java.io.File;
|
||||||
|
+import java.time.LocalDateTime;
|
||||||
|
+import java.time.format.DateTimeFormatter;
|
||||||
|
+import java.util.ArrayList;
|
||||||
|
+import java.util.Arrays;
|
||||||
|
+import java.util.Collection;
|
||||||
|
+import java.util.Collections;
|
||||||
|
+import java.util.Iterator;
|
||||||
|
+import java.util.List;
|
||||||
|
+import java.util.Locale;
|
||||||
|
+import java.util.Map;
|
||||||
|
+import java.util.Set;
|
||||||
|
+import java.util.stream.Collectors;
|
||||||
|
+
|
||||||
|
+public class PaperCommand extends Command {
|
||||||
|
+ private static final String BASE_PERM = "bukkit.command.paper.";
|
||||||
|
+ private static final ImmutableSet<String> SUBCOMMANDS = ImmutableSet.<String>builder().add("heap", "entity", "reload", "version").build();
|
||||||
|
+
|
||||||
|
+ public PaperCommand(String name) {
|
||||||
|
+ super(name);
|
||||||
|
+ this.description = "Paper related commands";
|
||||||
|
+ this.usageMessage = "/paper [" + Joiner.on(" | ").join(SUBCOMMANDS) + "]";
|
||||||
|
+ this.setPermission("bukkit.command.paper;" + Joiner.on(';').join(SUBCOMMANDS.stream().map(s -> BASE_PERM + s).collect(Collectors.toSet())));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static boolean testPermission(CommandSender commandSender, String permission) {
|
||||||
|
+ if (commandSender.hasPermission(BASE_PERM + permission) || commandSender.hasPermission("bukkit.command.paper")) return true;
|
||||||
|
+ commandSender.sendMessage(Bukkit.getPermissionMessage());
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
|
||||||
|
+ if (args.length <= 1)
|
||||||
|
+ return getListMatchingLast(sender, args, SUBCOMMANDS);
|
||||||
|
+
|
||||||
|
+ switch (args[0].toLowerCase(Locale.ENGLISH))
|
||||||
|
+ {
|
||||||
|
+ case "entity":
|
||||||
|
+ if (args.length == 2)
|
||||||
|
+ return getListMatchingLast(sender, args, "help", "list");
|
||||||
|
+ if (args.length == 3)
|
||||||
|
+ return getListMatchingLast(sender, args, EntityType.getEntityNameList().stream().map(ResourceLocation::toString).sorted().toArray(String[]::new));
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ return Collections.emptyList();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Code from Mojang - copyright them
|
||||||
|
+ public static List<String> getListMatchingLast(CommandSender sender, String[] args, String... matches) {
|
||||||
|
+ return getListMatchingLast(sender, args, (Collection) Arrays.asList(matches));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static boolean matches(String s, String s1) {
|
||||||
|
+ return s1.regionMatches(true, 0, s, 0, s.length());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static List<String> getListMatchingLast(CommandSender sender, String[] strings, Collection<?> collection) {
|
||||||
|
+ String last = strings[strings.length - 1];
|
||||||
|
+ ArrayList<String> results = Lists.newArrayList();
|
||||||
|
+
|
||||||
|
+ if (!collection.isEmpty()) {
|
||||||
|
+ Iterator iterator = Iterables.transform(collection, Functions.toStringFunction()).iterator();
|
||||||
|
+
|
||||||
|
+ while (iterator.hasNext()) {
|
||||||
|
+ String s1 = (String) iterator.next();
|
||||||
|
+
|
||||||
|
+ if (matches(last, s1) && (sender.hasPermission(BASE_PERM + s1) || sender.hasPermission("bukkit.command.paper"))) {
|
||||||
|
+ results.add(s1);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (results.isEmpty()) {
|
||||||
|
+ iterator = collection.iterator();
|
||||||
|
+
|
||||||
|
+ while (iterator.hasNext()) {
|
||||||
|
+ Object object = iterator.next();
|
||||||
|
+
|
||||||
|
+ if (object instanceof ResourceLocation && matches(last, ((ResourceLocation) object).getPath())) {
|
||||||
|
+ results.add(String.valueOf(object));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return results;
|
||||||
|
+ }
|
||||||
|
+ // end copy stuff
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
||||||
|
+ if (!testPermission(sender)) return true;
|
||||||
|
+
|
||||||
|
+ if (args.length == 0) {
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ if (SUBCOMMANDS.contains(args[0].toLowerCase(Locale.ENGLISH))) {
|
||||||
|
+ if (!testPermission(sender, args[0].toLowerCase(Locale.ENGLISH))) return true;
|
||||||
|
+ }
|
||||||
|
+ switch (args[0].toLowerCase(Locale.ENGLISH)) {
|
||||||
|
+ case "heap":
|
||||||
|
+ dumpHeap(sender);
|
||||||
|
+ break;
|
||||||
|
+ case "entity":
|
||||||
|
+ listEntities(sender, args);
|
||||||
|
+ break;
|
||||||
|
+ case "reload":
|
||||||
|
+ doReload(sender);
|
||||||
|
+ break;
|
||||||
|
+ case "ver":
|
||||||
|
+ if (!testPermission(sender, "version")) break; // "ver" needs a special check because it's an alias. All other commands are checked up before the switch statement (because they are present in the SUBCOMMANDS set)
|
||||||
|
+ case "version":
|
||||||
|
+ Command ver = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version");
|
||||||
|
+ if (ver != null) {
|
||||||
|
+ ver.execute(sender, commandLabel, new String[0]);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ // else - fall through to default
|
||||||
|
+ default:
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Ported from MinecraftForge - author: LexManos <LexManos@gmail.com> - License: LGPLv2.1
|
||||||
|
+ */
|
||||||
|
+ private void listEntities(CommandSender sender, String[] args) {
|
||||||
|
+ if (args.length < 2 || args[1].toLowerCase(Locale.ENGLISH).equals("help")) {
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "Use /paper entity [list] help for more information on a specific command.");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ switch (args[1].toLowerCase(Locale.ENGLISH)) {
|
||||||
|
+ case "list":
|
||||||
|
+ String filter = "*";
|
||||||
|
+ if (args.length > 2) {
|
||||||
|
+ if (args[2].toLowerCase(Locale.ENGLISH).equals("help")) {
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "Use /paper entity list [filter] [worldName] to get entity info that matches the optional filter.");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ filter = args[2];
|
||||||
|
+ }
|
||||||
|
+ final String cleanfilter = filter.replace("?", ".?").replace("*", ".*?");
|
||||||
|
+ Set<ResourceLocation> names = EntityType.getEntityNameList().stream()
|
||||||
|
+ .filter(n -> n.toString().matches(cleanfilter))
|
||||||
|
+ .collect(Collectors.toSet());
|
||||||
|
+
|
||||||
|
+ if (names.isEmpty()) {
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "Invalid filter, does not match any entities. Use /paper entity list for a proper list");
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "Usage: /paper entity list [filter] [worldName]");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ String worldName;
|
||||||
|
+ if (args.length > 3) {
|
||||||
|
+ worldName = args[3];
|
||||||
|
+ } else if (sender instanceof Player) {
|
||||||
|
+ worldName = ((Player) sender).getWorld().getName();
|
||||||
|
+ } else {
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "Please specify the name of a world");
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "To do so without a filter, specify '*' as the filter");
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "Usage: /paper entity list [filter] [worldName]");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Map<ResourceLocation, MutablePair<Integer, Map<ChunkPos, Integer>>> list = Maps.newHashMap();
|
||||||
|
+ World bukkitWorld = Bukkit.getWorld(worldName);
|
||||||
|
+ if (bukkitWorld == null) {
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "Could not load world for " + worldName + ". Please select a valid world.");
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "Usage: /paper entity list [filter] [worldName]");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ ServerLevel world = ((CraftWorld) Bukkit.getWorld(worldName)).getHandle();
|
||||||
|
+
|
||||||
|
+ Map<ResourceLocation, Integer> nonEntityTicking = Maps.newHashMap();
|
||||||
|
+ ServerChunkCache chunkProviderServer = world.getChunkSource();
|
||||||
|
+
|
||||||
|
+ Collection<Entity> entities = world.entitiesById.values();
|
||||||
|
+ entities.forEach(e -> {
|
||||||
|
+ ResourceLocation key = new ResourceLocation(""); // TODO: update in next patch
|
||||||
|
+
|
||||||
|
+ MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap()));
|
||||||
|
+ ChunkPos chunk = new ChunkPos(e.xChunk, e.zChunk);
|
||||||
|
+ info.left++;
|
||||||
|
+ info.right.put(chunk, info.right.getOrDefault(chunk, 0) + 1);
|
||||||
|
+ if (!chunkProviderServer.isInEntityTickingChunk(e)) {
|
||||||
|
+ nonEntityTicking.merge(key, Integer.valueOf(1), Integer::sum);
|
||||||
|
+ }
|
||||||
|
+ });
|
||||||
|
+
|
||||||
|
+ if (names.size() == 1) {
|
||||||
|
+ ResourceLocation name = names.iterator().next();
|
||||||
|
+ Pair<Integer, Map<ChunkPos, Integer>> info = list.get(name);
|
||||||
|
+ int nonTicking = nonEntityTicking.getOrDefault(name, Integer.valueOf(0)).intValue();
|
||||||
|
+ if (info == null) {
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "No entities found.");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ sender.sendMessage("Entity: " + name + " Total Ticking: " + (info.getLeft() - nonTicking) + ", Total Non-Ticking: " + nonTicking);
|
||||||
|
+ info.getRight().entrySet().stream()
|
||||||
|
+ .sorted((a, b) -> !a.getValue().equals(b.getValue()) ? b.getValue() - a.getValue() : a.getKey().toString().compareTo(b.getKey().toString()))
|
||||||
|
+ .limit(10).forEach(e -> sender.sendMessage(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z + (chunkProviderServer.isEntityTickingChunk(e.getKey()) ? " (Ticking)" : " (Non-Ticking)")));
|
||||||
|
+ } else {
|
||||||
|
+ List<Pair<ResourceLocation, Integer>> info = list.entrySet().stream()
|
||||||
|
+ .filter(e -> names.contains(e.getKey()))
|
||||||
|
+ .map(e -> Pair.of(e.getKey(), e.getValue().left))
|
||||||
|
+ .sorted((a, b) -> !a.getRight().equals(b.getRight()) ? b.getRight() - a.getRight() : a.getKey().toString().compareTo(b.getKey().toString()))
|
||||||
|
+ .collect(Collectors.toList());
|
||||||
|
+
|
||||||
|
+ if (info == null || info.size() == 0) {
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "No entities found.");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ int count = info.stream().mapToInt(Pair::getRight).sum();
|
||||||
|
+ int nonTickingCount = nonEntityTicking.values().stream().mapToInt(Integer::intValue).sum();
|
||||||
|
+ sender.sendMessage("Total Ticking: " + (count - nonTickingCount) + ", Total Non-Ticking: " + nonTickingCount);
|
||||||
|
+ info.forEach(e -> {
|
||||||
|
+ int nonTicking = nonEntityTicking.getOrDefault(e.getKey(), Integer.valueOf(0)).intValue();
|
||||||
|
+ sender.sendMessage(" " + (e.getValue() - nonTicking) + " (" + nonTicking + ") " + ": " + e.getKey());
|
||||||
|
+ });
|
||||||
|
+ sender.sendMessage("* First number is ticking entities, second number is non-ticking entities");
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void dumpHeap(CommandSender sender) {
|
||||||
|
+ java.nio.file.Path dir = java.nio.file.Paths.get("./dumps");
|
||||||
|
+ String name = "heap-dump-" + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now());
|
||||||
|
+
|
||||||
|
+ Command.broadcastCommandMessage(sender, ChatColor.YELLOW + "Writing JVM heap data...");
|
||||||
|
+
|
||||||
|
+ java.nio.file.Path file = CraftServer.dumpHeap(dir, name);
|
||||||
|
+ if (file != null) {
|
||||||
|
+ Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Heap dump saved to " + file);
|
||||||
|
+ } else {
|
||||||
|
+ Command.broadcastCommandMessage(sender, ChatColor.RED + "Failed to write heap dump, see sever log for details");
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void doReload(CommandSender sender) {
|
||||||
|
+ 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();
|
||||||
|
+ com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings"));
|
||||||
|
+ for (ServerLevel world : console.getAllLevels()) {
|
||||||
|
+ world.paperConfig.init();
|
||||||
|
+ }
|
||||||
|
+ console.server.reloadCount++;
|
||||||
|
+
|
||||||
|
+ Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Paper config reload complete.");
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..2c0514892d3993bef57ecf677cf8bb0fbe0216e4
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
@@ -0,0 +1,185 @@
|
||||||
|
+package com.destroystokyo.paper;
|
||||||
|
+
|
||||||
|
+import com.google.common.base.Throwables;
|
||||||
|
+
|
||||||
|
+import java.io.File;
|
||||||
|
+import java.io.IOException;
|
||||||
|
+import java.lang.reflect.InvocationTargetException;
|
||||||
|
+import java.lang.reflect.Method;
|
||||||
|
+import java.lang.reflect.Modifier;
|
||||||
|
+import java.util.HashMap;
|
||||||
|
+import java.util.List;
|
||||||
|
+import java.util.Map;
|
||||||
|
+import java.util.concurrent.TimeUnit;
|
||||||
|
+import java.util.logging.Level;
|
||||||
|
+import java.util.regex.Pattern;
|
||||||
|
+
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
+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;
|
||||||
|
+
|
||||||
|
+public class PaperConfig {
|
||||||
|
+
|
||||||
|
+ private static File CONFIG_FILE;
|
||||||
|
+ private static final String HEADER = "This is the main configuration file for Paper.\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 Paper,\n"
|
||||||
|
+ + "join us in our Discord or IRC channel.\n"
|
||||||
|
+ + "\n"
|
||||||
|
+ + "Discord: https://discord.gg/papermc\n"
|
||||||
|
+ + "IRC: #paper @ irc.esper.net ( https://webchat.esper.net/?channels=paper ) \n"
|
||||||
|
+ + "Website: https://papermc.io/ \n"
|
||||||
|
+ + "Docs: https://paper.readthedocs.org/ \n";
|
||||||
|
+ /*========================================================================*/
|
||||||
|
+ public static YamlConfiguration config;
|
||||||
|
+ static int version;
|
||||||
|
+ static Map<String, Command> commands;
|
||||||
|
+ private static boolean verbose;
|
||||||
|
+ private static boolean fatalError;
|
||||||
|
+ /*========================================================================*/
|
||||||
|
+
|
||||||
|
+ public static void init(File configFile) {
|
||||||
|
+ CONFIG_FILE = configFile;
|
||||||
|
+ config = new YamlConfiguration();
|
||||||
|
+ try {
|
||||||
|
+ config.load(CONFIG_FILE);
|
||||||
|
+ } catch (IOException ex) {
|
||||||
|
+ } catch (InvalidConfigurationException ex) {
|
||||||
|
+ Bukkit.getLogger().log(Level.SEVERE, "Could not load paper.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<String, Command>();
|
||||||
|
+ commands.put("paper", new PaperCommand("paper"));
|
||||||
|
+
|
||||||
|
+ version = getInt("config-version", 20);
|
||||||
|
+ set("config-version", 20);
|
||||||
|
+ readConfig(PaperConfig.class, null);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected static void logError(String s) {
|
||||||
|
+ Bukkit.getLogger().severe(s);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected static void fatal(String s) {
|
||||||
|
+ fatalError = true;
|
||||||
|
+ throw new RuntimeException("Fatal paper.yml config error: " + s);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected static void log(String s) {
|
||||||
|
+ if (verbose) {
|
||||||
|
+ Bukkit.getLogger().info(s);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static void registerCommands() {
|
||||||
|
+ for (Map.Entry<String, Command> entry : commands.entrySet()) {
|
||||||
|
+ MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Paper", 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 final Pattern SPACE = Pattern.compile(" ");
|
||||||
|
+ private static final Pattern NOT_NUMERIC = Pattern.compile("[^-\\d.]");
|
||||||
|
+ public static int getSeconds(String str) {
|
||||||
|
+ str = SPACE.matcher(str).replaceAll("");
|
||||||
|
+ final char unit = str.charAt(str.length() - 1);
|
||||||
|
+ str = NOT_NUMERIC.matcher(str).replaceAll("");
|
||||||
|
+ double num;
|
||||||
|
+ try {
|
||||||
|
+ num = Double.parseDouble(str);
|
||||||
|
+ } catch (Exception e) {
|
||||||
|
+ num = 0D;
|
||||||
|
+ }
|
||||||
|
+ switch (unit) {
|
||||||
|
+ case 'd': num *= (double) 60*60*24; break;
|
||||||
|
+ case 'h': num *= (double) 60*60; break;
|
||||||
|
+ case 'm': num *= (double) 60; break;
|
||||||
|
+ default: case 's': break;
|
||||||
|
+ }
|
||||||
|
+ return (int) num;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected static String timeSummary(int seconds) {
|
||||||
|
+ String time = "";
|
||||||
|
+
|
||||||
|
+ if (seconds > 60 * 60 * 24) {
|
||||||
|
+ time += TimeUnit.SECONDS.toDays(seconds) + "d";
|
||||||
|
+ seconds %= 60 * 60 * 24;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (seconds > 60 * 60) {
|
||||||
|
+ time += TimeUnit.SECONDS.toHours(seconds) + "h";
|
||||||
|
+ seconds %= 60 * 60;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (seconds > 0) {
|
||||||
|
+ time += TimeUnit.SECONDS.toMinutes(seconds) + "m";
|
||||||
|
+ }
|
||||||
|
+ return time;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static void set(String path, Object val) {
|
||||||
|
+ config.set(path, val);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ 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 float getFloat(String path, float def) {
|
||||||
|
+ // TODO: Figure out why getFloat() always returns the default value.
|
||||||
|
+ return (float) getDouble(path, (double) def);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ 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 (List<T>) config.getList(path, config.getList(path));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static String getString(String path, String def) {
|
||||||
|
+ config.addDefault(path, def);
|
||||||
|
+ return config.getString(path, config.getString(path));
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..b31109d2dadd29e8852468c19265066b773d2be0
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -0,0 +1,68 @@
|
||||||
|
+package com.destroystokyo.paper;
|
||||||
|
+
|
||||||
|
+import java.util.List;
|
||||||
|
+
|
||||||
|
+import org.bukkit.Bukkit;
|
||||||
|
+import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
+import org.spigotmc.SpigotWorldConfig;
|
||||||
|
+
|
||||||
|
+import static com.destroystokyo.paper.PaperConfig.log;
|
||||||
|
+import static com.destroystokyo.paper.PaperConfig.logError;
|
||||||
|
+
|
||||||
|
+public class PaperWorldConfig {
|
||||||
|
+
|
||||||
|
+ private final String worldName;
|
||||||
|
+ private final SpigotWorldConfig spigotConfig;
|
||||||
|
+ private YamlConfiguration config;
|
||||||
|
+ private boolean verbose;
|
||||||
|
+
|
||||||
|
+ public PaperWorldConfig(String worldName, SpigotWorldConfig spigotConfig) {
|
||||||
|
+ this.worldName = worldName;
|
||||||
|
+ this.spigotConfig = spigotConfig;
|
||||||
|
+ this.config = PaperConfig.config;
|
||||||
|
+ init();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void init() {
|
||||||
|
+ this.config = PaperConfig.config; // grab updated reference
|
||||||
|
+ log("-------- World Settings For [" + worldName + "] --------");
|
||||||
|
+ PaperConfig.readConfig(PaperWorldConfig.class, this);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void set(String path, Object val) {
|
||||||
|
+ config.set("world-settings.default." + path, val);
|
||||||
|
+ if (config.get("world-settings." + worldName + "." + path) != null) {
|
||||||
|
+ config.set("world-settings." + worldName + "." + path, val);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private boolean getBoolean(String path, boolean def) {
|
||||||
|
+ config.addDefault("world-settings.default." + path, def);
|
||||||
|
+ return config.getBoolean("world-settings." + worldName + "." + path, config.getBoolean("world-settings.default." + path));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private double getDouble(String path, double def) {
|
||||||
|
+ config.addDefault("world-settings.default." + path, def);
|
||||||
|
+ return config.getDouble("world-settings." + worldName + "." + path, config.getDouble("world-settings.default." + path));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private int getInt(String path, int def) {
|
||||||
|
+ config.addDefault("world-settings.default." + path, def);
|
||||||
|
+ return config.getInt("world-settings." + worldName + "." + path, config.getInt("world-settings.default." + path));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private float getFloat(String path, float def) {
|
||||||
|
+ // TODO: Figure out why getFloat() always returns the default value.
|
||||||
|
+ return (float) getDouble(path, (double) def);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private <T> List<T> getList(String path, List<T> def) {
|
||||||
|
+ config.addDefault("world-settings.default." + path, def);
|
||||||
|
+ return (List<T>) config.getList("world-settings." + worldName + "." + path, config.getList("world-settings.default." + path));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private String getString(String path, String def) {
|
||||||
|
+ config.addDefault("world-settings.default." + path, def);
|
||||||
|
+ return config.getString("world-settings." + worldName + "." + path, config.getString("world-settings.default." + path));
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
|
||||||
|
index 9366b5551047e87e455fafbf45be5fb145aa875b..5d83a8d4c69144219219877c521c364d912d2452 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/Main.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/Main.java
|
||||||
|
@@ -95,6 +95,12 @@ public class Main {
|
||||||
|
DedicatedServerSettings dedicatedserversettings = new DedicatedServerSettings(iregistrycustom_dimension, optionset); // CraftBukkit - CLI argument support
|
||||||
|
|
||||||
|
dedicatedserversettings.forceSave();
|
||||||
|
+ // Paper start - load config files for access below if needed
|
||||||
|
+ org.bukkit.configuration.file.YamlConfiguration bukkitConfiguration = loadConfigFile((File) optionset.valueOf("bukkit-settings"));
|
||||||
|
+ org.bukkit.configuration.file.YamlConfiguration spigotConfiguration = loadConfigFile((File) optionset.valueOf("spigot-settings"));
|
||||||
|
+ org.bukkit.configuration.file.YamlConfiguration paperConfiguration = loadConfigFile((File) optionset.valueOf("paper-settings"));
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
java.nio.file.Path java_nio_file_path1 = Paths.get("eula.txt");
|
||||||
|
Eula eula = new Eula(java_nio_file_path1);
|
||||||
|
|
||||||
|
@@ -236,6 +242,20 @@ public class Main {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start - load config files
|
||||||
|
+ private static org.bukkit.configuration.file.YamlConfiguration loadConfigFile(File configFile) throws Exception {
|
||||||
|
+ org.bukkit.configuration.file.YamlConfiguration config = new org.bukkit.configuration.file.YamlConfiguration();
|
||||||
|
+ if (configFile.exists()) {
|
||||||
|
+ try {
|
||||||
|
+ config.load(configFile);
|
||||||
|
+ } catch (Exception ex) {
|
||||||
|
+ throw new Exception("Failed to load configuration file: " + configFile.getName(), ex);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return config;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
public static void forceUpgrade(LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, boolean eraseCache, BooleanSupplier booleansupplier, ImmutableSet<ResourceKey<DimensionType>> worlds) { // CraftBukkit
|
||||||
|
Main.LOGGER.info("Forcing world upgrade! {}", session.getLevelId()); // CraftBukkit
|
||||||
|
WorldUpgrader worldupgrader = new WorldUpgrader(session, dataFixer, worlds, eraseCache);
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
index 2228f83f251851aa683f739ac5ce2ec98f059f3f..23d6f803eafa78fd51ea4cdc4ca25c78661bc80b 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
@@ -184,6 +184,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||||
|
org.spigotmc.SpigotConfig.init((java.io.File) options.valueOf("spigot-settings"));
|
||||||
|
org.spigotmc.SpigotConfig.registerCommands();
|
||||||
|
// Spigot end
|
||||||
|
+ // Paper start
|
||||||
|
+ try {
|
||||||
|
+ com.destroystokyo.paper.PaperConfig.init((java.io.File) options.valueOf("paper-settings"));
|
||||||
|
+ } catch (Exception e) {
|
||||||
|
+ DedicatedServer.LOGGER.error("Unable to load server configuration", e);
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ com.destroystokyo.paper.PaperConfig.registerCommands();
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
this.setPvpAllowed(dedicatedserverproperties.pvp);
|
||||||
|
this.setFlightAllowed(dedicatedserverproperties.allowFlight);
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||||
|
index aa7bf54e4b93a9b6085aa943500f5dec5f60a117..7cc5070f70a4f740add9d971385ceaa4d44275a2 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||||
|
@@ -307,15 +307,15 @@ public class ServerChunkCache extends ChunkSource {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- @Override
|
||||||
|
- public boolean isEntityTickingChunk(Entity entity) {
|
||||||
|
+ public final boolean isInEntityTickingChunk(Entity entity) { return this.isEntityTickingChunk(entity); } // Paper - OBFHELPER
|
||||||
|
+ @Override public boolean isEntityTickingChunk(Entity entity) {
|
||||||
|
long i = ChunkPos.asLong(Mth.floor(entity.getX()) >> 4, Mth.floor(entity.getZ()) >> 4);
|
||||||
|
|
||||||
|
return this.checkChunkFuture(i, (Function<ChunkHolder, CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>>>) ChunkHolder::getEntityTickingChunkFuture); // CraftBukkit - decompile error
|
||||||
|
}
|
||||||
|
|
||||||
|
- @Override
|
||||||
|
- public boolean isEntityTickingChunk(ChunkPos pos) {
|
||||||
|
+ public final boolean isEntityTickingChunk(ChunkPos chunkcoordintpair) { return this.isEntityTickingChunk(chunkcoordintpair); } // Paper - OBFHELPER
|
||||||
|
+ @Override public boolean isEntityTickingChunk(ChunkPos pos) {
|
||||||
|
return this.checkChunkFuture(pos.toLong(), (Function<ChunkHolder, CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>>>) ChunkHolder::getEntityTickingChunkFuture); // CraftBukkit - decompile error
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||||
|
index f82fd4a50921c3c4791be18a43778e6fd216f557..ff482d0349c18d0d1ba902ea0d10611b1ca4e588 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||||
|
@@ -2,6 +2,7 @@ package net.minecraft.world.entity;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import java.util.Optional;
|
||||||
|
+import java.util.Set; // Paper
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
@@ -599,4 +600,10 @@ public class EntityType<T extends Entity> {
|
||||||
|
return new EntityType<>(this.factory, this.category, this.serialize, this.summon, this.fireImmune, this.canSpawnFarFromPlayer, this.immuneTo, this.dimensions, this.clientTrackingRange, this.updateInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Paper start
|
||||||
|
+ public static Set<ResourceLocation> getEntityNameList() {
|
||||||
|
+ return Registry.ENTITY_TYPE.keySet();
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index b7c64fcf49ea50fa38a121d906ec6df20a1be31b..f08de81dcc4acd5a3e44407b431ce827a19b2e9c 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -129,6 +129,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
public boolean populating;
|
||||||
|
public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot
|
||||||
|
|
||||||
|
+ public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper
|
||||||
|
+
|
||||||
|
public final SpigotTimings.WorldTimingsHandler timings; // Spigot
|
||||||
|
public static BlockPos lastPhysicsProblem; // Spigot
|
||||||
|
private org.spigotmc.TickLimiter entityLimiter;
|
||||||
|
@@ -149,6 +151,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
|
||||||
|
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, final DimensionType dimensionmanager, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env) {
|
||||||
|
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
||||||
|
+ this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper
|
||||||
|
this.generator = gen;
|
||||||
|
this.world = new CraftWorld((ServerLevel) this, gen, env);
|
||||||
|
this.ticksPerAnimalSpawns = this.getCraftServer().getTicksPerAnimalSpawns(); // CraftBukkit
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index 761ad2d7e538d1e299d3050446274addcde7d772..328d1e2b128b62f24917719c79823c9fb64a0dcf 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -806,6 +806,7 @@ public final class CraftServer implements Server {
|
||||||
|
}
|
||||||
|
|
||||||
|
org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot
|
||||||
|
+ com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings")); // Paper
|
||||||
|
for (ServerLevel world : console.getAllLevels()) {
|
||||||
|
world.worldDataServer.setDifficulty(config.difficulty);
|
||||||
|
world.setSpawnSettings(config.spawnMonsters, config.spawnAnimals);
|
||||||
|
@@ -839,6 +840,7 @@ public final class CraftServer implements Server {
|
||||||
|
world.ticksPerAmbientSpawns = this.getTicksPerAmbientSpawns();
|
||||||
|
}
|
||||||
|
world.spigotConfig.init(); // Spigot
|
||||||
|
+ world.paperConfig.init(); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginManager.clearPlugins();
|
||||||
|
@@ -846,6 +848,7 @@ public final class CraftServer implements Server {
|
||||||
|
resetRecipes();
|
||||||
|
reloadData();
|
||||||
|
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
|
||||||
|
+ com.destroystokyo.paper.PaperConfig.registerCommands(); // Paper
|
||||||
|
overrideAllCommandBlockCommands = commandsConfiguration.getStringList("command-block-overrides").contains("*");
|
||||||
|
ignoreVanillaPermissions = commandsConfiguration.getBoolean("ignore-vanilla-permissions");
|
||||||
|
|
||||||
|
@@ -2101,4 +2104,35 @@ public final class CraftServer implements Server {
|
||||||
|
return spigot;
|
||||||
|
}
|
||||||
|
// Spigot end
|
||||||
|
+
|
||||||
|
+ // Paper start
|
||||||
|
+ @SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
+ public static java.nio.file.Path dumpHeap(java.nio.file.Path dir, String name) {
|
||||||
|
+ try {
|
||||||
|
+ java.nio.file.Files.createDirectories(dir);
|
||||||
|
+
|
||||||
|
+ javax.management.MBeanServer server = java.lang.management.ManagementFactory.getPlatformMBeanServer();
|
||||||
|
+ java.nio.file.Path file;
|
||||||
|
+
|
||||||
|
+ try {
|
||||||
|
+ Class clazz = Class.forName("openj9.lang.management.OpenJ9DiagnosticsMXBean");
|
||||||
|
+ Object openj9Mbean = java.lang.management.ManagementFactory.newPlatformMXBeanProxy(server, "openj9.lang.management:type=OpenJ9Diagnostics", clazz);
|
||||||
|
+ java.lang.reflect.Method m = clazz.getMethod("triggerDumpToFile", String.class, String.class);
|
||||||
|
+ file = dir.resolve(name + ".phd");
|
||||||
|
+ m.invoke(openj9Mbean, "heap", file.toString());
|
||||||
|
+ } catch (ClassNotFoundException e) {
|
||||||
|
+ Class clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean");
|
||||||
|
+ Object hotspotMBean = java.lang.management.ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", clazz);
|
||||||
|
+ java.lang.reflect.Method m = clazz.getMethod("dumpHeap", String.class, boolean.class);
|
||||||
|
+ file = dir.resolve(name + ".hprof");
|
||||||
|
+ m.invoke(hotspotMBean, file.toString(), true);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return file;
|
||||||
|
+ } catch (Throwable t) {
|
||||||
|
+ Bukkit.getLogger().log(Level.SEVERE, "Could not write heap", t);
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
index 46a16e31775b28c44f95a8ac5545ebcb656c74b6..05aedca561919a12ced1925c5cc9af585bb04523 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
@@ -129,6 +129,14 @@ public class Main {
|
||||||
|
.defaultsTo(new File("spigot.yml"))
|
||||||
|
.describedAs("Yml file");
|
||||||
|
// Spigot End
|
||||||
|
+
|
||||||
|
+ // Paper Start
|
||||||
|
+ acceptsAll(asList("paper", "paper-settings"), "File for paper settings")
|
||||||
|
+ .withRequiredArg()
|
||||||
|
+ .ofType(File.class)
|
||||||
|
+ .defaultsTo(new File("paper.yml"))
|
||||||
|
+ .describedAs("Yml file");
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||||
|
index 83d83ff7ceffbb77723da721b869dfd0091e496d..0efcbab8f8806aeb8dd8bd6384e5a7cee375d100 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||||
|
@@ -39,36 +39,36 @@ public class SpigotWorldConfig
|
||||||
|
config.set( "world-settings.default." + path, val );
|
||||||
|
}
|
||||||
|
|
||||||
|
- private boolean getBoolean(String path, boolean def)
|
||||||
|
+ public boolean getBoolean(String path, boolean def) // Paper - private -> public
|
||||||
|
{
|
||||||
|
config.addDefault( "world-settings.default." + path, def );
|
||||||
|
return config.getBoolean( "world-settings." + worldName + "." + path, config.getBoolean( "world-settings.default." + path ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
- private double getDouble(String path, double def)
|
||||||
|
+ public double getDouble(String path, double def) // Paper - private -> public
|
||||||
|
{
|
||||||
|
config.addDefault( "world-settings.default." + path, def );
|
||||||
|
return config.getDouble( "world-settings." + worldName + "." + path, config.getDouble( "world-settings.default." + path ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
- private int getInt(String path)
|
||||||
|
+ public int getInt(String path) // Paper - private -> public
|
||||||
|
{
|
||||||
|
return config.getInt( "world-settings." + worldName + "." + path );
|
||||||
|
}
|
||||||
|
|
||||||
|
- private int getInt(String path, int def)
|
||||||
|
+ public int getInt(String path, int def) // Paper - private -> public
|
||||||
|
{
|
||||||
|
config.addDefault( "world-settings.default." + path, def );
|
||||||
|
return config.getInt( "world-settings." + worldName + "." + path, config.getInt( "world-settings.default." + path ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
- private <T> List getList(String path, T def)
|
||||||
|
+ public <T> List getList(String path, T def) // Paper - private -> public
|
||||||
|
{
|
||||||
|
config.addDefault( "world-settings.default." + path, def );
|
||||||
|
return (List<T>) config.getList( "world-settings." + worldName + "." + path, config.getList( "world-settings.default." + path ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
- private String getString(String path, String def)
|
||||||
|
+ public String getString(String path, String def) // Paper - private -> public
|
||||||
|
{
|
||||||
|
config.addDefault( "world-settings.default." + path, def );
|
||||||
|
return config.getString( "world-settings." + worldName + "." + path, config.getString( "world-settings.default." + path ) );
|
929
Remapped-Spigot-Server-Patches/0003-MC-Dev-fixes.patch
Normal file
929
Remapped-Spigot-Server-Patches/0003-MC-Dev-fixes.patch
Normal file
File diff suppressed because one or more lines are too long
4859
Remapped-Spigot-Server-Patches/0004-MC-Utils.patch
Normal file
4859
Remapped-Spigot-Server-Patches/0004-MC-Utils.patch
Normal file
File diff suppressed because it is too large
Load diff
735
Remapped-Spigot-Server-Patches/0005-Paper-Metrics.patch
Normal file
735
Remapped-Spigot-Server-Patches/0005-Paper-Metrics.patch
Normal file
|
@ -0,0 +1,735 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Fri, 24 Mar 2017 23:56:01 -0500
|
||||||
|
Subject: [PATCH] Paper Metrics
|
||||||
|
|
||||||
|
Removes Spigot's mcstats metrics in favor of a system using bStats
|
||||||
|
|
||||||
|
To disable for privacy or other reasons go to the bStats folder in your plugins folder
|
||||||
|
and edit the config.yml file present there.
|
||||||
|
|
||||||
|
Please keep in mind the data collected is anonymous and collection should have no
|
||||||
|
tangible effect on server performance. The data is used to allow the authors of
|
||||||
|
PaperMC to track version and platform usage so that we can make better management
|
||||||
|
decisions on behalf of the project.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..0b9e689d57705965721b5c55bc45d36657f360e4
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||||
|
@@ -0,0 +1,670 @@
|
||||||
|
+package com.destroystokyo.paper;
|
||||||
|
+
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
+import org.bukkit.Bukkit;
|
||||||
|
+import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
+import org.bukkit.craftbukkit.util.CraftMagicNumbers;
|
||||||
|
+import org.bukkit.plugin.Plugin;
|
||||||
|
+
|
||||||
|
+import org.json.simple.JSONArray;
|
||||||
|
+import org.json.simple.JSONObject;
|
||||||
|
+
|
||||||
|
+import javax.net.ssl.HttpsURLConnection;
|
||||||
|
+import java.io.ByteArrayOutputStream;
|
||||||
|
+import java.io.DataOutputStream;
|
||||||
|
+import java.io.File;
|
||||||
|
+import java.io.IOException;
|
||||||
|
+import java.net.URL;
|
||||||
|
+import java.util.*;
|
||||||
|
+import java.util.concurrent.Callable;
|
||||||
|
+import java.util.concurrent.Executors;
|
||||||
|
+import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
+import java.util.concurrent.TimeUnit;
|
||||||
|
+import java.util.logging.Level;
|
||||||
|
+import java.util.logging.Logger;
|
||||||
|
+import java.util.regex.Matcher;
|
||||||
|
+import java.util.regex.Pattern;
|
||||||
|
+import java.util.zip.GZIPOutputStream;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * bStats collects some data for plugin authors.
|
||||||
|
+ *
|
||||||
|
+ * Check out https://bStats.org/ to learn more about bStats!
|
||||||
|
+ */
|
||||||
|
+public class Metrics {
|
||||||
|
+
|
||||||
|
+ // Executor service for requests
|
||||||
|
+ // We use an executor service because the Bukkit scheduler is affected by server lags
|
||||||
|
+ private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||||
|
+
|
||||||
|
+ // The version of this bStats class
|
||||||
|
+ public static final int B_STATS_VERSION = 1;
|
||||||
|
+
|
||||||
|
+ // The url to which the data is sent
|
||||||
|
+ private static final String URL = "https://bStats.org/submitData/server-implementation";
|
||||||
|
+
|
||||||
|
+ // Should failed requests be logged?
|
||||||
|
+ private static boolean logFailedRequests = false;
|
||||||
|
+
|
||||||
|
+ // The logger for the failed requests
|
||||||
|
+ private static Logger logger = Logger.getLogger("bStats");
|
||||||
|
+
|
||||||
|
+ // The name of the server software
|
||||||
|
+ private final String name;
|
||||||
|
+
|
||||||
|
+ // The uuid of the server
|
||||||
|
+ private final String serverUUID;
|
||||||
|
+
|
||||||
|
+ // A list with all custom charts
|
||||||
|
+ private final List<CustomChart> charts = new ArrayList<>();
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Class constructor.
|
||||||
|
+ *
|
||||||
|
+ * @param name The name of the server software.
|
||||||
|
+ * @param serverUUID The uuid of the server.
|
||||||
|
+ * @param logFailedRequests Whether failed requests should be logged or not.
|
||||||
|
+ * @param logger The logger for the failed requests.
|
||||||
|
+ */
|
||||||
|
+ public Metrics(String name, String serverUUID, boolean logFailedRequests, Logger logger) {
|
||||||
|
+ this.name = name;
|
||||||
|
+ this.serverUUID = serverUUID;
|
||||||
|
+ Metrics.logFailedRequests = logFailedRequests;
|
||||||
|
+ Metrics.logger = logger;
|
||||||
|
+
|
||||||
|
+ // Start submitting the data
|
||||||
|
+ startSubmitting();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Adds a custom chart.
|
||||||
|
+ *
|
||||||
|
+ * @param chart The chart to add.
|
||||||
|
+ */
|
||||||
|
+ public void addCustomChart(CustomChart chart) {
|
||||||
|
+ if (chart == null) {
|
||||||
|
+ throw new IllegalArgumentException("Chart cannot be null!");
|
||||||
|
+ }
|
||||||
|
+ charts.add(chart);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Starts the Scheduler which submits our data every 30 minutes.
|
||||||
|
+ */
|
||||||
|
+ private void startSubmitting() {
|
||||||
|
+ final Runnable submitTask = this::submitData;
|
||||||
|
+
|
||||||
|
+ // Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution of requests on the
|
||||||
|
+ // bStats backend. To circumvent this problem, we introduce some randomness into the initial and second delay.
|
||||||
|
+ // WARNING: You must not modify any part of this Metrics class, including the submit delay or frequency!
|
||||||
|
+ // WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it!
|
||||||
|
+ long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3));
|
||||||
|
+ long secondDelay = (long) (1000 * 60 * (Math.random() * 30));
|
||||||
|
+ scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS);
|
||||||
|
+ scheduler.scheduleAtFixedRate(submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Gets the plugin specific data.
|
||||||
|
+ *
|
||||||
|
+ * @return The plugin specific data.
|
||||||
|
+ */
|
||||||
|
+ private JSONObject getPluginData() {
|
||||||
|
+ JSONObject data = new JSONObject();
|
||||||
|
+
|
||||||
|
+ data.put("pluginName", name); // Append the name of the server software
|
||||||
|
+ JSONArray customCharts = new JSONArray();
|
||||||
|
+ for (CustomChart customChart : charts) {
|
||||||
|
+ // Add the data of the custom charts
|
||||||
|
+ JSONObject chart = customChart.getRequestJsonObject();
|
||||||
|
+ if (chart == null) { // If the chart is null, we skip it
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ customCharts.add(chart);
|
||||||
|
+ }
|
||||||
|
+ data.put("customCharts", customCharts);
|
||||||
|
+
|
||||||
|
+ return data;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Gets the server specific data.
|
||||||
|
+ *
|
||||||
|
+ * @return The server specific data.
|
||||||
|
+ */
|
||||||
|
+ private JSONObject getServerData() {
|
||||||
|
+ // OS specific data
|
||||||
|
+ String osName = System.getProperty("os.name");
|
||||||
|
+ String osArch = System.getProperty("os.arch");
|
||||||
|
+ String osVersion = System.getProperty("os.version");
|
||||||
|
+ int coreCount = Runtime.getRuntime().availableProcessors();
|
||||||
|
+
|
||||||
|
+ JSONObject data = new JSONObject();
|
||||||
|
+
|
||||||
|
+ data.put("serverUUID", serverUUID);
|
||||||
|
+
|
||||||
|
+ data.put("osName", osName);
|
||||||
|
+ data.put("osArch", osArch);
|
||||||
|
+ data.put("osVersion", osVersion);
|
||||||
|
+ data.put("coreCount", coreCount);
|
||||||
|
+
|
||||||
|
+ return data;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Collects the data and sends it afterwards.
|
||||||
|
+ */
|
||||||
|
+ private void submitData() {
|
||||||
|
+ final JSONObject data = getServerData();
|
||||||
|
+
|
||||||
|
+ JSONArray pluginData = new JSONArray();
|
||||||
|
+ pluginData.add(getPluginData());
|
||||||
|
+ data.put("plugins", pluginData);
|
||||||
|
+
|
||||||
|
+ try {
|
||||||
|
+ // We are still in the Thread of the timer, so nothing get blocked :)
|
||||||
|
+ sendData(data);
|
||||||
|
+ } catch (Exception e) {
|
||||||
|
+ // Something went wrong! :(
|
||||||
|
+ if (logFailedRequests) {
|
||||||
|
+ logger.log(Level.WARNING, "Could not submit stats of " + name, e);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Sends the data to the bStats server.
|
||||||
|
+ *
|
||||||
|
+ * @param data The data to send.
|
||||||
|
+ * @throws Exception If the request failed.
|
||||||
|
+ */
|
||||||
|
+ private static void sendData(JSONObject data) throws Exception {
|
||||||
|
+ if (data == null) {
|
||||||
|
+ throw new IllegalArgumentException("Data cannot be null!");
|
||||||
|
+ }
|
||||||
|
+ HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
|
||||||
|
+
|
||||||
|
+ // Compress the data to save bandwidth
|
||||||
|
+ byte[] compressedData = compress(data.toString());
|
||||||
|
+
|
||||||
|
+ // Add headers
|
||||||
|
+ connection.setRequestMethod("POST");
|
||||||
|
+ connection.addRequestProperty("Accept", "application/json");
|
||||||
|
+ connection.addRequestProperty("Connection", "close");
|
||||||
|
+ connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
|
||||||
|
+ connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
|
||||||
|
+ connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
|
||||||
|
+ connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
|
||||||
|
+
|
||||||
|
+ // Send data
|
||||||
|
+ connection.setDoOutput(true);
|
||||||
|
+ DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
|
||||||
|
+ outputStream.write(compressedData);
|
||||||
|
+ outputStream.flush();
|
||||||
|
+ outputStream.close();
|
||||||
|
+
|
||||||
|
+ connection.getInputStream().close(); // We don't care about the response - Just send our data :)
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Gzips the given String.
|
||||||
|
+ *
|
||||||
|
+ * @param str The string to gzip.
|
||||||
|
+ * @return The gzipped String.
|
||||||
|
+ * @throws IOException If the compression failed.
|
||||||
|
+ */
|
||||||
|
+ private static byte[] compress(final String str) throws IOException {
|
||||||
|
+ if (str == null) {
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
+ GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
|
||||||
|
+ gzip.write(str.getBytes("UTF-8"));
|
||||||
|
+ gzip.close();
|
||||||
|
+ return outputStream.toByteArray();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Represents a custom chart.
|
||||||
|
+ */
|
||||||
|
+ public static abstract class CustomChart {
|
||||||
|
+
|
||||||
|
+ // The id of the chart
|
||||||
|
+ final String chartId;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Class constructor.
|
||||||
|
+ *
|
||||||
|
+ * @param chartId The id of the chart.
|
||||||
|
+ */
|
||||||
|
+ CustomChart(String chartId) {
|
||||||
|
+ if (chartId == null || chartId.isEmpty()) {
|
||||||
|
+ throw new IllegalArgumentException("ChartId cannot be null or empty!");
|
||||||
|
+ }
|
||||||
|
+ this.chartId = chartId;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private JSONObject getRequestJsonObject() {
|
||||||
|
+ JSONObject chart = new JSONObject();
|
||||||
|
+ chart.put("chartId", chartId);
|
||||||
|
+ try {
|
||||||
|
+ JSONObject data = getChartData();
|
||||||
|
+ if (data == null) {
|
||||||
|
+ // If the data is null we don't send the chart.
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ chart.put("data", data);
|
||||||
|
+ } catch (Throwable t) {
|
||||||
|
+ if (logFailedRequests) {
|
||||||
|
+ logger.log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t);
|
||||||
|
+ }
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ return chart;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected abstract JSONObject getChartData() throws Exception;
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Represents a custom simple pie.
|
||||||
|
+ */
|
||||||
|
+ public static class SimplePie extends CustomChart {
|
||||||
|
+
|
||||||
|
+ private final Callable<String> callable;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Class constructor.
|
||||||
|
+ *
|
||||||
|
+ * @param chartId The id of the chart.
|
||||||
|
+ * @param callable The callable which is used to request the chart data.
|
||||||
|
+ */
|
||||||
|
+ public SimplePie(String chartId, Callable<String> callable) {
|
||||||
|
+ super(chartId);
|
||||||
|
+ this.callable = callable;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected JSONObject getChartData() throws Exception {
|
||||||
|
+ JSONObject data = new JSONObject();
|
||||||
|
+ String value = callable.call();
|
||||||
|
+ if (value == null || value.isEmpty()) {
|
||||||
|
+ // Null = skip the chart
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ data.put("value", value);
|
||||||
|
+ return data;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Represents a custom advanced pie.
|
||||||
|
+ */
|
||||||
|
+ public static class AdvancedPie extends CustomChart {
|
||||||
|
+
|
||||||
|
+ private final Callable<Map<String, Integer>> callable;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Class constructor.
|
||||||
|
+ *
|
||||||
|
+ * @param chartId The id of the chart.
|
||||||
|
+ * @param callable The callable which is used to request the chart data.
|
||||||
|
+ */
|
||||||
|
+ public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
|
||||||
|
+ super(chartId);
|
||||||
|
+ this.callable = callable;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected JSONObject getChartData() throws Exception {
|
||||||
|
+ JSONObject data = new JSONObject();
|
||||||
|
+ JSONObject values = new JSONObject();
|
||||||
|
+ Map<String, Integer> map = callable.call();
|
||||||
|
+ if (map == null || map.isEmpty()) {
|
||||||
|
+ // Null = skip the chart
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ boolean allSkipped = true;
|
||||||
|
+ for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||||
|
+ if (entry.getValue() == 0) {
|
||||||
|
+ continue; // Skip this invalid
|
||||||
|
+ }
|
||||||
|
+ allSkipped = false;
|
||||||
|
+ values.put(entry.getKey(), entry.getValue());
|
||||||
|
+ }
|
||||||
|
+ if (allSkipped) {
|
||||||
|
+ // Null = skip the chart
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ data.put("values", values);
|
||||||
|
+ return data;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Represents a custom drilldown pie.
|
||||||
|
+ */
|
||||||
|
+ public static class DrilldownPie extends CustomChart {
|
||||||
|
+
|
||||||
|
+ private final Callable<Map<String, Map<String, Integer>>> callable;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Class constructor.
|
||||||
|
+ *
|
||||||
|
+ * @param chartId The id of the chart.
|
||||||
|
+ * @param callable The callable which is used to request the chart data.
|
||||||
|
+ */
|
||||||
|
+ public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
|
||||||
|
+ super(chartId);
|
||||||
|
+ this.callable = callable;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public JSONObject getChartData() throws Exception {
|
||||||
|
+ JSONObject data = new JSONObject();
|
||||||
|
+ JSONObject values = new JSONObject();
|
||||||
|
+ Map<String, Map<String, Integer>> map = callable.call();
|
||||||
|
+ if (map == null || map.isEmpty()) {
|
||||||
|
+ // Null = skip the chart
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ boolean reallyAllSkipped = true;
|
||||||
|
+ for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||||
|
+ JSONObject value = new JSONObject();
|
||||||
|
+ boolean allSkipped = true;
|
||||||
|
+ for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
|
||||||
|
+ value.put(valueEntry.getKey(), valueEntry.getValue());
|
||||||
|
+ allSkipped = false;
|
||||||
|
+ }
|
||||||
|
+ if (!allSkipped) {
|
||||||
|
+ reallyAllSkipped = false;
|
||||||
|
+ values.put(entryValues.getKey(), value);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (reallyAllSkipped) {
|
||||||
|
+ // Null = skip the chart
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ data.put("values", values);
|
||||||
|
+ return data;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Represents a custom single line chart.
|
||||||
|
+ */
|
||||||
|
+ public static class SingleLineChart extends CustomChart {
|
||||||
|
+
|
||||||
|
+ private final Callable<Integer> callable;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Class constructor.
|
||||||
|
+ *
|
||||||
|
+ * @param chartId The id of the chart.
|
||||||
|
+ * @param callable The callable which is used to request the chart data.
|
||||||
|
+ */
|
||||||
|
+ public SingleLineChart(String chartId, Callable<Integer> callable) {
|
||||||
|
+ super(chartId);
|
||||||
|
+ this.callable = callable;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected JSONObject getChartData() throws Exception {
|
||||||
|
+ JSONObject data = new JSONObject();
|
||||||
|
+ int value = callable.call();
|
||||||
|
+ if (value == 0) {
|
||||||
|
+ // Null = skip the chart
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ data.put("value", value);
|
||||||
|
+ return data;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Represents a custom multi line chart.
|
||||||
|
+ */
|
||||||
|
+ public static class MultiLineChart extends CustomChart {
|
||||||
|
+
|
||||||
|
+ private final Callable<Map<String, Integer>> callable;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Class constructor.
|
||||||
|
+ *
|
||||||
|
+ * @param chartId The id of the chart.
|
||||||
|
+ * @param callable The callable which is used to request the chart data.
|
||||||
|
+ */
|
||||||
|
+ public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) {
|
||||||
|
+ super(chartId);
|
||||||
|
+ this.callable = callable;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected JSONObject getChartData() throws Exception {
|
||||||
|
+ JSONObject data = new JSONObject();
|
||||||
|
+ JSONObject values = new JSONObject();
|
||||||
|
+ Map<String, Integer> map = callable.call();
|
||||||
|
+ if (map == null || map.isEmpty()) {
|
||||||
|
+ // Null = skip the chart
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ boolean allSkipped = true;
|
||||||
|
+ for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||||
|
+ if (entry.getValue() == 0) {
|
||||||
|
+ continue; // Skip this invalid
|
||||||
|
+ }
|
||||||
|
+ allSkipped = false;
|
||||||
|
+ values.put(entry.getKey(), entry.getValue());
|
||||||
|
+ }
|
||||||
|
+ if (allSkipped) {
|
||||||
|
+ // Null = skip the chart
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ data.put("values", values);
|
||||||
|
+ return data;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Represents a custom simple bar chart.
|
||||||
|
+ */
|
||||||
|
+ public static class SimpleBarChart extends CustomChart {
|
||||||
|
+
|
||||||
|
+ private final Callable<Map<String, Integer>> callable;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Class constructor.
|
||||||
|
+ *
|
||||||
|
+ * @param chartId The id of the chart.
|
||||||
|
+ * @param callable The callable which is used to request the chart data.
|
||||||
|
+ */
|
||||||
|
+ public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) {
|
||||||
|
+ super(chartId);
|
||||||
|
+ this.callable = callable;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected JSONObject getChartData() throws Exception {
|
||||||
|
+ JSONObject data = new JSONObject();
|
||||||
|
+ JSONObject values = new JSONObject();
|
||||||
|
+ Map<String, Integer> map = callable.call();
|
||||||
|
+ if (map == null || map.isEmpty()) {
|
||||||
|
+ // Null = skip the chart
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||||
|
+ JSONArray categoryValues = new JSONArray();
|
||||||
|
+ categoryValues.add(entry.getValue());
|
||||||
|
+ values.put(entry.getKey(), categoryValues);
|
||||||
|
+ }
|
||||||
|
+ data.put("values", values);
|
||||||
|
+ return data;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Represents a custom advanced bar chart.
|
||||||
|
+ */
|
||||||
|
+ public static class AdvancedBarChart extends CustomChart {
|
||||||
|
+
|
||||||
|
+ private final Callable<Map<String, int[]>> callable;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Class constructor.
|
||||||
|
+ *
|
||||||
|
+ * @param chartId The id of the chart.
|
||||||
|
+ * @param callable The callable which is used to request the chart data.
|
||||||
|
+ */
|
||||||
|
+ public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) {
|
||||||
|
+ super(chartId);
|
||||||
|
+ this.callable = callable;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected JSONObject getChartData() throws Exception {
|
||||||
|
+ JSONObject data = new JSONObject();
|
||||||
|
+ JSONObject values = new JSONObject();
|
||||||
|
+ Map<String, int[]> map = callable.call();
|
||||||
|
+ if (map == null || map.isEmpty()) {
|
||||||
|
+ // Null = skip the chart
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ boolean allSkipped = true;
|
||||||
|
+ for (Map.Entry<String, int[]> entry : map.entrySet()) {
|
||||||
|
+ if (entry.getValue().length == 0) {
|
||||||
|
+ continue; // Skip this invalid
|
||||||
|
+ }
|
||||||
|
+ allSkipped = false;
|
||||||
|
+ JSONArray categoryValues = new JSONArray();
|
||||||
|
+ for (int categoryValue : entry.getValue()) {
|
||||||
|
+ categoryValues.add(categoryValue);
|
||||||
|
+ }
|
||||||
|
+ values.put(entry.getKey(), categoryValues);
|
||||||
|
+ }
|
||||||
|
+ if (allSkipped) {
|
||||||
|
+ // Null = skip the chart
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ data.put("values", values);
|
||||||
|
+ return data;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ static class PaperMetrics {
|
||||||
|
+ static void startMetrics() {
|
||||||
|
+ // Get the config file
|
||||||
|
+ File configFile = new File(new File((File) MinecraftServer.getServer().options.valueOf("plugins"), "bStats"), "config.yml");
|
||||||
|
+ YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
||||||
|
+
|
||||||
|
+ // Check if the config file exists
|
||||||
|
+ if (!config.isSet("serverUuid")) {
|
||||||
|
+
|
||||||
|
+ // Add default values
|
||||||
|
+ config.addDefault("enabled", true);
|
||||||
|
+ // Every server gets it's unique random id.
|
||||||
|
+ config.addDefault("serverUuid", UUID.randomUUID().toString());
|
||||||
|
+ // Should failed request be logged?
|
||||||
|
+ config.addDefault("logFailedRequests", false);
|
||||||
|
+
|
||||||
|
+ // Inform the server owners about bStats
|
||||||
|
+ config.options().header(
|
||||||
|
+ "bStats collects some data for plugin authors like how many servers are using their plugins.\n" +
|
||||||
|
+ "To honor their work, you should not disable it.\n" +
|
||||||
|
+ "This has nearly no effect on the server performance!\n" +
|
||||||
|
+ "Check out https://bStats.org/ to learn more :)"
|
||||||
|
+ ).copyDefaults(true);
|
||||||
|
+ try {
|
||||||
|
+ config.save(configFile);
|
||||||
|
+ } catch (IOException ignored) {
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Load the data
|
||||||
|
+ String serverUUID = config.getString("serverUuid");
|
||||||
|
+ 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.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> {
|
||||||
|
+ String minecraftVersion = Bukkit.getVersion();
|
||||||
|
+ minecraftVersion = minecraftVersion.substring(minecraftVersion.indexOf("MC: ") + 4, minecraftVersion.length() - 1);
|
||||||
|
+ return minecraftVersion;
|
||||||
|
+ }));
|
||||||
|
+
|
||||||
|
+ metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size()));
|
||||||
|
+ metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() || PaperConfig.isProxyOnlineMode() ? "online" : "offline"));
|
||||||
|
+ metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown"));
|
||||||
|
+
|
||||||
|
+ metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> {
|
||||||
|
+ Map<String, Map<String, Integer>> map = new HashMap<>();
|
||||||
|
+ String javaVersion = System.getProperty("java.version");
|
||||||
|
+ Map<String, Integer> entry = new HashMap<>();
|
||||||
|
+ entry.put(javaVersion, 1);
|
||||||
|
+
|
||||||
|
+ // http://openjdk.java.net/jeps/223
|
||||||
|
+ // Java decided to change their versioning scheme and in doing so modified the java.version system
|
||||||
|
+ // property to return $major[.$minor][.$secuity][-ea], as opposed to 1.$major.0_$identifier
|
||||||
|
+ // we can handle pre-9 by checking if the "major" is equal to "1", otherwise, 9+
|
||||||
|
+ String majorVersion = javaVersion.split("\\.")[0];
|
||||||
|
+ String release;
|
||||||
|
+
|
||||||
|
+ int indexOf = javaVersion.lastIndexOf('.');
|
||||||
|
+
|
||||||
|
+ if (majorVersion.equals("1")) {
|
||||||
|
+ release = "Java " + javaVersion.substring(0, indexOf);
|
||||||
|
+ } else {
|
||||||
|
+ // of course, it really wouldn't be all that simple if they didn't add a quirk, now would it
|
||||||
|
+ // valid strings for the major may potentially include values such as -ea to deannotate a pre release
|
||||||
|
+ Matcher versionMatcher = Pattern.compile("\\d+").matcher(majorVersion);
|
||||||
|
+ if (versionMatcher.find()) {
|
||||||
|
+ majorVersion = versionMatcher.group(0);
|
||||||
|
+ }
|
||||||
|
+ release = "Java " + majorVersion;
|
||||||
|
+ }
|
||||||
|
+ map.put(release, entry);
|
||||||
|
+
|
||||||
|
+ return map;
|
||||||
|
+ }));
|
||||||
|
+
|
||||||
|
+ metrics.addCustomChart(new Metrics.DrilldownPie("legacy_plugins", () -> {
|
||||||
|
+ Map<String, Map<String, Integer>> map = new HashMap<>();
|
||||||
|
+
|
||||||
|
+ // count legacy plugins
|
||||||
|
+ int legacy = 0;
|
||||||
|
+ for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
|
||||||
|
+ if (CraftMagicNumbers.isLegacy(plugin.getDescription())) {
|
||||||
|
+ legacy++;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // insert real value as lower dimension
|
||||||
|
+ Map<String, Integer> entry = new HashMap<>();
|
||||||
|
+ entry.put(String.valueOf(legacy), 1);
|
||||||
|
+
|
||||||
|
+ // create buckets as higher dimension
|
||||||
|
+ if (legacy == 0) {
|
||||||
|
+ map.put("0 \uD83D\uDE0E", entry); // :sunglasses:
|
||||||
|
+ } else if (legacy <= 5) {
|
||||||
|
+ map.put("1-5", entry);
|
||||||
|
+ } else if (legacy <= 10) {
|
||||||
|
+ map.put("6-10", entry);
|
||||||
|
+ } else if (legacy <= 25) {
|
||||||
|
+ map.put("11-25", entry);
|
||||||
|
+ } else if (legacy <= 50) {
|
||||||
|
+ map.put("26-50", entry);
|
||||||
|
+ } else {
|
||||||
|
+ map.put("50+ \uD83D\uDE2D", entry); // :cry:
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return map;
|
||||||
|
+ }));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
index 2c0514892d3993bef57ecf677cf8bb0fbe0216e4..da922f395f0fff0881ead893c900c5b2623f48f0 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
@@ -42,6 +42,7 @@ public class PaperConfig {
|
||||||
|
private static boolean verbose;
|
||||||
|
private static boolean fatalError;
|
||||||
|
/*========================================================================*/
|
||||||
|
+ private static boolean metricsStarted;
|
||||||
|
|
||||||
|
public static void init(File configFile) {
|
||||||
|
CONFIG_FILE = configFile;
|
||||||
|
@@ -84,6 +85,11 @@ public class PaperConfig {
|
||||||
|
for (Map.Entry<String, Command> entry : commands.entrySet()) {
|
||||||
|
MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Paper", entry.getValue());
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ if (!metricsStarted) {
|
||||||
|
+ Metrics.PaperMetrics.startMetrics();
|
||||||
|
+ metricsStarted = true;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readConfig(Class<?> clazz, Object instance) {
|
||||||
|
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
|
||||||
|
index dc11dab14624ca25e78bf0b919ecf461e0be430d..0083f979933d4a9035efb992ab0a2f250a56a979 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/SpigotConfig.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
|
||||||
|
@@ -83,6 +83,7 @@ public class SpigotConfig
|
||||||
|
MinecraftServer.getServer().server.getCommandMap().register( entry.getKey(), "Spigot", entry.getValue() );
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /* // Paper - Replace with our own
|
||||||
|
if ( metrics == null )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
@@ -94,6 +95,7 @@ public class SpigotConfig
|
||||||
|
Bukkit.getServer().getLogger().log( Level.SEVERE, "Could not start metrics service", ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ */ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readConfig(Class<?> clazz, Object instance)
|
|
@ -0,0 +1,144 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Wed, 4 Jul 2018 01:40:13 -0400
|
||||||
|
Subject: [PATCH] Add MinecraftKey Information to Objects
|
||||||
|
|
||||||
|
Stores the reference to the objects respective MinecraftKey
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||||
|
index d05eeaa711a09bb121b530654821894e795ff4ea..e95b91cefb0374bd5bb57cc090f5ecd566d7a618 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||||
|
@@ -208,7 +208,7 @@ public class PaperCommand extends Command {
|
||||||
|
|
||||||
|
Collection<Entity> entities = world.entitiesById.values();
|
||||||
|
entities.forEach(e -> {
|
||||||
|
- ResourceLocation key = new ResourceLocation(""); // TODO: update in next patch
|
||||||
|
+ ResourceLocation key = e.getMinecraftKey();
|
||||||
|
|
||||||
|
MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap()));
|
||||||
|
ChunkPos chunk = new ChunkPos(e.xChunk, e.zChunk);
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/KeyedObject.java b/src/main/java/net/minecraft/server/KeyedObject.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..3c9933050ca0a7453ba7950cb3cf4cc8b5b7081d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/net/minecraft/server/KeyedObject.java
|
||||||
|
@@ -0,0 +1,11 @@
|
||||||
|
+package net.minecraft.server;
|
||||||
|
+
|
||||||
|
+import net.minecraft.resources.ResourceLocation;
|
||||||
|
+
|
||||||
|
+public interface KeyedObject {
|
||||||
|
+ ResourceLocation getMinecraftKey();
|
||||||
|
+ default String getMinecraftKeyString() {
|
||||||
|
+ ResourceLocation key = getMinecraftKey();
|
||||||
|
+ return key != null ? key.toString() : null;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index c7008fcbd4d805fe0e743f1d4ad948dcd86ceae3..48c9d2b7d56832ebd13749a394b8b715f0b1704d 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -135,7 +135,7 @@ import org.bukkit.event.player.PlayerTeleportEvent;
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
-public abstract class Entity implements Nameable, CommandSource {
|
||||||
|
+public abstract class Entity implements Nameable, CommandSource, net.minecraft.server.KeyedObject { // Paper
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
private static final int CURRENT_LEVEL = 2;
|
||||||
|
@@ -1761,12 +1761,31 @@ public abstract class Entity implements Nameable, CommandSource {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ private ResourceLocation entityKey;
|
||||||
|
+ private String entityKeyString;
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public ResourceLocation getMinecraftKey() {
|
||||||
|
+ if (entityKey == null) {
|
||||||
|
+ this.entityKey = EntityType.getKey(this.getType());
|
||||||
|
+ this.entityKeyString = this.entityKey != null ? this.entityKey.toString() : null;
|
||||||
|
+ }
|
||||||
|
+ return entityKey;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public String getMinecraftKeyString() {
|
||||||
|
+ getMinecraftKey(); // Try to load if it doesn't exists. see: https://github.com/PaperMC/Paper/issues/1280
|
||||||
|
+ return entityKeyString;
|
||||||
|
+ }
|
||||||
|
@Nullable
|
||||||
|
public final String getEncodeId() {
|
||||||
|
EntityType<?> entitytypes = this.getType();
|
||||||
|
ResourceLocation minecraftkey = EntityType.getKey(entitytypes);
|
||||||
|
|
||||||
|
- return entitytypes.canSerialize() && minecraftkey != null ? minecraftkey.toString() : null;
|
||||||
|
+ return entitytypes != null && entitytypes.isPersistable() ? getMinecraftKeyString() : null;
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void readAdditionalSaveData(CompoundTag tag);
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||||
|
index 102298d57cf3143092d04ab1d5d0d69b28d696ea..2cb86de4bfc87a709f0cfa2c4e550d8e7928a3f0 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||||
|
@@ -384,6 +384,7 @@ public class EntityType<T extends Entity> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public boolean isPersistable() { return canSerialize(); } // Paper - OBFHELPER
|
||||||
|
public boolean canSerialize() {
|
||||||
|
return this.serialize;
|
||||||
|
}
|
||||||
|
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 8928a1ae51d24fd15aaae93bc8ea573548f2b012..846fc0f36377337630b2ec2a5f7a5a54c39c2965 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
|
||||||
|
@@ -23,7 +23,7 @@ import org.bukkit.inventory.InventoryHolder;
|
||||||
|
|
||||||
|
import org.spigotmc.CustomTimingsHandler; // Spigot
|
||||||
|
|
||||||
|
-public abstract class BlockEntity {
|
||||||
|
+public abstract class BlockEntity implements net.minecraft.server.KeyedObject { // Paper
|
||||||
|
|
||||||
|
public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getTileEntityTimings(this); // Spigot
|
||||||
|
// CraftBukkit start - data containers
|
||||||
|
@@ -31,7 +31,7 @@ public abstract class BlockEntity {
|
||||||
|
public CraftPersistentDataContainer persistentDataContainer;
|
||||||
|
// CraftBukkit end
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
- private final BlockEntityType<?> type;
|
||||||
|
+ private final BlockEntityType<?> type; public BlockEntityType getTileEntityType() { return type; } // Paper - OBFHELPER
|
||||||
|
@Nullable
|
||||||
|
protected Level level;
|
||||||
|
protected BlockPos worldPosition;
|
||||||
|
@@ -45,6 +45,26 @@ public abstract class BlockEntity {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ private String tileEntityKeyString = null;
|
||||||
|
+ private ResourceLocation tileEntityKey = null;
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public ResourceLocation getMinecraftKey() {
|
||||||
|
+ if (tileEntityKey == null) {
|
||||||
|
+ tileEntityKey = BlockEntityType.getKey(this.getTileEntityType());
|
||||||
|
+ tileEntityKeyString = tileEntityKey != null ? tileEntityKey.toString() : null;
|
||||||
|
+ }
|
||||||
|
+ return tileEntityKey;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public String getMinecraftKeyString() {
|
||||||
|
+ getMinecraftKey(); // Try to load if it doesn't exists.
|
||||||
|
+ return tileEntityKeyString;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
@Nullable
|
||||||
|
public Level getLevel() {
|
||||||
|
return this.level;
|
|
@ -0,0 +1,171 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Wed, 4 Jul 2018 02:10:36 -0400
|
||||||
|
Subject: [PATCH] Store reference to current Chunk for Entity and Block
|
||||||
|
Entities
|
||||||
|
|
||||||
|
This enables us a fast reference to the entities current chunk instead
|
||||||
|
of having to look it up by hashmap lookups.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 48c9d2b7d56832ebd13749a394b8b715f0b1704d..b633f6b3a36b793e6dbc1b8b554bfba74c719570 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -260,7 +260,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isChunkLoaded() {
|
||||||
|
- return level.hasChunk((int) Math.floor(this.getX()) >> 4, (int) Math.floor(this.getZ()) >> 4);
|
||||||
|
+ return getCurrentChunk() != null;
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
@@ -1762,6 +1762,23 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paper start
|
||||||
|
+ public java.lang.ref.WeakReference<net.minecraft.world.level.chunk.LevelChunk> currentChunk = null;
|
||||||
|
+
|
||||||
|
+ public void setCurrentChunk(net.minecraft.world.level.chunk.LevelChunk chunk) {
|
||||||
|
+ this.currentChunk = chunk != null ? new java.lang.ref.WeakReference<>(chunk) : null;
|
||||||
|
+ }
|
||||||
|
+ /**
|
||||||
|
+ * Returns the entities current registered chunk. If the entity is not added to a chunk yet, it will return null
|
||||||
|
+ */
|
||||||
|
+ public net.minecraft.world.level.chunk.LevelChunk getCurrentChunk() {
|
||||||
|
+ final net.minecraft.world.level.chunk.LevelChunk chunk = currentChunk != null ? currentChunk.get() : null;
|
||||||
|
+ if (chunk != null && chunk.loaded) {
|
||||||
|
+ return chunk;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return !inChunk ? null : ((ServerLevel)level).getChunkSource().getChunkAtIfLoadedMainThreadNoCache(xChunk, zChunk);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
private ResourceLocation entityKey;
|
||||||
|
private String entityKeyString;
|
||||||
|
|
||||||
|
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 846fc0f36377337630b2ec2a5f7a5a54c39c2965..bb60c9da9f3ba0d5c5bad22512675ccb841a60e5 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
|
||||||
|
@@ -11,6 +11,7 @@ import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Mirror;
|
||||||
|
import net.minecraft.world.level.block.Rotation;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
+import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.apache.logging.log4j.util.Supplier;
|
||||||
|
@@ -63,6 +64,15 @@ public abstract class BlockEntity implements net.minecraft.server.KeyedObject {
|
||||||
|
getMinecraftKey(); // Try to load if it doesn't exists.
|
||||||
|
return tileEntityKeyString;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ private java.lang.ref.WeakReference<LevelChunk> currentChunk = null;
|
||||||
|
+ public LevelChunk getCurrentChunk() {
|
||||||
|
+ final LevelChunk chunk = currentChunk != null ? currentChunk.get() : null;
|
||||||
|
+ return chunk != null && chunk.loaded ? chunk : null;
|
||||||
|
+ }
|
||||||
|
+ public void setCurrentChunk(LevelChunk chunk) {
|
||||||
|
+ this.currentChunk = chunk != null ? new java.lang.ref.WeakReference<>(chunk) : null;
|
||||||
|
+ }
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
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 e2c5a17aa72d1a5412d76881187d4d9ad1763297..ae08fcce66d50d7f61bc3bd4a0e2547d56f53e82 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
@@ -89,11 +89,36 @@ public class LevelChunk implements ChunkAccess {
|
||||||
|
this(world, pos, biomes, UpgradeData.EMPTY, EmptyTickList.empty(), EmptyTickList.empty(), 0L, (LevelChunkSection[]) null, (Consumer) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ private class TileEntityHashMap extends java.util.HashMap<BlockPos, BlockEntity> {
|
||||||
|
+ @Override
|
||||||
|
+ public BlockEntity put(BlockPos key, BlockEntity value) {
|
||||||
|
+ BlockEntity replaced = super.put(key, value);
|
||||||
|
+ if (replaced != null) {
|
||||||
|
+ replaced.setCurrentChunk(null);
|
||||||
|
+ }
|
||||||
|
+ if (value != null) {
|
||||||
|
+ value.setCurrentChunk(LevelChunk.this);
|
||||||
|
+ }
|
||||||
|
+ return replaced;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public BlockEntity remove(Object key) {
|
||||||
|
+ BlockEntity removed = super.remove(key);
|
||||||
|
+ if (removed != null) {
|
||||||
|
+ removed.setCurrentChunk(null);
|
||||||
|
+ }
|
||||||
|
+ return removed;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
public LevelChunk(Level world, ChunkPos pos, ChunkBiomeContainer biomes, UpgradeData upgradeData, TickList<Block> blockTickScheduler, TickList<Fluid> fluidTickScheduler, long inhabitedTime, @Nullable LevelChunkSection[] sections, @Nullable Consumer<LevelChunk> loadToWorldConsumer) {
|
||||||
|
this.sections = new LevelChunkSection[16];
|
||||||
|
this.pendingBlockEntities = Maps.newHashMap();
|
||||||
|
this.heightmaps = Maps.newEnumMap(Heightmap.Types.class);
|
||||||
|
- this.blockEntities = Maps.newHashMap();
|
||||||
|
+ this.blockEntities = new TileEntityHashMap(); // Paper
|
||||||
|
this.structureStarts = Maps.newHashMap();
|
||||||
|
this.structuresRefences = Maps.newHashMap();
|
||||||
|
this.postProcessing = new ShortList[16];
|
||||||
|
@@ -504,6 +529,7 @@ public class LevelChunk implements ChunkAccess {
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.inChunk = true;
|
||||||
|
+ entity.setCurrentChunk(this); // Paper
|
||||||
|
entity.xChunk = this.chunkPos.x;
|
||||||
|
entity.yChunk = k;
|
||||||
|
entity.zChunk = this.chunkPos.z;
|
||||||
|
@@ -516,6 +542,7 @@ public class LevelChunk implements ChunkAccess {
|
||||||
|
((Heightmap) this.heightmaps.get(type)).setRawData(heightmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public final void removeEntity(Entity entity) { this.removeEntity(entity); } // Paper - OBFHELPER
|
||||||
|
public void removeEntity(Entity entity) {
|
||||||
|
this.removeEntity(entity, entity.yChunk);
|
||||||
|
}
|
||||||
|
@@ -530,7 +557,12 @@ public class LevelChunk implements ChunkAccess {
|
||||||
|
section = this.entitySlices.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
- this.entitySlices[section].remove(entity);
|
||||||
|
+ // Paper start
|
||||||
|
+ if (entity.currentChunk != null && entity.currentChunk.get() == this) entity.setCurrentChunk(null);
|
||||||
|
+ if (!this.entitySlices[section].remove(entity)) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
this.entities.remove(entity); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
index 080d3292e03c5a179b9eb89da1550718d263f817..eb61c803cf74c5ca2c51d5027a02ed3db6b53096 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
@@ -145,6 +145,7 @@ import net.minecraft.world.entity.vehicle.MinecartHopper;
|
||||||
|
import net.minecraft.world.entity.vehicle.MinecartSpawner;
|
||||||
|
import net.minecraft.world.entity.vehicle.MinecartTNT;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
+import org.bukkit.Chunk; // Paper
|
||||||
|
import org.bukkit.EntityEffect;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
@@ -186,6 +187,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||||
|
this.entity = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ @Override
|
||||||
|
+ public Chunk getChunk() {
|
||||||
|
+ net.minecraft.world.level.chunk.LevelChunk currentChunk = entity.getCurrentChunk();
|
||||||
|
+ return currentChunk != null ? currentChunk.bukkitChunk : getLocation().getChunk();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
public static CraftEntity getEntity(CraftServer server, Entity entity) {
|
||||||
|
/*
|
||||||
|
* Order is *EXTREMELY* important -- keep it right! =D
|
|
@ -0,0 +1,55 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Wed, 4 Jul 2018 02:13:59 -0400
|
||||||
|
Subject: [PATCH] Store counts for each Entity/Block Entity Type
|
||||||
|
|
||||||
|
Opens door for future patches to optimize performance
|
||||||
|
|
||||||
|
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 ae08fcce66d50d7f61bc3bd4a0e2547d56f53e82..00ce55c17980da87a3834f952475a766543506b0 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
@@ -90,15 +90,19 @@ public class LevelChunk implements ChunkAccess {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paper start
|
||||||
|
+ public final co.aikar.util.Counter<String> entityCounts = new co.aikar.util.Counter<>();
|
||||||
|
+ public final co.aikar.util.Counter<String> tileEntityCounts = new co.aikar.util.Counter<>();
|
||||||
|
private class TileEntityHashMap extends java.util.HashMap<BlockPos, BlockEntity> {
|
||||||
|
@Override
|
||||||
|
public BlockEntity put(BlockPos key, BlockEntity value) {
|
||||||
|
BlockEntity replaced = super.put(key, value);
|
||||||
|
if (replaced != null) {
|
||||||
|
replaced.setCurrentChunk(null);
|
||||||
|
+ tileEntityCounts.decrement(replaced.getMinecraftKeyString());
|
||||||
|
}
|
||||||
|
if (value != null) {
|
||||||
|
value.setCurrentChunk(LevelChunk.this);
|
||||||
|
+ tileEntityCounts.increment(value.getMinecraftKeyString());
|
||||||
|
}
|
||||||
|
return replaced;
|
||||||
|
}
|
||||||
|
@@ -108,6 +112,7 @@ public class LevelChunk implements ChunkAccess {
|
||||||
|
BlockEntity removed = super.remove(key);
|
||||||
|
if (removed != null) {
|
||||||
|
removed.setCurrentChunk(null);
|
||||||
|
+ tileEntityCounts.decrement(removed.getMinecraftKeyString());
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
@@ -528,6 +533,7 @@ public class LevelChunk implements ChunkAccess {
|
||||||
|
k = this.entitySlices.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (!entity.inChunk || entity.getCurrentChunk() != this) entityCounts.increment(entity.getMinecraftKeyString()); // Paper
|
||||||
|
entity.inChunk = true;
|
||||||
|
entity.setCurrentChunk(this); // Paper
|
||||||
|
entity.xChunk = this.chunkPos.x;
|
||||||
|
@@ -562,6 +568,7 @@ public class LevelChunk implements ChunkAccess {
|
||||||
|
if (!this.entitySlices[section].remove(entity)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
+ entityCounts.decrement(entity.getMinecraftKeyString());
|
||||||
|
// Paper end
|
||||||
|
this.entities.remove(entity); // Paper
|
||||||
|
}
|
2330
Remapped-Spigot-Server-Patches/0009-Timings-v2.patch
Normal file
2330
Remapped-Spigot-Server-Patches/0009-Timings-v2.patch
Normal file
File diff suppressed because it is too large
Load diff
3238
Remapped-Spigot-Server-Patches/0010-Adventure.patch
Normal file
3238
Remapped-Spigot-Server-Patches/0010-Adventure.patch
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,114 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Tue, 1 Mar 2016 13:02:51 -0600
|
||||||
|
Subject: [PATCH] Configurable cactus bamboo and reed growth heights
|
||||||
|
|
||||||
|
Bamboo - Both the minimum fully-grown heights and the maximum are configurable
|
||||||
|
- Machine_Maker
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index b31109d2dadd29e8852468c19265066b773d2be0..3618cc017feb60e257a28f67cbddca3f792a9833 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -65,4 +65,17 @@ public class PaperWorldConfig {
|
||||||
|
config.addDefault("world-settings.default." + path, def);
|
||||||
|
return config.getString("world-settings." + worldName + "." + path, config.getString("world-settings.default." + path));
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public int cactusMaxHeight;
|
||||||
|
+ public int reedMaxHeight;
|
||||||
|
+ public int bambooMaxHeight;
|
||||||
|
+ public int bambooMinHeight;
|
||||||
|
+ private void blockGrowthHeight() {
|
||||||
|
+ cactusMaxHeight = getInt("max-growth-height.cactus", 3);
|
||||||
|
+ reedMaxHeight = getInt("max-growth-height.reeds", 3);
|
||||||
|
+ bambooMaxHeight = getInt("max-growth-height.bamboo.max", 16);
|
||||||
|
+ bambooMinHeight = getInt("max-growth-height.bamboo.min", 11);
|
||||||
|
+ log("Max height for cactus growth " + cactusMaxHeight + ". Max height for reed growth " + reedMaxHeight + ". Max height for bamboo growth " + bambooMaxHeight + ". Min height for fully-grown bamboo " + bambooMinHeight + ".");
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/block/BambooBlock.java b/src/main/java/net/minecraft/world/level/block/BambooBlock.java
|
||||||
|
index 8f423ae6261434a670bb94aa70b6bc1694f1fc45..36583c189aa5e55de7f5eba362285e57c8279176 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/BambooBlock.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/BambooBlock.java
|
||||||
|
@@ -124,7 +124,7 @@ public class BambooBlock extends Block implements BonemealableBlock {
|
||||||
|
if (random.nextInt(Math.max(1, (int) (100.0F / world.spigotConfig.bambooModifier) * 3)) == 0 && world.isEmptyBlock(pos.above()) && world.getRawBrightness(pos.above(), 0) >= 9) { // Spigot
|
||||||
|
int i = this.getHeightBelowUpToMax(world, pos) + 1;
|
||||||
|
|
||||||
|
- if (i < 16) {
|
||||||
|
+ if (i < world.paperConfig.bambooMaxHeight) { // Paper
|
||||||
|
this.growBamboo(state, (Level) world, pos, random, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -155,7 +155,7 @@ public class BambooBlock extends Block implements BonemealableBlock {
|
||||||
|
int i = this.getHeightAboveUpToMax(world, pos);
|
||||||
|
int j = this.getHeightBelowUpToMax(world, pos);
|
||||||
|
|
||||||
|
- return i + j + 1 < 16 && (Integer) world.getBlockState(pos.above(i)).getValue(BambooBlock.STAGE) != 1;
|
||||||
|
+ return i + j + 1 < ((Level) world).paperConfig.bambooMaxHeight && (Integer) world.getBlockState(pos.above(i)).getValue(BambooBlock.STAGE) != 1; // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@@ -174,7 +174,7 @@ public class BambooBlock extends Block implements BonemealableBlock {
|
||||||
|
BlockPos blockposition1 = pos.above(i);
|
||||||
|
BlockState iblockdata1 = world.getBlockState(blockposition1);
|
||||||
|
|
||||||
|
- if (k >= 16 || !iblockdata1.is(Blocks.BAMBOO) || (Integer) iblockdata1.getValue(BambooBlock.STAGE) == 1 || !world.isEmptyBlock(blockposition1.above())) { // CraftBukkit - If the BlockSpreadEvent was cancelled, we have no bamboo here
|
||||||
|
+ if (k >= world.paperConfig.bambooMaxHeight || !iblockdata1.is(Blocks.BAMBOO) || (Integer) iblockdata1.getValue(BambooBlock.STAGE) == 1 || !world.isEmptyBlock(blockposition1.above())) { // CraftBukkit - If the BlockSpreadEvent was cancelled, we have no bamboo here // Paper - Configurable cactus bamboo and reed growth heights
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -215,7 +215,7 @@ public class BambooBlock extends Block implements BonemealableBlock {
|
||||||
|
}
|
||||||
|
|
||||||
|
int j = (Integer) state.getValue(BambooBlock.AGE) != 1 && !iblockdata2.is(Blocks.BAMBOO) ? 0 : 1;
|
||||||
|
- int k = (height < 11 || random.nextFloat() >= 0.25F) && height != 15 ? 0 : 1;
|
||||||
|
+ int k = (height < world.paperConfig.bambooMinHeight || random.nextFloat() >= 0.25F) && height != (world.paperConfig.bambooMaxHeight - 1) ? 0 : 1; // Paper
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, pos.above(), (BlockState) ((BlockState) ((BlockState) this.defaultBlockState().setValue(BambooBlock.AGE, j)).setValue(BambooBlock.LEAVES, blockpropertybamboosize)).setValue(BambooBlock.STAGE, k), 3)) {
|
||||||
|
@@ -230,7 +230,7 @@ public class BambooBlock extends Block implements BonemealableBlock {
|
||||||
|
protected int getHeightAboveUpToMax(BlockGetter world, BlockPos pos) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
- for (i = 0; i < 16 && world.getBlockState(pos.above(i + 1)).is(Blocks.BAMBOO); ++i) {
|
||||||
|
+ for (i = 0; i < ((Level) world).paperConfig.bambooMaxHeight && world.getBlockState(pos.above(i + 1)).is(Blocks.BAMBOO); ++i) { // Paper
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -240,7 +240,7 @@ public class BambooBlock extends Block implements BonemealableBlock {
|
||||||
|
protected int getHeightBelowUpToMax(BlockGetter world, BlockPos pos) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
- for (i = 0; i < 16 && world.getBlockState(pos.below(i + 1)).is(Blocks.BAMBOO); ++i) {
|
||||||
|
+ for (i = 0; i < ((Level) world).paperConfig.bambooMaxHeight && world.getBlockState(pos.below(i + 1)).is(Blocks.BAMBOO); ++i) { // Paper
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 d07fd9c1f726b1d45992352408499034c12683e6..de61393e3f702554817d81ff10693ec3fb63d492 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/CactusBlock.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/CactusBlock.java
|
||||||
|
@@ -54,7 +54,7 @@ public class CactusBlock extends Block {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (i < 3) {
|
||||||
|
+ if (i < world.paperConfig.cactusMaxHeight) { // Paper - Configurable growth height
|
||||||
|
int j = (Integer) state.getValue(CactusBlock.AGE);
|
||||||
|
|
||||||
|
if (j >= (byte) range(3, ((100.0F / world.spigotConfig.cactusModifier) * 15) + 0.5F, 15)) { // Spigot
|
||||||
|
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 25f634ee93fa4678eaf09694d98783f2aef9d0f0..a795732af122204b88a01311e73892658132da25 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
|
||||||
|
@@ -51,7 +51,7 @@ public class SugarCaneBlock extends Block {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (i < 3) {
|
||||||
|
+ if (i < world.paperConfig.reedMaxHeight) { // Paper - Configurable growth height
|
||||||
|
int j = (Integer) state.getValue(SugarCaneBlock.AGE);
|
||||||
|
|
||||||
|
if (j >= (byte) range(3, ((100.0F / world.spigotConfig.caneModifier) * 15) + 0.5F, 15)) { // Spigot
|
|
@ -0,0 +1,51 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Tue, 1 Mar 2016 13:09:16 -0600
|
||||||
|
Subject: [PATCH] Configurable baby zombie movement speed
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 3618cc017feb60e257a28f67cbddca3f792a9833..796c17e0941922a9716212c6eae91643d8360418 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -78,4 +78,15 @@ public class PaperWorldConfig {
|
||||||
|
log("Max height for cactus growth " + cactusMaxHeight + ". Max height for reed growth " + reedMaxHeight + ". Max height for bamboo growth " + bambooMaxHeight + ". Min height for fully-grown bamboo " + bambooMinHeight + ".");
|
||||||
|
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public double babyZombieMovementModifier;
|
||||||
|
+ private void babyZombieMovementModifier() {
|
||||||
|
+ babyZombieMovementModifier = getDouble("baby-zombie-movement-modifier", 0.5D);
|
||||||
|
+ if (PaperConfig.version < 20) {
|
||||||
|
+ babyZombieMovementModifier = getDouble("baby-zombie-movement-speed", 0.5D);
|
||||||
|
+ set("baby-zombie-movement-modifier", babyZombieMovementModifier);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ log("Baby zombies will move at the speed of " + babyZombieMovementModifier);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
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 992c9646c274350b30c1abb75e0469adc471397f..94e2a8f74e74d68d4a9b82b667fbff24b7e9e629 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||||
|
@@ -79,7 +79,7 @@ import org.bukkit.event.entity.EntityTransformEvent;
|
||||||
|
public class Zombie extends Monster {
|
||||||
|
|
||||||
|
private static final UUID SPEED_MODIFIER_BABY_UUID = UUID.fromString("B9766B59-9566-4402-BC1F-2EE2A276D836");
|
||||||
|
- private static final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_UUID, "Baby speed boost", 0.5D, AttributeModifier.Operation.MULTIPLY_BASE);
|
||||||
|
+ private final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_UUID, "Baby speed boost", 0.5D, AttributeModifier.Operation.MULTIPLY_BASE); private final AttributeModifier babyModifier = this.SPEED_MODIFIER_BABY; // Paper - remove static - Make baby speed configurable
|
||||||
|
private static final EntityDataAccessor<Boolean> DATA_BABY_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.BOOLEAN);
|
||||||
|
private static final EntityDataAccessor<Integer> DATA_SPECIAL_TYPE_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.INT);
|
||||||
|
public static final EntityDataAccessor<Boolean> DATA_DROWNED_CONVERSION_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.BOOLEAN);
|
||||||
|
@@ -182,9 +182,9 @@ public class Zombie extends Monster {
|
||||||
|
if (this.level != null && !this.level.isClientSide) {
|
||||||
|
AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
|
||||||
|
|
||||||
|
- attributemodifiable.removeModifier(Zombie.SPEED_MODIFIER_BABY);
|
||||||
|
+ attributemodifiable.removeModifier(this.babyModifier); // Paper
|
||||||
|
if (baby) {
|
||||||
|
- attributemodifiable.addTransientModifier(Zombie.SPEED_MODIFIER_BABY);
|
||||||
|
+ attributemodifiable.addTransientModifier(this.babyModifier); // Paper
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Tue, 1 Mar 2016 13:14:11 -0600
|
||||||
|
Subject: [PATCH] Configurable fishing time ranges
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 796c17e0941922a9716212c6eae91643d8360418..78948c42b13194005bdbbbc69c2b7ae0732a78c5 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -89,4 +89,12 @@ public class PaperWorldConfig {
|
||||||
|
|
||||||
|
log("Baby zombies will move at the speed of " + babyZombieMovementModifier);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public int fishingMinTicks;
|
||||||
|
+ public int fishingMaxTicks;
|
||||||
|
+ private void fishingTickRange() {
|
||||||
|
+ fishingMinTicks = getInt("fishing-time-range.MinimumTicks", 100);
|
||||||
|
+ fishingMaxTicks = getInt("fishing-time-range.MaximumTicks", 600);
|
||||||
|
+ log("Fishing time ranges are between " + fishingMinTicks +" and " + fishingMaxTicks + " ticks");
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
|
||||||
|
index d74dae6d7bd78c082b39a4e38da640a57c40b341..2f67c2065ef29f17f12190b25bd1ea53e1fb55b4 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
|
||||||
|
@@ -82,6 +82,10 @@ public class FishingHook extends Projectile {
|
||||||
|
owner.fishing = this;
|
||||||
|
this.luck = Math.max(0, lureLevel);
|
||||||
|
this.lureSpeed = Math.max(0, luckOfTheSeaLevel);
|
||||||
|
+ // Paper start
|
||||||
|
+ minWaitTime = world.paperConfig.fishingMinTicks;
|
||||||
|
+ maxWaitTime = world.paperConfig.fishingMaxTicks;
|
||||||
|
+ // paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
public FishingHook(net.minecraft.world.entity.player.Player thrower, Level world, int lureLevel, int luckOfTheSeaLevel) {
|
|
@ -0,0 +1,105 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Tue, 1 Mar 2016 13:24:16 -0600
|
||||||
|
Subject: [PATCH] Allow nerfed mobs to jump and take water damage
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 78948c42b13194005bdbbbc69c2b7ae0732a78c5..b41e7922dd96c3358eb849ab39982a75736e3476 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -97,4 +97,9 @@ public class PaperWorldConfig {
|
||||||
|
fishingMaxTicks = getInt("fishing-time-range.MaximumTicks", 600);
|
||||||
|
log("Fishing time ranges are between " + fishingMinTicks +" and " + fishingMaxTicks + " ticks");
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean nerfedMobsShouldJump;
|
||||||
|
+ private void nerfedMobsShouldJump() {
|
||||||
|
+ nerfedMobsShouldJump = getBoolean("spawner-nerfed-mobs-should-jump", false);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 2a7f587e19fcdd6d01b360d6b47d9eadd9df92cc..584e83441a9fef88eb1b0a29bec8bda29d6a0c9c 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -1104,6 +1104,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
return this.isInWater() || this.isInRain();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public final boolean isInWaterOrRainOrBubble() { return isInWaterRainOrBubble(); } // Paper - OBFHELPER
|
||||||
|
public boolean isInWaterRainOrBubble() {
|
||||||
|
return this.isInWater() || this.isInRain() || this.isInBubbleColumn();
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||||
|
index 99cb4dc1a1009d4a29e651c94d21babcc61388ed..151ebcffc1f2ae02fa55ab83d2ae7d8a0057f29d 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||||
|
@@ -1,5 +1,6 @@
|
||||||
|
package net.minecraft.world.entity;
|
||||||
|
|
||||||
|
+import PathfinderGoalFloat;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
@@ -96,6 +97,7 @@ public abstract class Mob extends LivingEntity {
|
||||||
|
private final BodyRotationControl bodyRotationControl;
|
||||||
|
protected PathNavigation navigation;
|
||||||
|
public GoalSelector goalSelector;
|
||||||
|
+ @Nullable public PathfinderGoalFloat goalFloat; // Paper
|
||||||
|
public GoalSelector targetSelector;
|
||||||
|
private LivingEntity target;
|
||||||
|
private final Sensing sensing;
|
||||||
|
@@ -782,7 +784,17 @@ public abstract class Mob extends LivingEntity {
|
||||||
|
@Override
|
||||||
|
protected final void serverAiStep() {
|
||||||
|
++this.noActionTime;
|
||||||
|
- if (!this.aware) return; // CraftBukkit
|
||||||
|
+ if (!this.aware) { // Paper start - Allow nerfed mobs to jump, float and take water damage
|
||||||
|
+ if (goalFloat != null) {
|
||||||
|
+ if (goalFloat.validConditions()) goalFloat.update();
|
||||||
|
+ this.getJumpControl().jumpIfSet();
|
||||||
|
+ }
|
||||||
|
+ if ((this instanceof EntityBlaze || this instanceof EntityEnderman) && isInWaterOrRainOrBubble()) {
|
||||||
|
+ hurt(DamageSource.DROWN, 1.0F);
|
||||||
|
+ }
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
this.level.getProfiler().push("sensing");
|
||||||
|
this.sensing.tick();
|
||||||
|
this.level.getProfiler().pop();
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/control/JumpControl.java b/src/main/java/net/minecraft/world/entity/ai/control/JumpControl.java
|
||||||
|
index 5f7ad2b57d8d8f0f6a7d880f55e08b52f017cf51..09d1cda50ce9076e9236d124aa7766a26a50dae1 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/ai/control/JumpControl.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/ai/control/JumpControl.java
|
||||||
|
@@ -15,6 +15,7 @@ public class JumpControl {
|
||||||
|
this.jump = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public final void jumpIfSet() { this.tick(); } // Paper - OBFHELPER
|
||||||
|
public void tick() {
|
||||||
|
this.mob.setJumping(this.jump);
|
||||||
|
this.jump = false;
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/FloatGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/FloatGoal.java
|
||||||
|
index 7ea5cb5a92ff3b66859ebcd53031aa06689bd329..790b5646683247ef757095a0763dc52701afe97b 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/ai/goal/FloatGoal.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/FloatGoal.java
|
||||||
|
@@ -11,15 +11,18 @@ public class FloatGoal extends Goal {
|
||||||
|
|
||||||
|
public FloatGoal(Mob mob) {
|
||||||
|
this.mob = mob;
|
||||||
|
+ if (mob.getCommandSenderWorld().paperConfig.nerfedMobsShouldJump) mob.goalFloat = this; // Paper
|
||||||
|
this.setFlags(EnumSet.of(Goal.Flag.JUMP));
|
||||||
|
mob.getNavigation().setCanFloat(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public final boolean validConditions() { return this.canUse(); } // Paper - OBFHELPER
|
||||||
|
@Override
|
||||||
|
public boolean canUse() {
|
||||||
|
return this.mob.isInWater() && this.mob.getFluidHeight((Tag) FluidTags.WATER) > this.mob.getFluidJumpThreshold() || this.mob.isInLava();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public void update() { this.tick(); } // Paper - OBFHELPER
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (this.mob.getRandom().nextFloat() < 0.8F) {
|
|
@ -0,0 +1,55 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Suddenly <suddenly@suddenly.coffee>
|
||||||
|
Date: Tue, 1 Mar 2016 13:51:54 -0600
|
||||||
|
Subject: [PATCH] Add configurable despawn distances for living entities
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index b41e7922dd96c3358eb849ab39982a75736e3476..2f0d582baf0eb2bb477944d0cb1369db6ca33956 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -102,4 +102,20 @@ public class PaperWorldConfig {
|
||||||
|
private void nerfedMobsShouldJump() {
|
||||||
|
nerfedMobsShouldJump = getBoolean("spawner-nerfed-mobs-should-jump", false);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public int softDespawnDistance;
|
||||||
|
+ public int hardDespawnDistance;
|
||||||
|
+ private void despawnDistances() {
|
||||||
|
+ softDespawnDistance = getInt("despawn-ranges.soft", 32); // 32^2 = 1024, Minecraft Default
|
||||||
|
+ hardDespawnDistance = getInt("despawn-ranges.hard", 128); // 128^2 = 16384, Minecraft Default
|
||||||
|
+
|
||||||
|
+ if (softDespawnDistance > hardDespawnDistance) {
|
||||||
|
+ softDespawnDistance = hardDespawnDistance;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ log("Living Entity Despawn Ranges: Soft: " + softDespawnDistance + " Hard: " + hardDespawnDistance);
|
||||||
|
+
|
||||||
|
+ softDespawnDistance = softDespawnDistance*softDespawnDistance;
|
||||||
|
+ hardDespawnDistance = hardDespawnDistance*hardDespawnDistance;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||||
|
index 151ebcffc1f2ae02fa55ab83d2ae7d8a0057f29d..4d3000067ae3d46b7ed4dda6146a21993199c6d9 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||||
|
@@ -762,16 +762,16 @@ public abstract class Mob extends LivingEntity {
|
||||||
|
int i = this.getType().getCategory().getDespawnDistance();
|
||||||
|
int j = i * i;
|
||||||
|
|
||||||
|
- if (d0 > (double) j) { // CraftBukkit - remove isTypeNotPersistent() check
|
||||||
|
+ if (d0 > (double) level.paperConfig.hardDespawnDistance) { // CraftBukkit - remove isTypeNotPersistent() check // Paper - custom despawn distances
|
||||||
|
this.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
int k = this.getType().getCategory().getNoDespawnDistance();
|
||||||
|
int l = k * k;
|
||||||
|
|
||||||
|
- if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d0 > (double) l) { // CraftBukkit - remove isTypeNotPersistent() check
|
||||||
|
+ if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d0 > level.paperConfig.softDespawnDistance) { // CraftBukkit - remove isTypeNotPersistent() check // Paper - custom despawn distances
|
||||||
|
this.remove();
|
||||||
|
- } else if (d0 < (double) l) {
|
||||||
|
+ } else if (d0 < level.paperConfig.softDespawnDistance) { // Paper - custom despawn distances
|
||||||
|
this.noActionTime = 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Thu, 3 Mar 2016 03:53:43 -0600
|
||||||
|
Subject: [PATCH] Allow for toggling of spawn chunks
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 2f0d582baf0eb2bb477944d0cb1369db6ca33956..89e76dd73811fd0f6f8c8e7e5af804d5a4bb5a75 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -118,4 +118,10 @@ public class PaperWorldConfig {
|
||||||
|
softDespawnDistance = softDespawnDistance*softDespawnDistance;
|
||||||
|
hardDespawnDistance = hardDespawnDistance*hardDespawnDistance;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean keepSpawnInMemory;
|
||||||
|
+ private void keepSpawnInMemory() {
|
||||||
|
+ keepSpawnInMemory = getBoolean("keep-spawn-loaded", true);
|
||||||
|
+ log("Keep spawn chunk loaded: " + keepSpawnInMemory);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index c153df1f4dea3dc0ae744bde01e334b3bd3b50af..832abf73bdab2488c5814ea6e57888aac1b26154 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -217,6 +217,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
});
|
||||||
|
// CraftBukkit end
|
||||||
|
timings = new co.aikar.timings.WorldTimingsHandler(this); // Paper - code below can generate new world and access timings
|
||||||
|
+ this.keepSpawnInMemory = this.paperConfig.keepSpawnInMemory; // Paper
|
||||||
|
this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
|
||||||
|
this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Byteflux <byte@byteflux.net>
|
||||||
|
Date: Tue, 1 Mar 2016 14:14:15 -0600
|
||||||
|
Subject: [PATCH] Drop falling block and tnt entities at the specified height
|
||||||
|
|
||||||
|
* Dec 2, 2020 Added tnt nerf for tnt minecarts - Machine_Maker
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 89e76dd73811fd0f6f8c8e7e5af804d5a4bb5a75..d16ae924bcbe31c964f7fb448757c748e5c4418c 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -124,4 +124,14 @@ public class PaperWorldConfig {
|
||||||
|
keepSpawnInMemory = getBoolean("keep-spawn-loaded", true);
|
||||||
|
log("Keep spawn chunk loaded: " + keepSpawnInMemory);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public int fallingBlockHeightNerf;
|
||||||
|
+ public int entityTNTHeightNerf;
|
||||||
|
+ private void heightNerfs() {
|
||||||
|
+ fallingBlockHeightNerf = getInt("falling-block-height-nerf", 0);
|
||||||
|
+ entityTNTHeightNerf = getInt("tnt-entity-height-nerf", 0);
|
||||||
|
+
|
||||||
|
+ if (fallingBlockHeightNerf != 0) log("Falling Block Height Limit set to Y: " + fallingBlockHeightNerf);
|
||||||
|
+ if (entityTNTHeightNerf != 0) log("TNT Entity Height Limit set to Y: " + entityTNTHeightNerf);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 584e83441a9fef88eb1b0a29bec8bda29d6a0c9c..706417f44c1eebc7cc5e8e7053fa0ab21f4caeba 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -1849,6 +1849,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
return this.spawnAtLocation(stack, 0.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ @Nullable public final ItemEntity dropItem(ItemStack itemstack, float offset) { return this.spawnAtLocation(itemstack, offset); } // Paper - OBFHELPER
|
||||||
|
@Nullable
|
||||||
|
public ItemEntity spawnAtLocation(ItemStack stack, float yOffset) {
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
index 8a9e2316b9f5756503dc06e27981525d2cd7d1a5..5394bc6336cb84025c1c748fb5b3d38e0648a590 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
@@ -122,6 +122,17 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
}
|
||||||
|
|
||||||
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||||
|
+
|
||||||
|
+ // Paper start - Configurable EntityFallingBlock height nerf
|
||||||
|
+ if (this.level.paperConfig.fallingBlockHeightNerf != 0 && this.getY() > this.level.paperConfig.fallingBlockHeightNerf) {
|
||||||
|
+ if (this.dropItem && this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
|
||||||
|
+ this.spawnAtLocation(block);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ this.remove();
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
if (!this.level.isClientSide) {
|
||||||
|
blockposition = this.blockPosition();
|
||||||
|
boolean flag = this.blockState.getBlock() instanceof ConcretePowderBlock;
|
||||||
|
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 ff15a372b7cad5fa88b7ef6de1f3441d93f9c67e..4c4262b8f0cb44b8cea8cb46194a6e70d4ce56f4 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
@@ -69,6 +69,12 @@ public class PrimedTnt extends Entity {
|
||||||
|
}
|
||||||
|
|
||||||
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||||
|
+ // Paper start - Configurable TNT entity height nerf
|
||||||
|
+ if (this.level.paperConfig.entityTNTHeightNerf != 0 && this.getY() > this.level.paperConfig.entityTNTHeightNerf) {
|
||||||
|
+ this.remove();
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
this.setDeltaMovement(this.getDeltaMovement().scale(0.98D));
|
||||||
|
if (this.onGround) {
|
||||||
|
this.setDeltaMovement(this.getDeltaMovement().multiply(0.7D, -0.5D, 0.7D));
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/MinecartTNT.java b/src/main/java/net/minecraft/world/entity/vehicle/MinecartTNT.java
|
||||||
|
index c2ed3ba42d29a50386c94b109fdd3b2f2f1b433b..3b5e96f2325e14a94de0fb2d6da86812cecc7395 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartTNT.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartTNT.java
|
||||||
|
@@ -47,6 +47,12 @@ public class MinecartTNT extends AbstractMinecart {
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
if (this.fuse > 0) {
|
||||||
|
+ // Paper start - Configurable TNT entity height nerf
|
||||||
|
+ if (this.level.paperConfig.entityTNTHeightNerf != 0 && this.getY() > this.level.paperConfig.entityTNTHeightNerf) {
|
||||||
|
+ this.remove();
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
--this.fuse;
|
||||||
|
this.level.addParticle(ParticleTypes.SMOKE, this.getX(), this.getY() + 0.5D, this.getZ(), 0.0D, 0.0D, 0.0D);
|
||||||
|
} else if (this.fuse == 0) {
|
|
@ -0,0 +1,117 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Tue, 1 Mar 2016 14:32:43 -0600
|
||||||
|
Subject: [PATCH] Show 'Paper' in client crashes, server lists, and Mojang
|
||||||
|
stats
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/Eula.java b/src/main/java/net/minecraft/server/Eula.java
|
||||||
|
index 6934b0fdfe11ef673a3e4ae7564d04acee169252..9f104b1bd05d9f344579f086b2b9c00af1750690 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/Eula.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/Eula.java
|
||||||
|
@@ -72,7 +72,7 @@ public class Eula {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
|
||||||
|
properties.setProperty("eula", "false");
|
||||||
|
- properties.store(outputstream, "By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).");
|
||||||
|
+ properties.store(outputstream, "By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).\nYou also agree that tacos are tasty, and the best food in the world."); // Paper - fix lag;
|
||||||
|
} catch (Throwable throwable1) {
|
||||||
|
throwable = throwable1;
|
||||||
|
throw throwable1;
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index a456b9cbf0e5eea4e888e0e3d07ed17558650371..fa29790600021809f31092a90e1a3a9b84d5e0c4 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -1340,7 +1340,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerModName() {
|
||||||
|
- return "Spigot"; // Spigot - Spigot > // CraftBukkit - cb > vanilla!
|
||||||
|
+ return "Paper"; //Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla!
|
||||||
|
}
|
||||||
|
|
||||||
|
public CrashReport fillReport(CrashReport report) {
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index f7f5457d20586e0ba72368e64ff6025f6755e61e..f81def94a1a7ab3a24b74a8bbd5f3e8ebae2c0d5 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -224,7 +224,7 @@ import org.yaml.snakeyaml.error.MarkedYAMLException;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent; // Spigot
|
||||||
|
|
||||||
|
public final class CraftServer implements Server {
|
||||||
|
- private final String serverName = "CraftBukkit";
|
||||||
|
+ private final String serverName = "Paper"; // Paper
|
||||||
|
private final String serverVersion;
|
||||||
|
private final String bukkitVersion = Versioning.getBukkitVersion();
|
||||||
|
private final Logger logger = Logger.getLogger("Minecraft");
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
index ce9f10f890a5866ab6208c7253b15b09fe323a81..e8c225fcd1a3fa5a7e1971683b1876dd6462a1e2 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
@@ -206,12 +206,25 @@ public class Main {
|
||||||
|
deadline.add(Calendar.DAY_OF_YEAR, -28);
|
||||||
|
if (buildDate.before(deadline.getTime())) {
|
||||||
|
System.err.println("*** Error, this build is outdated ***");
|
||||||
|
- System.err.println("*** Please download a new build as per instructions from https://www.spigotmc.org/go/outdated-spigot ***");
|
||||||
|
+ System.err.println("*** Please download a new build as per instructions from https://papermc.io/downloads ***"); // Paper
|
||||||
|
System.err.println("*** Server will start in 20 seconds ***");
|
||||||
|
Thread.sleep(TimeUnit.SECONDS.toMillis(20));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start - Log Java and OS versioning to help with debugging plugin issues
|
||||||
|
+ java.lang.management.RuntimeMXBean runtimeMX = java.lang.management.ManagementFactory.getRuntimeMXBean();
|
||||||
|
+ java.lang.management.OperatingSystemMXBean osMX = java.lang.management.ManagementFactory.getOperatingSystemMXBean();
|
||||||
|
+ if (runtimeMX != null && osMX != null) {
|
||||||
|
+ String javaInfo = "Java " + runtimeMX.getSpecVersion() + " (" + runtimeMX.getVmName() + " " + runtimeMX.getVmVersion() + ")";
|
||||||
|
+ String osInfo = "Host: " + osMX.getName() + " " + osMX.getVersion() + " (" + osMX.getArch() + ")";
|
||||||
|
+
|
||||||
|
+ System.out.println("System Info: " + javaInfo + " " + osInfo);
|
||||||
|
+ } else {
|
||||||
|
+ System.out.println("Unable to read system info");
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
System.out.println("Loading libraries, please wait...");
|
||||||
|
net.minecraft.server.Main.main(options);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
index 9a695b80ef57d677fbdee1bfc59f0f9125a7ebd4..21d7b483920841456707fe3f08b180c1f072b7f7 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
@@ -19,7 +19,7 @@ public class WatchdogThread extends Thread
|
||||||
|
|
||||||
|
private WatchdogThread(long timeoutTime, boolean restart)
|
||||||
|
{
|
||||||
|
- super( "Spigot Watchdog Thread" );
|
||||||
|
+ super( "Paper Watchdog Thread" );
|
||||||
|
this.timeoutTime = timeoutTime;
|
||||||
|
this.restart = restart;
|
||||||
|
}
|
||||||
|
@@ -65,14 +65,14 @@ public class WatchdogThread extends Thread
|
||||||
|
{
|
||||||
|
Logger log = Bukkit.getServer().getLogger();
|
||||||
|
log.log( Level.SEVERE, "------------------------------" );
|
||||||
|
- log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Spigot bug." );
|
||||||
|
+ log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug." ); // Paper
|
||||||
|
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 Spigot bug, please report to https://www.spigotmc.org/" );
|
||||||
|
+ 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, "Be sure to include ALL relevant console errors and Minecraft crash reports" );
|
||||||
|
- log.log( Level.SEVERE, "Spigot version: " + Bukkit.getServer().getVersion() );
|
||||||
|
+ log.log( Level.SEVERE, "Paper version: " + Bukkit.getServer().getVersion() );
|
||||||
|
//
|
||||||
|
if ( net.minecraft.world.level.Level.lastPhysicsProblem != null )
|
||||||
|
{
|
||||||
|
@@ -82,7 +82,7 @@ public class WatchdogThread extends Thread
|
||||||
|
}
|
||||||
|
//
|
||||||
|
log.log( Level.SEVERE, "------------------------------" );
|
||||||
|
- log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Spigot!):" );
|
||||||
|
+ log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
||||||
|
dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||||
|
log.log( Level.SEVERE, "------------------------------" );
|
||||||
|
//
|
|
@ -0,0 +1,150 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach@zachbr.io>
|
||||||
|
Date: Mon, 27 May 2019 03:40:05 -0500
|
||||||
|
Subject: [PATCH] Implement Paper VersionChecker
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..1a1b50e475b9ede544b2f6d0d36632b24b68898c
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
|
||||||
|
@@ -0,0 +1,122 @@
|
||||||
|
+package com.destroystokyo.paper;
|
||||||
|
+
|
||||||
|
+import com.destroystokyo.paper.util.VersionFetcher;
|
||||||
|
+import com.google.common.base.Charsets;
|
||||||
|
+import com.google.common.io.Resources;
|
||||||
|
+import com.google.gson.*;
|
||||||
|
+import net.kyori.adventure.text.Component;
|
||||||
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
+
|
||||||
|
+import javax.annotation.Nonnull;
|
||||||
|
+import javax.annotation.Nullable;
|
||||||
|
+import java.io.*;
|
||||||
|
+import java.net.HttpURLConnection;
|
||||||
|
+import java.net.URL;
|
||||||
|
+import java.util.stream.StreamSupport;
|
||||||
|
+
|
||||||
|
+public class PaperVersionFetcher implements VersionFetcher {
|
||||||
|
+ private static final java.util.regex.Pattern VER_PATTERN = java.util.regex.Pattern.compile("^([0-9\\.]*)\\-.*R"); // R is an anchor, will always give '-R' at end
|
||||||
|
+ private static final String GITHUB_BRANCH_NAME = "master";
|
||||||
|
+ private static @Nullable String mcVer;
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public long getCacheTime() {
|
||||||
|
+ return 720000;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Nonnull
|
||||||
|
+ @Override
|
||||||
|
+ public Component getVersionMessage(@Nonnull String serverVersion) {
|
||||||
|
+ String[] parts = serverVersion.substring("git-Paper-".length()).split("[-\\s]");
|
||||||
|
+ return getUpdateStatusMessage("PaperMC/Paper", GITHUB_BRANCH_NAME, parts[0]);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static @Nullable String getMinecraftVersion() {
|
||||||
|
+ if (mcVer == null) {
|
||||||
|
+ java.util.regex.Matcher matcher = VER_PATTERN.matcher(org.bukkit.Bukkit.getBukkitVersion());
|
||||||
|
+ if (matcher.find()) {
|
||||||
|
+ String result = matcher.group();
|
||||||
|
+ mcVer = result.substring(0, result.length() - 2); // strip 'R' anchor and trailing '-'
|
||||||
|
+ } else {
|
||||||
|
+ org.bukkit.Bukkit.getLogger().warning("Unable to match version to pattern! Report to PaperMC!");
|
||||||
|
+ org.bukkit.Bukkit.getLogger().warning("Pattern: " + VER_PATTERN.toString());
|
||||||
|
+ org.bukkit.Bukkit.getLogger().warning("Version: " + org.bukkit.Bukkit.getBukkitVersion());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return mcVer;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static Component getUpdateStatusMessage(@Nonnull String repo, @Nonnull String branch, @Nonnull String versionInfo) {
|
||||||
|
+ int distance;
|
||||||
|
+ try {
|
||||||
|
+ int jenkinsBuild = Integer.parseInt(versionInfo);
|
||||||
|
+ distance = fetchDistanceFromSiteApi(jenkinsBuild, getMinecraftVersion());
|
||||||
|
+ } catch (NumberFormatException ignored) {
|
||||||
|
+ versionInfo = versionInfo.replace("\"", "");
|
||||||
|
+ distance = fetchDistanceFromGitHub(repo, branch, versionInfo);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ switch (distance) {
|
||||||
|
+ case -1:
|
||||||
|
+ return Component.text("Error obtaining version information", NamedTextColor.YELLOW);
|
||||||
|
+ case 0:
|
||||||
|
+ return Component.text("You are running the latest version", NamedTextColor.GREEN);
|
||||||
|
+ case -2:
|
||||||
|
+ return Component.text("Unknown version", NamedTextColor.YELLOW);
|
||||||
|
+ default:
|
||||||
|
+ return Component.text("You are " + distance + " version(s) behind", NamedTextColor.YELLOW);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static int fetchDistanceFromSiteApi(int jenkinsBuild, @Nullable String siteApiVersion) {
|
||||||
|
+ if (siteApiVersion == null) { return -1; }
|
||||||
|
+ try {
|
||||||
|
+ try (BufferedReader reader = Resources.asCharSource(
|
||||||
|
+ new URL("https://papermc.io/api/v2/projects/paper/versions/" + siteApiVersion),
|
||||||
|
+ Charsets.UTF_8
|
||||||
|
+ ).openBufferedStream()) {
|
||||||
|
+ JsonObject json = new Gson().fromJson(reader, JsonObject.class);
|
||||||
|
+ JsonArray builds = json.getAsJsonArray("builds");
|
||||||
|
+ int latest = StreamSupport.stream(builds.spliterator(), false)
|
||||||
|
+ .mapToInt(e -> e.getAsInt())
|
||||||
|
+ .max()
|
||||||
|
+ .getAsInt();
|
||||||
|
+ return latest - jenkinsBuild;
|
||||||
|
+ } catch (JsonSyntaxException ex) {
|
||||||
|
+ ex.printStackTrace();
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ } catch (IOException e) {
|
||||||
|
+ e.printStackTrace();
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Contributed by Techcable <Techcable@outlook.com> in GH-65
|
||||||
|
+ private static int fetchDistanceFromGitHub(@Nonnull String repo, @Nonnull String branch, @Nonnull String hash) {
|
||||||
|
+ try {
|
||||||
|
+ HttpURLConnection connection = (HttpURLConnection) new URL("https://api.github.com/repos/" + repo + "/compare/" + branch + "..." + hash).openConnection();
|
||||||
|
+ connection.connect();
|
||||||
|
+ if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) return -2; // Unknown commit
|
||||||
|
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8))) {
|
||||||
|
+ JsonObject obj = new Gson().fromJson(reader, JsonObject.class);
|
||||||
|
+ String status = obj.get("status").getAsString();
|
||||||
|
+ switch (status) {
|
||||||
|
+ case "identical":
|
||||||
|
+ return 0;
|
||||||
|
+ case "behind":
|
||||||
|
+ return obj.get("behind_by").getAsInt();
|
||||||
|
+ default:
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ } catch (JsonSyntaxException | NumberFormatException e) {
|
||||||
|
+ e.printStackTrace();
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ } catch (IOException e) {
|
||||||
|
+ e.printStackTrace();
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||||
|
index 2d4faef5a2b9c4fe8b65ff4f1346b8375e0e02c8..21052d0e88351b075733331d71e07b086354b820 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||||
|
@@ -368,6 +368,11 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||||
|
public String getTimingsServerName() {
|
||||||
|
return com.destroystokyo.paper.PaperConfig.timingsServerName;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() {
|
||||||
|
+ return new com.destroystokyo.paper.PaperVersionFetcher();
|
||||||
|
+ }
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
/**
|
|
@ -0,0 +1,215 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Kyle Wood <demonwav@gmail.com>
|
||||||
|
Date: Thu, 1 Mar 2018 19:37:52 -0600
|
||||||
|
Subject: [PATCH] Add version history to version command
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
|
||||||
|
index 1a1b50e475b9ede544b2f6d0d36632b24b68898c..580bae0d414d371a07a6bfeefc41fdd989dc0083 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
|
||||||
|
@@ -5,7 +5,9 @@ import com.google.common.base.Charsets;
|
||||||
|
import com.google.common.io.Resources;
|
||||||
|
import com.google.gson.*;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
+import net.kyori.adventure.text.TextComponent;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
+import net.kyori.adventure.text.format.TextDecoration;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
@@ -28,7 +30,10 @@ public class PaperVersionFetcher implements VersionFetcher {
|
||||||
|
@Override
|
||||||
|
public Component getVersionMessage(@Nonnull String serverVersion) {
|
||||||
|
String[] parts = serverVersion.substring("git-Paper-".length()).split("[-\\s]");
|
||||||
|
- return getUpdateStatusMessage("PaperMC/Paper", GITHUB_BRANCH_NAME, parts[0]);
|
||||||
|
+ final Component updateMessage = getUpdateStatusMessage("PaperMC/Paper", GITHUB_BRANCH_NAME, parts[0]);
|
||||||
|
+ final Component history = getHistory();
|
||||||
|
+
|
||||||
|
+ return history != null ? TextComponent.ofChildren(updateMessage, Component.newline(), history) : updateMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @Nullable String getMinecraftVersion() {
|
||||||
|
@@ -119,4 +124,19 @@ public class PaperVersionFetcher implements VersionFetcher {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ @Nullable
|
||||||
|
+ private Component getHistory() {
|
||||||
|
+ final VersionHistoryManager.VersionData data = VersionHistoryManager.INSTANCE.getVersionData();
|
||||||
|
+ if (data == null) {
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final String oldVersion = data.getOldVersion();
|
||||||
|
+ if (oldVersion == null) {
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return Component.text("Previous version: " + oldVersion, NamedTextColor.GRAY, TextDecoration.ITALIC);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/VersionHistoryManager.java b/src/main/java/com/destroystokyo/paper/VersionHistoryManager.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..aac3f66cb23d260729c2a48d8710a9de2346aa22
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/VersionHistoryManager.java
|
||||||
|
@@ -0,0 +1,145 @@
|
||||||
|
+package com.destroystokyo.paper;
|
||||||
|
+
|
||||||
|
+import com.google.common.base.MoreObjects;
|
||||||
|
+import com.google.gson.Gson;
|
||||||
|
+import com.google.gson.JsonSyntaxException;
|
||||||
|
+import java.io.BufferedReader;
|
||||||
|
+import java.io.BufferedWriter;
|
||||||
|
+import java.io.IOException;
|
||||||
|
+import java.nio.charset.StandardCharsets;
|
||||||
|
+import java.nio.file.Files;
|
||||||
|
+import java.nio.file.Path;
|
||||||
|
+import java.nio.file.Paths;
|
||||||
|
+import java.nio.file.StandardOpenOption;
|
||||||
|
+import java.util.Objects;
|
||||||
|
+import java.util.logging.Level;
|
||||||
|
+import java.util.logging.Logger;
|
||||||
|
+import org.bukkit.Bukkit;
|
||||||
|
+
|
||||||
|
+import javax.annotation.Nonnull;
|
||||||
|
+import javax.annotation.Nullable;
|
||||||
|
+
|
||||||
|
+public enum VersionHistoryManager {
|
||||||
|
+ INSTANCE;
|
||||||
|
+
|
||||||
|
+ private final Gson gson = new Gson();
|
||||||
|
+
|
||||||
|
+ private final Logger logger = Bukkit.getLogger();
|
||||||
|
+
|
||||||
|
+ private VersionData currentData = null;
|
||||||
|
+
|
||||||
|
+ VersionHistoryManager() {
|
||||||
|
+ final Path path = Paths.get("version_history.json");
|
||||||
|
+
|
||||||
|
+ if (Files.exists(path)) {
|
||||||
|
+ // Basic file santiy checks
|
||||||
|
+ if (!Files.isRegularFile(path)) {
|
||||||
|
+ if (Files.isDirectory(path)) {
|
||||||
|
+ logger.severe(path + " is a directory, cannot be used for version history");
|
||||||
|
+ } else {
|
||||||
|
+ logger.severe(path + " is not a regular file, cannot be used for version history");
|
||||||
|
+ }
|
||||||
|
+ // We can't continue
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ try (final BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
|
||||||
|
+ currentData = gson.fromJson(reader, VersionData.class);
|
||||||
|
+ } catch (final IOException e) {
|
||||||
|
+ logger.log(Level.SEVERE, "Failed to read version history file '" + path + "'", e);
|
||||||
|
+ return;
|
||||||
|
+ } catch (final JsonSyntaxException e) {
|
||||||
|
+ logger.log(Level.SEVERE, "Invalid json syntax for file '" + path + "'", e);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final String version = Bukkit.getVersion();
|
||||||
|
+ if (version == null) {
|
||||||
|
+ logger.severe("Failed to retrieve current version");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!version.equals(currentData.getCurrentVersion())) {
|
||||||
|
+ // The version appears to have changed
|
||||||
|
+ currentData.setOldVersion(currentData.getCurrentVersion());
|
||||||
|
+ currentData.setCurrentVersion(version);
|
||||||
|
+ writeFile(path);
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ // File doesn't exist, start fresh
|
||||||
|
+ currentData = new VersionData();
|
||||||
|
+ // oldVersion is null
|
||||||
|
+ currentData.setCurrentVersion(Bukkit.getVersion());
|
||||||
|
+ writeFile(path);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void writeFile(@Nonnull final Path path) {
|
||||||
|
+ try (final BufferedWriter writer = Files.newBufferedWriter(
|
||||||
|
+ path,
|
||||||
|
+ StandardCharsets.UTF_8,
|
||||||
|
+ StandardOpenOption.WRITE,
|
||||||
|
+ StandardOpenOption.CREATE,
|
||||||
|
+ StandardOpenOption.TRUNCATE_EXISTING
|
||||||
|
+ )) {
|
||||||
|
+ gson.toJson(currentData, writer);
|
||||||
|
+ } catch (final IOException e) {
|
||||||
|
+ logger.log(Level.SEVERE, "Failed to write to version history file", e);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Nullable
|
||||||
|
+ public VersionData getVersionData() {
|
||||||
|
+ return currentData;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static class VersionData {
|
||||||
|
+ private String oldVersion;
|
||||||
|
+
|
||||||
|
+ private String currentVersion;
|
||||||
|
+
|
||||||
|
+ @Nullable
|
||||||
|
+ public String getOldVersion() {
|
||||||
|
+ return oldVersion;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void setOldVersion(@Nullable String oldVersion) {
|
||||||
|
+ this.oldVersion = oldVersion;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Nullable
|
||||||
|
+ public String getCurrentVersion() {
|
||||||
|
+ return currentVersion;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void setCurrentVersion(@Nullable String currentVersion) {
|
||||||
|
+ this.currentVersion = currentVersion;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public String toString() {
|
||||||
|
+ return MoreObjects.toStringHelper(this)
|
||||||
|
+ .add("oldVersion", oldVersion)
|
||||||
|
+ .add("currentVersion", currentVersion)
|
||||||
|
+ .toString();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean equals(@Nullable Object o) {
|
||||||
|
+ if (this == o) {
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+ if (o == null || getClass() != o.getClass()) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ final VersionData versionData = (VersionData) o;
|
||||||
|
+ return Objects.equals(oldVersion, versionData.oldVersion) &&
|
||||||
|
+ Objects.equals(currentVersion, versionData.currentVersion);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public int hashCode() {
|
||||||
|
+ return Objects.hash(oldVersion, currentVersion);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
index 40fe03c844c8bf6a9c4c5ae028b259f01a81eead..c7655883262f122b373ac30a33ddb4c06cd9aebe 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
@@ -193,6 +193,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
com.destroystokyo.paper.PaperConfig.registerCommands();
|
||||||
|
+ com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
this.setPvpAllowed(dedicatedserverproperties.pvp);
|
|
@ -0,0 +1,157 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jedediah Smith <jedediah@silencegreys.com>
|
||||||
|
Date: Tue, 1 Mar 2016 14:47:52 -0600
|
||||||
|
Subject: [PATCH] Player affects spawning API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 706417f44c1eebc7cc5e8e7053fa0ab21f4caeba..392f2f2d67b688d5b37f77c8e4b3036348472d77 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -1353,6 +1353,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
return Mth.sqrt(f * f + f1 * f1 + f2 * f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public double getDistanceSquared(double x, double y, double z) { return distanceToSqr(x, y, z); } // Paper - OBFHELPER
|
||||||
|
public double distanceToSqr(double x, double y, double z) {
|
||||||
|
double d3 = this.getX() - x;
|
||||||
|
double d4 = this.getY() - y;
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||||
|
index f8c13881f59ccaccf8d8e5496d2f8f49ba7d7343..a3bad391a719363077740aa810c9412df34b4ae5 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||||
|
@@ -29,6 +29,12 @@ public final class EntitySelector {
|
||||||
|
return !entity.isSpectator();
|
||||||
|
};
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ public static final Predicate<Entity> affectsSpawning = (entity) -> {
|
||||||
|
+ return !entity.isSpectator() && entity.isAlive() && (entity instanceof EntityPlayer) && ((EntityPlayer) entity).affectsSpawning;
|
||||||
|
+ };
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
public static Predicate<Entity> withinDistance(double x, double y, double z, double d3) {
|
||||||
|
double d4 = d3 * d3;
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||||
|
index 4d3000067ae3d46b7ed4dda6146a21993199c6d9..09d39b73e8a3987e58a502bd914a6451b807421b 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||||
|
@@ -755,7 +755,7 @@ public abstract class Mob extends LivingEntity {
|
||||||
|
if (this.level.getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
|
||||||
|
this.remove();
|
||||||
|
} else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) {
|
||||||
|
- Player entityhuman = this.level.getNearestPlayer(this, -1.0D);
|
||||||
|
+ Player entityhuman = this.level.findNearbyPlayer(this, -1.0D, EntitySelector.affectsSpawning); // Paper
|
||||||
|
|
||||||
|
if (entityhuman != null) {
|
||||||
|
double d0 = entityhuman.distanceToSqr((Entity) this); // CraftBukkit - decompile error
|
||||||
|
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 4ce9e37d7334ba0557c397c0ebd2cb7928c7c564..cfdbaec1de6add7a189c26eb66701dfa5f40fe4f 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
|
||||||
|
@@ -122,7 +122,7 @@ public class Silverfish extends Monster {
|
||||||
|
if (checkAnyLightMonsterSpawnRules(type, world, spawnReason, pos, random)) {
|
||||||
|
Player entityhuman = world.getNearestPlayer((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, 5.0D, true);
|
||||||
|
|
||||||
|
- return entityhuman == null;
|
||||||
|
+ return !(entityhuman != null && !entityhuman.affectsSpawning) && entityhuman == null; // Paper - Affects Spawning API
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
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 91f605c803c021c8743de87b67dcb0fb9fc807e9..3b451e75a7f49ea6b543aee9f0a51c0be3c4dfba 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||||
|
@@ -161,6 +161,9 @@ public abstract class Player extends LivingEntity {
|
||||||
|
private final ItemCooldowns cooldowns;
|
||||||
|
@Nullable
|
||||||
|
public FishingHook fishing;
|
||||||
|
+ // Paper start
|
||||||
|
+ public boolean affectsSpawning = true;
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
public boolean fauxSleeping;
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||||
|
index 98f85d59bc48451ef6381a47fe341f77b9920981..10058d3c3565382faa893b79119c5caf845bf29a 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||||
|
@@ -66,7 +66,7 @@ public abstract class BaseSpawner {
|
||||||
|
private boolean isNearPlayer() {
|
||||||
|
BlockPos blockposition = this.getPos();
|
||||||
|
|
||||||
|
- return this.getLevel().hasNearbyAlivePlayer((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, (double) this.requiredPlayerRange);
|
||||||
|
+ return this.getLevel().isAffectsSpawningPlayerNearby((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, (double) this.requiredPlayerRange); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java
|
||||||
|
index 7e7a58b9a9ececdcc37fc33b33703428eb1d5faf..66681b9f0e2531d3da25629e44180417b32b4d66 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/EntityGetter.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java
|
||||||
|
@@ -92,8 +92,9 @@ public interface EntityGetter {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- @Nullable
|
||||||
|
- default Player getNearestPlayer(double x, double y, double z, double maxDistance, @Nullable Predicate<Entity> targetPredicate) {
|
||||||
|
+ default Player findNearbyPlayer(Entity entity, double d0, @Nullable Predicate<Entity> predicate) { return this.findNearbyPlayer(entity.getX(), entity.getY(), entity.getZ(), d0, predicate); } // Paper
|
||||||
|
+ @Nullable default Player findNearbyPlayer(double d0, double d1, double d2, double d3, @Nullable Predicate<Entity> predicate) { return getNearestPlayer(d0, d1, d2, d3, predicate); } // Paper - OBFHELPER
|
||||||
|
+ @Nullable default Player getNearestPlayer(double x, double y, double z, double maxDistance, @Nullable Predicate<Entity> targetPredicate) { // Paper
|
||||||
|
double d4 = -1.0D;
|
||||||
|
Player entityhuman = null;
|
||||||
|
Iterator iterator = this.players().iterator();
|
||||||
|
@@ -126,6 +127,27 @@ public interface EntityGetter {
|
||||||
|
return this.getNearestPlayer(x, y, z, maxDistance, predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper end
|
||||||
|
+ default boolean isAffectsSpawningPlayerNearby(double d0, double d1, double d2, double d3) {
|
||||||
|
+ Iterator iterator = this.players().iterator();
|
||||||
|
+ double d4;
|
||||||
|
+ do {
|
||||||
|
+ Player entityhuman;
|
||||||
|
+ do {
|
||||||
|
+ if (!iterator.hasNext()) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ entityhuman = (Player) iterator.next();
|
||||||
|
+ } while (!EntitySelector.affectsSpawning.test(entityhuman));
|
||||||
|
+
|
||||||
|
+ d4 = entityhuman.getDistanceSquared(d0, d1, d2);
|
||||||
|
+ } while (d3 >= 0.0D && d4 >= d3 * d3);
|
||||||
|
+
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
default boolean hasNearbyAlivePlayer(double x, double y, double z, double range) {
|
||||||
|
Iterator iterator = this.players().iterator();
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
index 50d11611702e3d1f0e980fb8f2280b05b891167b..e6c39c822c6a910f63e9b4899d53b7d75e1b77cf 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
@@ -1768,8 +1768,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
@Override
|
||||||
|
public String getLocale() {
|
||||||
|
return getHandle().locale;
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Paper start
|
||||||
|
+ public void setAffectsSpawning(boolean affects) {
|
||||||
|
+ this.getHandle().affectsSpawning = affects;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ @Override
|
||||||
|
+ public boolean getAffectsSpawning() {
|
||||||
|
+ return this.getHandle().affectsSpawning;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public void updateCommands() {
|
||||||
|
if (getHandle().connection == null) return;
|
|
@ -0,0 +1,31 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Byteflux <byte@byteflux.net>
|
||||||
|
Date: Tue, 1 Mar 2016 15:08:03 -0600
|
||||||
|
Subject: [PATCH] Remove invalid mob spawner tile entities
|
||||||
|
|
||||||
|
|
||||||
|
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 f30793b81dfd9018b4879d655c7c18a9f9c25267..300749822d52f9f973e71c6ec9c8bf29d6a6938e 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
@@ -41,7 +41,9 @@ import net.minecraft.world.level.TickList;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
|
+import net.minecraft.world.level.block.SpawnerBlock;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
+import net.minecraft.world.level.block.entity.SpawnerBlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.levelgen.DebugLevelSource;
|
||||||
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
|
@@ -647,6 +649,10 @@ public class LevelChunk implements ChunkAccess {
|
||||||
|
}
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
+ // Paper start - Remove invalid mob spawner tile entities
|
||||||
|
+ } else if (blockEntity instanceof SpawnerBlockEntity && !(getBlockData(pos.getX(), pos.getY(), pos.getZ()).getBlock() instanceof SpawnerBlock)) {
|
||||||
|
+ this.blockEntities.remove(pos);
|
||||||
|
+ // Paper end
|
||||||
|
} else {
|
||||||
|
System.out.println("Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + "," + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
|
||||||
|
+ " (" + getBlockState(pos) + ") where there was no entity tile!");
|
|
@ -0,0 +1,279 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Sun, 8 Mar 2015 22:55:25 -0600
|
||||||
|
Subject: [PATCH] Optimize TileEntity Ticking
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||||
|
index 94adf0275a2e7093c152cc3b8b0a5747b3a13a86..5bcf9cefc29eb20e2cfbfb49e2b2662ec394a87e 100644
|
||||||
|
--- a/src/main/java/co/aikar/timings/TimingsExport.java
|
||||||
|
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||||
|
@@ -112,7 +112,7 @@ public class TimingsExport extends Thread {
|
||||||
|
pair("end", System.currentTimeMillis() / 1000),
|
||||||
|
pair("online-mode", Bukkit.getServer().getOnlineMode()),
|
||||||
|
pair("sampletime", (System.currentTimeMillis() - TimingsManager.timingStart) / 1000),
|
||||||
|
- pair("datapacks", toArrayMapper(MinecraftServer.getServer().getPackRepository().getSelectedIds(), pack -> {
|
||||||
|
+ pair("datapacks", toArrayMapper(MinecraftServer.getServer().getPackRepository().getSelectedPacks(), pack -> {
|
||||||
|
// Don't feel like obf helper'ing these, non fatal if its temp missed.
|
||||||
|
return ChatColor.stripColor(CraftChatMessage.fromComponent(pack.a(true)));
|
||||||
|
}))
|
||||||
|
@@ -151,8 +151,8 @@ public class TimingsExport extends Thread {
|
||||||
|
);
|
||||||
|
|
||||||
|
parent.put("worlds", toObjectMapper(MinecraftServer.getServer().getAllLevels(), world -> {
|
||||||
|
- if (world.getWorldData().getName().equals("worldeditregentempworld")) return null;
|
||||||
|
- return pair(world.getWorldData().getName(), createObject(
|
||||||
|
+ if (world.getWorld().getName().equals("worldeditregentempworld")) return null;
|
||||||
|
+ return pair(world.getWorld().getName(), createObject(
|
||||||
|
pair("gamerules", toObjectMapper(world.getWorld().getGameRules(), rule -> {
|
||||||
|
return pair(rule, world.getWorld().getGameRuleValue(rule));
|
||||||
|
})),
|
||||||
|
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 56656bf34db07bc717ace8ae9c1b60f9bfd7ff05..1bda9a158eb4372b9ab7cf3097732e64810aefc6 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/ChestBlock.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/ChestBlock.java
|
||||||
|
@@ -54,8 +54,8 @@ import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
public class ChestBlock extends AbstractChestBlock<ChestBlockEntity> implements SimpleWaterloggedBlock {
|
||||||
|
|
||||||
|
public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING;
|
||||||
|
- public static final EnumProperty<ChestType> TYPE = BlockStateProperties.CHEST_TYPE;
|
||||||
|
- public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
|
||||||
|
+ public static final EnumProperty<ChestType> TYPE = BlockStateProperties.CHEST_TYPE; public static final EnumProperty<ChestType> CHEST_TYPE_PROPERTY = TYPE; // Paper - OBFHELPER
|
||||||
|
+ public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; public static final BooleanProperty waterlogged() { return WATERLOGGED; } // Paper OBFHELPER
|
||||||
|
protected static final VoxelShape NORTH_AABB = Block.box(1.0D, 0.0D, 0.0D, 15.0D, 14.0D, 15.0D);
|
||||||
|
protected static final VoxelShape SOUTH_AABB = Block.box(1.0D, 0.0D, 1.0D, 15.0D, 14.0D, 16.0D);
|
||||||
|
protected static final VoxelShape WEST_AABB = Block.box(0.0D, 0.0D, 1.0D, 15.0D, 14.0D, 15.0D);
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java
|
||||||
|
index 7b08ee35d2d8dc3fe783d773bf6686a5197006b8..17289d28b6d0023279a573715ee3d182988dd651 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java
|
||||||
|
@@ -8,6 +8,7 @@ import net.minecraft.core.NonNullList;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.TranslatableComponent;
|
||||||
|
+import net.minecraft.server.MCUtil;
|
||||||
|
import net.minecraft.sounds.SoundEvent;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
@@ -32,7 +33,7 @@ import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||||
|
import org.bukkit.entity.HumanEntity;
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
-public class ChestBlockEntity extends RandomizableContainerBlockEntity implements TickableBlockEntity {
|
||||||
|
+public class ChestBlockEntity extends RandomizableContainerBlockEntity { // Paper - Remove ITickable
|
||||||
|
|
||||||
|
private NonNullList<ItemStack> items;
|
||||||
|
protected float openness;
|
||||||
|
@@ -110,14 +111,20 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
- @Override
|
||||||
|
public void tick() {
|
||||||
|
int i = this.worldPosition.getX();
|
||||||
|
int j = this.worldPosition.getY();
|
||||||
|
int k = this.worldPosition.getZ();
|
||||||
|
|
||||||
|
++this.tickInterval;
|
||||||
|
- this.openCount = getOpenCount(this.level, this, this.tickInterval, i, j, k, this.openCount);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void doOpenLogic() {
|
||||||
|
+ int i = this.worldPosition.getX();
|
||||||
|
+ int j = this.worldPosition.getY();
|
||||||
|
+ int k = this.worldPosition.getZ();
|
||||||
|
+
|
||||||
|
+ //this.viewingCount = a(this.world, this, this.j, i, j, k, this.viewingCount); // Paper - check is faulty given our logic is called before active container set
|
||||||
|
this.oOpenness = this.openness;
|
||||||
|
float f = 0.1F;
|
||||||
|
|
||||||
|
@@ -131,25 +138,31 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement
|
||||||
|
if (this.openCount > 0 && this.openness == 0.0F) {
|
||||||
|
this.playSound(SoundEvents.CHEST_OPEN);
|
||||||
|
}
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- if (this.openCount == 0 && this.openness > 0.0F || this.openCount > 0 && this.openness < 1.0F) {
|
||||||
|
- float f1 = this.openness;
|
||||||
|
+ public void doCloseLogic() {
|
||||||
|
+ if (this.openCount == 0 /* && this.a > 0.0F || this.viewingCount > 0 && this.a < 1.0F */) { // Paper - disable all but player count check
|
||||||
|
+ /* // Paper - disable animation stuff
|
||||||
|
+ float f1 = this.a;
|
||||||
|
|
||||||
|
- if (this.openCount > 0) {
|
||||||
|
- this.openness += 0.1F;
|
||||||
|
+ if (this.viewingCount > 0) {
|
||||||
|
+ this.a += 0.1F;
|
||||||
|
} else {
|
||||||
|
- this.openness -= 0.1F;
|
||||||
|
+ this.a -= 0.1F;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (this.openness > 1.0F) {
|
||||||
|
- this.openness = 1.0F;
|
||||||
|
+ if (this.a > 1.0F) {
|
||||||
|
+ this.a = 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
float f2 = 0.5F;
|
||||||
|
|
||||||
|
- if (this.openness < 0.5F && f1 >= 0.5F) {
|
||||||
|
+ if (this.a < 0.5F && f1 >= 0.5F) {
|
||||||
|
+ */
|
||||||
|
+ MCUtil.scheduleTask(10, () -> {
|
||||||
|
this.playSound(SoundEvents.CHEST_CLOSE);
|
||||||
|
- }
|
||||||
|
+ }, "Chest Sounds");
|
||||||
|
+ //} // Paper end
|
||||||
|
|
||||||
|
if (this.openness < 0.0F) {
|
||||||
|
this.openness = 0.0F;
|
||||||
|
@@ -188,6 +201,7 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playSound(SoundEvent soundeffect) {
|
||||||
|
+ if (!this.getBlockState().contains(ChestBlock.CHEST_TYPE_PROPERTY)) { return; } // Paper - this can be delayed, double check exists - Fixes GH-2074
|
||||||
|
ChestType blockpropertychesttype = (ChestType) this.getBlockState().getValue(ChestBlock.TYPE);
|
||||||
|
|
||||||
|
if (blockpropertychesttype != ChestType.LEFT) {
|
||||||
|
@@ -226,6 +240,7 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement
|
||||||
|
|
||||||
|
++this.openCount;
|
||||||
|
if (this.level == null) return; // CraftBukkit
|
||||||
|
+ doOpenLogic(); // Paper
|
||||||
|
|
||||||
|
// CraftBukkit start - Call redstone event
|
||||||
|
if (this.getBlockState().getBlock() == Blocks.TRAPPED_CHEST) {
|
||||||
|
@@ -248,6 +263,7 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement
|
||||||
|
--this.openCount;
|
||||||
|
|
||||||
|
// CraftBukkit start - Call redstone event
|
||||||
|
+ doCloseLogic(); // Paper
|
||||||
|
if (this.getBlockState().getBlock() == Blocks.TRAPPED_CHEST) {
|
||||||
|
int newPower = Math.max(0, Math.min(15, this.openCount));
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/EnderChestBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/EnderChestBlockEntity.java
|
||||||
|
index b26337770e13c20f57a4e74282710ce697ac0d41..8f0477d9620ef71e10855bbca07f9b6984d5d794 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/entity/EnderChestBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/EnderChestBlockEntity.java
|
||||||
|
@@ -1,11 +1,12 @@
|
||||||
|
package net.minecraft.world.level.block.entity;
|
||||||
|
|
||||||
|
+import net.minecraft.server.MCUtil;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
|
||||||
|
-public class EnderChestBlockEntity extends BlockEntity implements TickableBlockEntity {
|
||||||
|
+public class EnderChestBlockEntity extends BlockEntity { // Paper - Remove ITickable
|
||||||
|
|
||||||
|
public float openness;
|
||||||
|
public float oOpenness;
|
||||||
|
@@ -16,18 +17,28 @@ public class EnderChestBlockEntity extends BlockEntity implements TickableBlockE
|
||||||
|
super(BlockEntityType.ENDER_CHEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
- @Override
|
||||||
|
public void tick() {
|
||||||
|
if (++this.tickInterval % 20 * 4 == 0) {
|
||||||
|
this.level.blockEvent(this.worldPosition, Blocks.ENDER_CHEST, 1, this.openCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.oOpenness = this.openness;
|
||||||
|
+ /* // Paper
|
||||||
|
+ int i = this.position.getX();
|
||||||
|
+ int j = this.position.getY();
|
||||||
|
+ int k = this.position.getZ();
|
||||||
|
+ float f = 0.1F;
|
||||||
|
+ double d0;
|
||||||
|
+ // Paper start
|
||||||
|
+ */
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void doOpenLogic() {
|
||||||
|
int i = this.worldPosition.getX();
|
||||||
|
int j = this.worldPosition.getY();
|
||||||
|
int k = this.worldPosition.getZ();
|
||||||
|
- float f = 0.1F;
|
||||||
|
double d0;
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
if (this.openCount > 0 && this.openness == 0.0F) {
|
||||||
|
double d1 = (double) i + 0.5D;
|
||||||
|
@@ -35,28 +46,40 @@ public class EnderChestBlockEntity extends BlockEntity implements TickableBlockE
|
||||||
|
d0 = (double) k + 0.5D;
|
||||||
|
this.level.playSound((Player) null, d1, (double) j + 0.5D, d0, SoundEvents.ENDER_CHEST_OPEN, SoundSource.BLOCKS, 0.5F, this.level.random.nextFloat() * 0.1F + 0.9F);
|
||||||
|
}
|
||||||
|
+ // Paper start
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- if (this.openCount == 0 && this.openness > 0.0F || this.openCount > 0 && this.openness < 1.0F) {
|
||||||
|
- float f1 = this.openness;
|
||||||
|
+ private void doCloseLogic() {
|
||||||
|
+ int i = this.worldPosition.getX();
|
||||||
|
+ int j = this.worldPosition.getY();
|
||||||
|
+ int k = this.worldPosition.getZ();
|
||||||
|
+ double d0;
|
||||||
|
+
|
||||||
|
+ if (this.openCount == 0) { /* && this.a > 0.0F || this.c > 0 && this.a < 1.0F) {
|
||||||
|
+ // Paper end
|
||||||
|
+ float f1 = this.a;
|
||||||
|
|
||||||
|
- if (this.openCount > 0) {
|
||||||
|
- this.openness += 0.1F;
|
||||||
|
+ if (this.c > 0) {
|
||||||
|
+ this.a += 0.1F;
|
||||||
|
} else {
|
||||||
|
- this.openness -= 0.1F;
|
||||||
|
+ this.a -= 0.1F;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (this.openness > 1.0F) {
|
||||||
|
- this.openness = 1.0F;
|
||||||
|
+ if (this.a > 1.0F) {
|
||||||
|
+ this.a = 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
float f2 = 0.5F;
|
||||||
|
|
||||||
|
- if (this.openness < 0.5F && f1 >= 0.5F) {
|
||||||
|
+ if (this.a < 0.5F && f1 >= 0.5F) {
|
||||||
|
+ // Paper start
|
||||||
|
+ */
|
||||||
|
d0 = (double) i + 0.5D;
|
||||||
|
double d2 = (double) k + 0.5D;
|
||||||
|
|
||||||
|
+ MCUtil.scheduleTask(10, () -> {
|
||||||
|
this.level.playSound((Player) null, d0, (double) j + 0.5D, d2, SoundEvents.ENDER_CHEST_CLOSE, SoundSource.BLOCKS, 0.5F, this.level.random.nextFloat() * 0.1F + 0.9F);
|
||||||
|
- }
|
||||||
|
+ }, "Chest Sounds");
|
||||||
|
|
||||||
|
if (this.openness < 0.0F) {
|
||||||
|
this.openness = 0.0F;
|
||||||
|
@@ -84,11 +107,13 @@ public class EnderChestBlockEntity extends BlockEntity implements TickableBlockE
|
||||||
|
public void startOpen() {
|
||||||
|
++this.openCount;
|
||||||
|
this.level.blockEvent(this.worldPosition, Blocks.ENDER_CHEST, 1, this.openCount);
|
||||||
|
+ doOpenLogic(); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopOpen() {
|
||||||
|
--this.openCount;
|
||||||
|
this.level.blockEvent(this.worldPosition, Blocks.ENDER_CHEST, 1, this.openCount);
|
||||||
|
+ doCloseLogic(); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean stillValid(Player entityhuman) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java
|
||||||
|
index 60ce75c7f94c995d3753c40bc8d1ec09b4d37b1a..ac10fb9cd4701f0f6477a86bec73cb5ac6496725 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java
|
||||||
|
@@ -84,6 +84,7 @@ public abstract class StateHolder<O, S> {
|
||||||
|
return Collections.unmodifiableCollection(this.values.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public <T extends Comparable<T>> boolean contains(Property<T> iblockstate) { return this.hasProperty(iblockstate); } // Paper - OBFHELPER
|
||||||
|
public <T extends Comparable<T>> boolean hasProperty(Property<T> property) {
|
||||||
|
return this.values.containsKey(property);
|
||||||
|
}
|
|
@ -0,0 +1,208 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Tue, 1 Mar 2016 23:09:29 -0600
|
||||||
|
Subject: [PATCH] Further improve server tick loop
|
||||||
|
|
||||||
|
Improves how the catchup buffer is handled, allowing it to roll both ways
|
||||||
|
increasing the effeciency of the thread sleep so it only will sleep once.
|
||||||
|
|
||||||
|
Also increases the buffer of the catchup to ensure server stays at 20 TPS unless extreme conditions
|
||||||
|
|
||||||
|
Previous implementation did not calculate TPS correctly.
|
||||||
|
Switch to a realistic rolling average and factor in std deviation as an extra reporting variable
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index fa29790600021809f31092a90e1a3a9b84d5e0c4..526d6c0fa45bfba92a3f964f72e4965fd5c841c1 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -251,7 +251,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
public org.bukkit.command.ConsoleCommandSender console;
|
||||||
|
public org.bukkit.command.RemoteConsoleCommandSender remoteConsole;
|
||||||
|
public ConsoleReader reader;
|
||||||
|
- public static int currentTick = (int) (System.currentTimeMillis() / 50);
|
||||||
|
+ public static int currentTick = 0; // Paper - Further improve tick loop
|
||||||
|
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
|
||||||
|
public int autosavePeriod;
|
||||||
|
public Commands vanillaCommandDispatcher;
|
||||||
|
@@ -260,7 +260,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
// Spigot start
|
||||||
|
public static final int TPS = 20;
|
||||||
|
public static final int TICK_TIME = 1000000000 / TPS;
|
||||||
|
- private static final int SAMPLE_INTERVAL = 100;
|
||||||
|
+ private static final int SAMPLE_INTERVAL = 20; // Paper
|
||||||
|
public final double[] recentTps = new double[ 3 ];
|
||||||
|
public final SlackActivityAccountant slackActivityAccountant = new SlackActivityAccountant();
|
||||||
|
// Spigot end
|
||||||
|
@@ -923,6 +923,57 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
{
|
||||||
|
return ( avg * exp ) + ( tps * ( 1 - exp ) );
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Paper start - Further improve server tick loop
|
||||||
|
+ private static final long SEC_IN_NANO = 1000000000;
|
||||||
|
+ private static final long MAX_CATCHUP_BUFFER = TICK_TIME * TPS * 60L;
|
||||||
|
+ private long lastTick = 0;
|
||||||
|
+ private long catchupTime = 0;
|
||||||
|
+ public final RollingAverage tps1 = new RollingAverage(60);
|
||||||
|
+ public final RollingAverage tps5 = new RollingAverage(60 * 5);
|
||||||
|
+ public final RollingAverage tps15 = new RollingAverage(60 * 15);
|
||||||
|
+
|
||||||
|
+ public static class RollingAverage {
|
||||||
|
+ private final int size;
|
||||||
|
+ private long time;
|
||||||
|
+ private java.math.BigDecimal total;
|
||||||
|
+ private int index = 0;
|
||||||
|
+ private final java.math.BigDecimal[] samples;
|
||||||
|
+ private final long[] times;
|
||||||
|
+
|
||||||
|
+ RollingAverage(int size) {
|
||||||
|
+ this.size = size;
|
||||||
|
+ this.time = size * SEC_IN_NANO;
|
||||||
|
+ this.total = dec(TPS).multiply(dec(SEC_IN_NANO)).multiply(dec(size));
|
||||||
|
+ this.samples = new java.math.BigDecimal[size];
|
||||||
|
+ this.times = new long[size];
|
||||||
|
+ for (int i = 0; i < size; i++) {
|
||||||
|
+ this.samples[i] = dec(TPS);
|
||||||
|
+ this.times[i] = SEC_IN_NANO;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static java.math.BigDecimal dec(long t) {
|
||||||
|
+ return new java.math.BigDecimal(t);
|
||||||
|
+ }
|
||||||
|
+ public void add(java.math.BigDecimal x, long t) {
|
||||||
|
+ time -= times[index];
|
||||||
|
+ total = total.subtract(samples[index].multiply(dec(times[index])));
|
||||||
|
+ samples[index] = x;
|
||||||
|
+ times[index] = t;
|
||||||
|
+ time += t;
|
||||||
|
+ total = total.add(x.multiply(dec(t)));
|
||||||
|
+ if (++index == size) {
|
||||||
|
+ index = 0;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public double getAverage() {
|
||||||
|
+ return total.divide(dec(time), 30, java.math.RoundingMode.HALF_UP).doubleValue();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ private static final java.math.BigDecimal TPS_BASE = new java.math.BigDecimal(1E9).multiply(new java.math.BigDecimal(SAMPLE_INTERVAL));
|
||||||
|
+ // Paper End
|
||||||
|
// Spigot End
|
||||||
|
|
||||||
|
protected void runServer() {
|
||||||
|
@@ -935,30 +986,38 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
|
||||||
|
// Spigot start
|
||||||
|
Arrays.fill( recentTps, 20 );
|
||||||
|
- long curTime, tickSection = Util.getMillis(), tickCount = 1;
|
||||||
|
+ long start = System.nanoTime(), curTime, tickSection = start; // Paper - Further improve server tick loop
|
||||||
|
+ lastTick = start - TICK_TIME; // Paper
|
||||||
|
while (this.running) {
|
||||||
|
- long i = (curTime = Util.getMillis()) - this.nextTickTime;
|
||||||
|
+ long i = ((curTime = System.nanoTime()) / (1000L * 1000L)) - this.nextTickTime; // Paper
|
||||||
|
|
||||||
|
if (i > 5000L && this.nextTickTime - this.lastOverloadWarning >= 30000L) { // CraftBukkit
|
||||||
|
long j = i / 50L;
|
||||||
|
|
||||||
|
if (server.getWarnOnOverload()) // CraftBukkit
|
||||||
|
- MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", i, j);
|
||||||
|
+ MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", i, j);
|
||||||
|
this.nextTickTime += j * 50L;
|
||||||
|
this.lastOverloadWarning = this.nextTickTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ( tickCount++ % SAMPLE_INTERVAL == 0 )
|
||||||
|
+ if ( ++MinecraftServer.currentTick % SAMPLE_INTERVAL == 0 )
|
||||||
|
{
|
||||||
|
- double currentTps = 1E3 / ( curTime - tickSection ) * SAMPLE_INTERVAL;
|
||||||
|
- recentTps[0] = calcTps( recentTps[0], 0.92, currentTps ); // 1/exp(5sec/1min)
|
||||||
|
- recentTps[1] = calcTps( recentTps[1], 0.9835, currentTps ); // 1/exp(5sec/5min)
|
||||||
|
- recentTps[2] = calcTps( recentTps[2], 0.9945, currentTps ); // 1/exp(5sec/15min)
|
||||||
|
+ final long diff = curTime - tickSection;
|
||||||
|
+ java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP);
|
||||||
|
+ tps1.add(currentTps, diff);
|
||||||
|
+ tps5.add(currentTps, diff);
|
||||||
|
+ tps15.add(currentTps, diff);
|
||||||
|
+ // Backwards compat with bad plugins
|
||||||
|
+ recentTps[0] = tps1.getAverage();
|
||||||
|
+ recentTps[1] = tps5.getAverage();
|
||||||
|
+ recentTps[2] = tps15.getAverage();
|
||||||
|
+ // Paper end
|
||||||
|
tickSection = curTime;
|
||||||
|
}
|
||||||
|
// Spigot end
|
||||||
|
|
||||||
|
- MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit
|
||||||
|
+ //MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit // Paper - don't overwrite current tick time
|
||||||
|
+ lastTick = curTime;
|
||||||
|
this.nextTickTime += 50L;
|
||||||
|
SingleTickProfiler gameprofilertick = SingleTickProfiler.createTickProfiler("Server");
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index f81def94a1a7ab3a24b74a8bbd5f3e8ebae2c0d5..6fa31ca31128b1094eebd5f848c5b506dfeedeeb 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -2121,6 +2121,17 @@ public final class CraftServer implements Server {
|
||||||
|
return CraftMagicNumbers.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper - Add getTPS API - Further improve tick loop
|
||||||
|
+ @Override
|
||||||
|
+ public double[] getTPS() {
|
||||||
|
+ return new double[] {
|
||||||
|
+ net.minecraft.server.MinecraftServer.getServer().tps1.getAverage(),
|
||||||
|
+ net.minecraft.server.MinecraftServer.getServer().tps5.getAverage(),
|
||||||
|
+ net.minecraft.server.MinecraftServer.getServer().tps15.getAverage()
|
||||||
|
+ };
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
// Spigot start
|
||||||
|
private final org.bukkit.Server.Spigot spigot = new org.bukkit.Server.Spigot()
|
||||||
|
{
|
||||||
|
diff --git a/src/main/java/org/spigotmc/TicksPerSecondCommand.java b/src/main/java/org/spigotmc/TicksPerSecondCommand.java
|
||||||
|
index f5b6dec1cbe7501ce2ee9125920e810bc94670cc..e62890433ffbe0b4e48942fe6c38b599a19e58fd 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/TicksPerSecondCommand.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/TicksPerSecondCommand.java
|
||||||
|
@@ -24,22 +24,30 @@ public class TicksPerSecondCommand extends Command
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
- StringBuilder sb = new StringBuilder( ChatColor.GOLD + "TPS from last 1m, 5m, 15m: " );
|
||||||
|
- for ( double tps : MinecraftServer.getServer().recentTps )
|
||||||
|
- {
|
||||||
|
- sb.append( format( tps ) );
|
||||||
|
- sb.append( ", " );
|
||||||
|
+ // Paper start - Further improve tick handling
|
||||||
|
+ double[] tps = org.bukkit.Bukkit.getTPS();
|
||||||
|
+ String[] tpsAvg = new String[tps.length];
|
||||||
|
+
|
||||||
|
+ for ( int i = 0; i < tps.length; i++) {
|
||||||
|
+ tpsAvg[i] = format( tps[i] );
|
||||||
|
+ }
|
||||||
|
+ sender.sendMessage(ChatColor.GOLD + "TPS from last 1m, 5m, 15m: " + org.apache.commons.lang.StringUtils.join(tpsAvg, ", "));
|
||||||
|
+ if (args.length > 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) {
|
||||||
|
+ sender.sendMessage(ChatColor.GOLD + "Current Memory Usage: " + ChatColor.GREEN + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)");
|
||||||
|
+ if (!hasShownMemoryWarning) {
|
||||||
|
+ sender.sendMessage(ChatColor.RED + "Warning: " + ChatColor.GOLD + " Memory usage on modern garbage collectors is not a stable value and it is perfectly normal to see it reach max. Please do not pay it much attention.");
|
||||||
|
+ hasShownMemoryWarning = true;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
- sender.sendMessage( sb.substring( 0, sb.length() - 2 ) );
|
||||||
|
- sender.sendMessage(ChatColor.GOLD + "Current Memory Usage: " + ChatColor.GREEN + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: "
|
||||||
|
- + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)");
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
- private String format(double tps)
|
||||||
|
+ private boolean hasShownMemoryWarning; // Paper
|
||||||
|
+ private static String format(double tps) // Paper - Made static
|
||||||
|
{
|
||||||
|
return ( ( tps > 18.0 ) ? ChatColor.GREEN : ( tps > 16.0 ) ? ChatColor.YELLOW : ChatColor.RED ).toString()
|
||||||
|
- + ( ( tps > 20.0 ) ? "*" : "" ) + Math.min( Math.round( tps * 100.0 ) / 100.0, 20.0 );
|
||||||
|
+ + ( ( tps > 21.0 ) ? "*" : "" ) + Math.min( Math.round( tps * 100.0 ) / 100.0, 20.0 ); // Paper - only print * at 21, we commonly peak to 20.02 as the tick sleep is not accurate enough, stop the noise
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Tue, 1 Mar 2016 23:12:03 -0600
|
||||||
|
Subject: [PATCH] Only refresh abilities if needed
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
index e6c39c822c6a910f63e9b4899d53b7d75e1b77cf..2920ba3d8eeb62670897ea19b50aaf395ab84c5a 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
@@ -1437,12 +1437,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFlying(boolean value) {
|
||||||
|
+ boolean needsUpdate = getHandle().abilities.flying != value; // Paper - Only refresh abilities if needed
|
||||||
|
if (!getAllowFlight() && value) {
|
||||||
|
throw new IllegalArgumentException("Cannot make player fly if getAllowFlight() is false");
|
||||||
|
}
|
||||||
|
|
||||||
|
getHandle().abilities.flying = value;
|
||||||
|
- getHandle().onUpdateAbilities();
|
||||||
|
+ if (needsUpdate) getHandle().onUpdateAbilities(); // Paper - Only refresh abilities if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
140
Remapped-Spigot-Server-Patches/0026-Entity-Origin-API.patch
Normal file
140
Remapped-Spigot-Server-Patches/0026-Entity-Origin-API.patch
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Byteflux <byte@byteflux.net>
|
||||||
|
Date: Tue, 1 Mar 2016 23:45:08 -0600
|
||||||
|
Subject: [PATCH] Entity Origin API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/nbt/ListTag.java b/src/main/java/net/minecraft/nbt/ListTag.java
|
||||||
|
index 084340dc73acb3d972e0717b48da820c027a5137..7927ebac41eb1f257738238500cfe0c06031fcaf 100644
|
||||||
|
--- a/src/main/java/net/minecraft/nbt/ListTag.java
|
||||||
|
+++ b/src/main/java/net/minecraft/nbt/ListTag.java
|
||||||
|
@@ -190,6 +190,7 @@ public class ListTag extends CollectionTag<Tag> {
|
||||||
|
return new int[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public final double getDoubleAt(int i) { return this.getDouble(i); } // Paper - OBFHELPER
|
||||||
|
public double getDouble(int index) {
|
||||||
|
if (index >= 0 && index < this.list.size()) {
|
||||||
|
Tag nbtbase = (Tag) this.list.get(index);
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index 0cc86ca4ea4a2e1b5acc3c0507397eef85dec0c1..d2bb9385fbc21cdef6cef06680fac685d3da3570 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -1240,6 +1240,11 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||||
|
this.navigations.add(((Mob) entity).getNavigation());
|
||||||
|
}
|
||||||
|
entity.valid = true; // CraftBukkit
|
||||||
|
+ // Paper start - Set origin location when the entity is being added to the world
|
||||||
|
+ if (entity.origin == null) {
|
||||||
|
+ entity.origin = entity.getBukkitEntity().getLocation();
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 392f2f2d67b688d5b37f77c8e4b3036348472d77..fd5b41ceb97dc8aa975f1c0ae05b58d0b09f2cd6 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -246,6 +246,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
public org.bukkit.projectiles.ProjectileSource projectileSource; // For projectiles only
|
||||||
|
public boolean forceExplosionKnockback; // SPIGOT-949
|
||||||
|
public boolean persistentInvisibility = false;
|
||||||
|
+ public org.bukkit.Location origin; // Paper
|
||||||
|
// Spigot start
|
||||||
|
public final org.spigotmc.ActivationRange.ActivationType activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this);
|
||||||
|
public final boolean defaultActivationState;
|
||||||
|
@@ -1624,6 +1625,12 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
this.bukkitEntity.storeBukkitValues(tag);
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
+ // Paper start - Save the entity's origin location
|
||||||
|
+ if (this.origin != null) {
|
||||||
|
+ tag.setUUID("Paper.OriginWorld", origin.getWorld().getUID());
|
||||||
|
+ tag.put("Paper.Origin", this.createList(origin.getX(), origin.getY(), origin.getZ()));
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
return tag;
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT");
|
||||||
|
@@ -1746,6 +1753,17 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
+ // Paper start - Restore the entity's origin location
|
||||||
|
+ ListTag originTag = tag.getList("Paper.Origin", 6);
|
||||||
|
+ if (!originTag.isEmpty()) {
|
||||||
|
+ org.bukkit.World originWorld = level.getWorld();
|
||||||
|
+ if (tag.contains("Paper.OriginWorld")) {
|
||||||
|
+ originWorld = Bukkit.getWorld(tag.getUUID("Paper.OriginWorld"));
|
||||||
|
+ }
|
||||||
|
+ origin = new org.bukkit.Location(originWorld, originTag.getDoubleAt(0), originTag.getDoubleAt(1), originTag.getDoubleAt(2));
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
CrashReport crashreport = CrashReport.forThrowable(throwable, "Loading entity NBT");
|
||||||
|
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being loaded");
|
||||||
|
@@ -1807,6 +1825,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
|
||||||
|
protected abstract void addAdditionalSaveData(CompoundTag tag);
|
||||||
|
|
||||||
|
+ protected final ListTag createList(double... adouble) { return newDoubleList(adouble); } // Paper - OBFHELPER
|
||||||
|
protected ListTag newDoubleList(double... values) {
|
||||||
|
ListTag nbttaglist = new ListTag();
|
||||||
|
double[] adouble1 = values;
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
index 5394bc6336cb84025c1c748fb5b3d38e0648a590..1d87717cc9002ea202ee2ca614aaa8a4c7ea3cb2 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
@@ -291,6 +291,14 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
this.blockState = Blocks.SAND.defaultBlockState();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start - Try and load origin location from the old NBT tags for backwards compatibility
|
||||||
|
+ if (tag.contains("SourceLoc_x")) {
|
||||||
|
+ int srcX = tag.getInt("SourceLoc_x");
|
||||||
|
+ int srcY = tag.getInt("SourceLoc_y");
|
||||||
|
+ int srcZ = tag.getInt("SourceLoc_z");
|
||||||
|
+ origin = new org.bukkit.Location(level.getWorld(), srcX, srcY, srcZ);
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHurtsEntities(boolean hurtEntities) {
|
||||||
|
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 4c4262b8f0cb44b8cea8cb46194a6e70d4ce56f4..661848084fd986321ef782317934dac19ed4dce3 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
@@ -119,6 +119,14 @@ public class PrimedTnt extends Entity {
|
||||||
|
@Override
|
||||||
|
protected void readAdditionalSaveData(CompoundTag tag) {
|
||||||
|
this.setFuse(tag.getShort("Fuse"));
|
||||||
|
+ // Paper start - Try and load origin location from the old NBT tags for backwards compatibility
|
||||||
|
+ if (tag.contains("SourceLoc_x")) {
|
||||||
|
+ int srcX = tag.getInt("SourceLoc_x");
|
||||||
|
+ int srcY = tag.getInt("SourceLoc_y");
|
||||||
|
+ int srcZ = tag.getInt("SourceLoc_z");
|
||||||
|
+ origin = new org.bukkit.Location(level.getWorld(), srcX, srcY, srcZ);
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
index 53c231925ef1b17e48c5863570e3c54124874621..e7a59a8e0424a0839dfa73fc65f44c5b04bd3dec 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
@@ -1062,4 +1062,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||||
|
return spigot;
|
||||||
|
}
|
||||||
|
// Spigot end
|
||||||
|
+
|
||||||
|
+ // Paper start
|
||||||
|
+ @Override
|
||||||
|
+ public Location getOrigin() {
|
||||||
|
+ Location origin = getHandle().origin;
|
||||||
|
+ return origin == null ? null : origin.clone();
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Tue, 1 Mar 2016 23:52:34 -0600
|
||||||
|
Subject: [PATCH] Prevent tile entity and entity crashes
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index 832abf73bdab2488c5814ea6e57888aac1b26154..870843254d1c1fc49bc101a49cdf9d300ae3ca1b 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -737,11 +737,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
|
||||||
|
gameprofilerfiller.pop();
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
- CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking block entity");
|
||||||
|
- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block entity being ticked");
|
||||||
|
-
|
||||||
|
- tileentity.fillCrashReportCategory(crashreportsystemdetails);
|
||||||
|
- throw new ReportedException(crashreport);
|
||||||
|
+ // Paper start - Prevent tile entity and entity crashes
|
||||||
|
+ System.err.println("TileEntity threw exception at " + tileentity.level.getWorld().getName() + ":" + tileentity.worldPosition.getX() + "," + tileentity.worldPosition.getY() + "," + tileentity.worldPosition.getZ());
|
||||||
|
+ throwable.printStackTrace();
|
||||||
|
+ tilesThisCycle--;
|
||||||
|
+ this.tickableBlockEntities.remove(tileTickPosition--);
|
||||||
|
+ continue;
|
||||||
|
+ // Paper end
|
||||||
|
// Spigot start
|
||||||
|
} finally {
|
||||||
|
tileentity.tickTimer.stopTiming();
|
||||||
|
@@ -806,11 +808,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
try {
|
||||||
|
tickConsumer.accept(entity);
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
- CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking entity");
|
||||||
|
- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being ticked");
|
||||||
|
-
|
||||||
|
- entity.fillCrashReportCategory(crashreportsystemdetails);
|
||||||
|
- throw new ReportedException(crashreport);
|
||||||
|
+ // Paper start - Prevent tile entity and entity crashes
|
||||||
|
+ System.err.println("Entity threw exception at " + entity.level.getWorld().getName() + ":" + entity.getX() + "," + entity.getY() + "," + entity.getZ());
|
||||||
|
+ throwable.printStackTrace();
|
||||||
|
+ entity.removed = true;
|
||||||
|
+ return;
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 d445a1b7b7605eed66923789c5d8e2199c31c5ac..13115d1b28dfa2d87b45a50bd0feaa7f57769122 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
|
||||||
|
@@ -208,7 +208,12 @@ public abstract class BlockEntity implements net.minecraft.server.KeyedObject {
|
||||||
|
return Registry.BLOCK_ENTITY_TYPE.getKey(this.getType()) + " // " + this.getClass().getCanonicalName();
|
||||||
|
});
|
||||||
|
if (this.level != null) {
|
||||||
|
- CrashReportCategory.populateBlockDetails(crashreportsystemdetails, this.worldPosition, this.getBlockState());
|
||||||
|
+ // Paper start - Prevent TileEntity and Entity crashes
|
||||||
|
+ BlockState block = this.getBlockState();
|
||||||
|
+ if (block != null) {
|
||||||
|
+ CrashReportCategory.populateBlockDetails(crashreportsystemdetails, this.worldPosition, block);
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
CrashReportCategory.populateBlockDetails(crashreportsystemdetails, this.worldPosition, this.level.getBlockState(this.worldPosition));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Tue, 1 Mar 2016 23:58:50 -0600
|
||||||
|
Subject: [PATCH] Configurable top of nether void damage
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index d16ae924bcbe31c964f7fb448757c748e5c4418c..4bba6977a0287837b8927718c040ac61463f0469 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -134,4 +134,19 @@ public class PaperWorldConfig {
|
||||||
|
if (fallingBlockHeightNerf != 0) log("Falling Block Height Limit set to Y: " + fallingBlockHeightNerf);
|
||||||
|
if (entityTNTHeightNerf != 0) log("TNT Entity Height Limit set to Y: " + entityTNTHeightNerf);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public int netherVoidTopDamageHeight;
|
||||||
|
+ public boolean doNetherTopVoidDamage() { return netherVoidTopDamageHeight > 0; }
|
||||||
|
+ private void netherVoidTopDamageHeight() {
|
||||||
|
+ netherVoidTopDamageHeight = getInt("nether-ceiling-void-damage-height", 0);
|
||||||
|
+ log("Top of the nether void damage height: " + netherVoidTopDamageHeight);
|
||||||
|
+
|
||||||
|
+ if (PaperConfig.version < 18) {
|
||||||
|
+ boolean legacy = getBoolean("nether-ceiling-void-damage", false);
|
||||||
|
+ if (legacy) {
|
||||||
|
+ netherVoidTopDamageHeight = 128;
|
||||||
|
+ set("nether-ceiling-void-damage-height", netherVoidTopDamageHeight);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index fd5b41ceb97dc8aa975f1c0ae05b58d0b09f2cd6..f3f48c268639937874dd39eea9bd8e119eebdce7 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -499,9 +499,16 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
this.fallDistance *= 0.5F;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (this.getY() < -64.0D) {
|
||||||
|
- this.outOfWorld();
|
||||||
|
+ // Paper start - Configurable nether ceiling damage
|
||||||
|
+
|
||||||
|
+ // Extracted to own function
|
||||||
|
+ /*
|
||||||
|
+ if (this.locY() < -64.0D) {
|
||||||
|
+ this.an();
|
||||||
|
}
|
||||||
|
+ */
|
||||||
|
+ this.performVoidDamage();
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
if (!this.level.isClientSide) {
|
||||||
|
this.setSharedFlag(0, this.remainingFireTicks > 0);
|
||||||
|
@@ -594,6 +601,17 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
this.setRemainingFireTicks(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ protected void performVoidDamage() {
|
||||||
|
+ if (this.getY() < -64.0D || (this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER
|
||||||
|
+ && level.paperConfig.doNetherTopVoidDamage()
|
||||||
|
+ && this.getY() >= level.paperConfig.netherVoidTopDamageHeight)) {
|
||||||
|
+ this.doVoidDamage();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
+ protected final void doVoidDamage() { this.outOfWorld(); } // Paper - OBFHELPER
|
||||||
|
protected void outOfWorld() {
|
||||||
|
this.remove();
|
||||||
|
}
|
||||||
|
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 9503376895d90e8db0d4f7b164e2d813dd1a4a3a..7ba74b0a9319e29077b5afe3019a463ed3004813 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java
|
||||||
|
@@ -329,9 +329,15 @@ public abstract class AbstractMinecart extends Entity {
|
||||||
|
this.setDamage(this.getDamage() - 1.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (this.getY() < -64.0D) {
|
||||||
|
- this.outOfWorld();
|
||||||
|
+ // Paper start - Configurable nether ceiling damage
|
||||||
|
+ // Extracted to own function
|
||||||
|
+ /*
|
||||||
|
+ if (this.locY() < -64.0D) {
|
||||||
|
+ this.an();
|
||||||
|
}
|
||||||
|
+ */
|
||||||
|
+ this.performVoidDamage();
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
// this.doPortalTick(); // CraftBukkit - handled in postTick
|
||||||
|
if (this.level.isClientSide) {
|
|
@ -0,0 +1,19 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Wed, 2 Mar 2016 00:03:55 -0600
|
||||||
|
Subject: [PATCH] Check online mode before converting and renaming player data
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
|
||||||
|
index 067c5acd4aad346ac9ccf6d1b5aa6691b0ccd348..60fe01e824e4657d2601797d7858d5de339ab255 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
|
||||||
|
@@ -56,7 +56,7 @@ public class PlayerDataStorage {
|
||||||
|
File file = new File(this.playerDir, entityhuman.getStringUUID() + ".dat");
|
||||||
|
// Spigot Start
|
||||||
|
boolean usingWrongFile = false;
|
||||||
|
- if ( !file.exists() )
|
||||||
|
+ if ( org.bukkit.Bukkit.getOnlineMode() && !file.exists() ) // Paper - Check online mode first
|
||||||
|
{
|
||||||
|
file = new File( this.playerDir, java.util.UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + entityhuman.getScoreboardName() ).getBytes( "UTF-8" ) ).toString() + ".dat");
|
||||||
|
if ( file.exists() )
|
|
@ -0,0 +1,18 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Wed, 2 Mar 2016 00:32:25 -0600
|
||||||
|
Subject: [PATCH] Always tick falling blocks
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
|
||||||
|
index 9bb35ec64e1538aabec9ff7831706c4717239449..0a9bd85e0308e962df3b24a74bd5aac919744d6d 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/ActivationRange.java
|
||||||
|
@@ -91,6 +91,7 @@ public class ActivationRange
|
||||||
|
|| entity instanceof AbstractHurtingProjectile
|
||||||
|
|| entity instanceof LightningBolt
|
||||||
|
|| entity instanceof PrimedTnt
|
||||||
|
+ || entity instanceof EntityFallingBlock // Paper - Always tick falling blocks
|
||||||
|
|| entity instanceof EndCrystal
|
||||||
|
|| entity instanceof FireworkRocketEntity
|
||||||
|
|| entity instanceof ThrownTrident )
|
|
@ -0,0 +1,42 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: DoctorDark <doctordark11@gmail.com>
|
||||||
|
Date: Wed, 16 Mar 2016 02:21:39 -0500
|
||||||
|
Subject: [PATCH] Configurable end credits
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 4bba6977a0287837b8927718c040ac61463f0469..e6e18f309dc09ea9416ea37dcc697ddc2b571a96 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -149,4 +149,10 @@ public class PaperWorldConfig {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean disableEndCredits;
|
||||||
|
+ private void disableEndCredits() {
|
||||||
|
+ disableEndCredits = getBoolean("game-mechanics.disable-end-credits", false);
|
||||||
|
+ log("End credits disabled: " + disableEndCredits);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
index ca647b3afbe8da5847dc8fa890ae9ca5c18e03d9..f3797bd761c2c6782cce3fca25bc9ef37e5c4978 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
@@ -188,7 +188,7 @@ public class ServerPlayer extends Player implements ContainerListener {
|
||||||
|
private long lastActionTime = Util.getMillis();
|
||||||
|
private Entity camera;
|
||||||
|
public boolean isChangingDimension;
|
||||||
|
- private boolean seenCredits;
|
||||||
|
+ private boolean seenCredits; private void setHasSeenCredits(boolean has) { this.seenCredits = has; } // Paper - OBFHELPER
|
||||||
|
private final ServerRecipeBook recipeBook = new ServerRecipeBook();
|
||||||
|
private Vec3 levitationStartPos;
|
||||||
|
private int levitationStartTime;
|
||||||
|
@@ -893,6 +893,7 @@ public class ServerPlayer extends Player implements ContainerListener {
|
||||||
|
this.unRide();
|
||||||
|
this.getLevel().removePlayerImmediately(this);
|
||||||
|
if (!this.wonGame) {
|
||||||
|
+ if (level.paperConfig.disableEndCredits) this.setHasSeenCredits(true); // Paper - Toggle to always disable end credits
|
||||||
|
this.wonGame = true;
|
||||||
|
this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, this.seenCredits ? 0.0F : 1.0F));
|
||||||
|
this.seenCredits = true;
|
|
@ -0,0 +1,19 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Iceee <andrew@opticgaming.tv>
|
||||||
|
Date: Wed, 2 Mar 2016 01:39:52 -0600
|
||||||
|
Subject: [PATCH] Fix lag from explosions processing dead entities
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
index 54c3bfead8497f64c183f5612676803d91fc557b..8d6cd2a5b16d99cb8e754ce04b2d12fee7ffb4d0 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
@@ -180,7 +180,7 @@ public class Explosion {
|
||||||
|
int i1 = Mth.floor(this.y + (double) f2 + 1.0D);
|
||||||
|
int j1 = Mth.floor(this.z - (double) f2 - 1.0D);
|
||||||
|
int k1 = Mth.floor(this.z + (double) f2 + 1.0D);
|
||||||
|
- List<Entity> list = this.level.getEntities(this.source, new AABB((double) i, (double) l, (double) j1, (double) j, (double) i1, (double) k1));
|
||||||
|
+ List<Entity> list = this.level.getEntities(this.source, new AABB((double) i, (double) l, (double) j1, (double) j, (double) i1, (double) k1), (com.google.common.base.Predicate<Entity>) entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities
|
||||||
|
Vec3 vec3d = new Vec3(this.x, this.y, this.z);
|
||||||
|
|
||||||
|
for (int l1 = 0; l1 < list.size(); ++l1) {
|
148
Remapped-Spigot-Server-Patches/0033-Optimize-explosions.patch
Normal file
148
Remapped-Spigot-Server-Patches/0033-Optimize-explosions.patch
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Byteflux <byte@byteflux.net>
|
||||||
|
Date: Wed, 2 Mar 2016 11:59:48 -0600
|
||||||
|
Subject: [PATCH] Optimize explosions
|
||||||
|
|
||||||
|
The process of determining an entity's exposure from explosions can be
|
||||||
|
expensive when there are hundreds or more entities in range.
|
||||||
|
|
||||||
|
This patch adds a per-tick cache that is used for storing and retrieving
|
||||||
|
an entity's exposure during an explosion.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index e6e18f309dc09ea9416ea37dcc697ddc2b571a96..4881b03d470646843bad1bc343eb6a6ab9072d8e 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -155,4 +155,10 @@ public class PaperWorldConfig {
|
||||||
|
disableEndCredits = getBoolean("game-mechanics.disable-end-credits", false);
|
||||||
|
log("End credits disabled: " + disableEndCredits);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean optimizeExplosions;
|
||||||
|
+ private void optimizeExplosions() {
|
||||||
|
+ optimizeExplosions = getBoolean("optimize-explosions", false);
|
||||||
|
+ log("Optimize explosions: " + optimizeExplosions);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index 526d6c0fa45bfba92a3f964f72e4965fd5c841c1..901d5497667706c049718dc4fca37a1bc489c465 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -1324,6 +1324,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
|
||||||
|
this.profiler.pop();
|
||||||
|
this.profiler.pop();
|
||||||
|
+ worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
|
||||||
|
}
|
||||||
|
|
||||||
|
this.profiler.popPush("connection");
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
index 8d6cd2a5b16d99cb8e754ce04b2d12fee7ffb4d0..db46caaa5ad5f129d313c65c5006cb24853768be 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
@@ -199,7 +199,7 @@ public class Explosion {
|
||||||
|
d8 /= d11;
|
||||||
|
d9 /= d11;
|
||||||
|
d10 /= d11;
|
||||||
|
- double d12 = (double) getSeenPercent(vec3d, entity);
|
||||||
|
+ double d12 = this.getBlockDensity(vec3d, entity); // Paper - Optimize explosions
|
||||||
|
double d13 = (1.0D - d7) * d12;
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
@@ -418,4 +418,84 @@ public class Explosion {
|
||||||
|
|
||||||
|
private BlockInteraction() {}
|
||||||
|
}
|
||||||
|
+ // Paper start - Optimize explosions
|
||||||
|
+ private float getBlockDensity(Vec3 vec3d, Entity entity) {
|
||||||
|
+ if (!this.level.paperConfig.optimizeExplosions) {
|
||||||
|
+ return getSeenPercent(vec3d, entity);
|
||||||
|
+ }
|
||||||
|
+ CacheKey key = new CacheKey(this, entity.getBoundingBox());
|
||||||
|
+ Float blockDensity = this.level.explosionDensityCache.get(key);
|
||||||
|
+ if (blockDensity == null) {
|
||||||
|
+ blockDensity = getSeenPercent(vec3d, entity);
|
||||||
|
+ this.level.explosionDensityCache.put(key, blockDensity);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return blockDensity;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ static class CacheKey {
|
||||||
|
+ private final Level world;
|
||||||
|
+ private final double posX, posY, posZ;
|
||||||
|
+ private final double minX, minY, minZ;
|
||||||
|
+ private final double maxX, maxY, maxZ;
|
||||||
|
+
|
||||||
|
+ public CacheKey(Explosion explosion, AABB aabb) {
|
||||||
|
+ this.world = explosion.level;
|
||||||
|
+ this.posX = explosion.x;
|
||||||
|
+ this.posY = explosion.y;
|
||||||
|
+ this.posZ = explosion.z;
|
||||||
|
+ this.minX = aabb.minX;
|
||||||
|
+ this.minY = aabb.minY;
|
||||||
|
+ this.minZ = aabb.minZ;
|
||||||
|
+ this.maxX = aabb.maxX;
|
||||||
|
+ this.maxY = aabb.maxY;
|
||||||
|
+ this.maxZ = aabb.maxZ;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean equals(Object o) {
|
||||||
|
+ if (this == o) return true;
|
||||||
|
+ if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
+
|
||||||
|
+ CacheKey cacheKey = (CacheKey) o;
|
||||||
|
+
|
||||||
|
+ if (Double.compare(cacheKey.posX, posX) != 0) return false;
|
||||||
|
+ if (Double.compare(cacheKey.posY, posY) != 0) return false;
|
||||||
|
+ if (Double.compare(cacheKey.posZ, posZ) != 0) return false;
|
||||||
|
+ if (Double.compare(cacheKey.minX, minX) != 0) return false;
|
||||||
|
+ if (Double.compare(cacheKey.minY, minY) != 0) return false;
|
||||||
|
+ if (Double.compare(cacheKey.minZ, minZ) != 0) return false;
|
||||||
|
+ if (Double.compare(cacheKey.maxX, maxX) != 0) return false;
|
||||||
|
+ if (Double.compare(cacheKey.maxY, maxY) != 0) return false;
|
||||||
|
+ if (Double.compare(cacheKey.maxZ, maxZ) != 0) return false;
|
||||||
|
+ return world.equals(cacheKey.world);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public int hashCode() {
|
||||||
|
+ int result;
|
||||||
|
+ long temp;
|
||||||
|
+ result = world.hashCode();
|
||||||
|
+ temp = Double.doubleToLongBits(posX);
|
||||||
|
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
+ temp = Double.doubleToLongBits(posY);
|
||||||
|
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
+ temp = Double.doubleToLongBits(posZ);
|
||||||
|
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
+ temp = Double.doubleToLongBits(minX);
|
||||||
|
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
+ temp = Double.doubleToLongBits(minY);
|
||||||
|
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
+ temp = Double.doubleToLongBits(minZ);
|
||||||
|
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
+ temp = Double.doubleToLongBits(maxX);
|
||||||
|
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
+ temp = Double.doubleToLongBits(maxY);
|
||||||
|
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
+ temp = Double.doubleToLongBits(maxZ);
|
||||||
|
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
+ return result;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index 870843254d1c1fc49bc101a49cdf9d300ae3ca1b..f71b56fa079e2c7b2123061a8e1a7cb41935bab6 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -136,6 +136,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
private org.spigotmc.TickLimiter entityLimiter;
|
||||||
|
private org.spigotmc.TickLimiter tileLimiter;
|
||||||
|
private int tileTickPosition;
|
||||||
|
+ public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
|
||||||
|
|
||||||
|
public CraftWorld getWorld() {
|
||||||
|
return this.world;
|
|
@ -0,0 +1,69 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sudzzy <originmc@outlook.com>
|
||||||
|
Date: Wed, 2 Mar 2016 14:48:03 -0600
|
||||||
|
Subject: [PATCH] Disable explosion knockback
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 4881b03d470646843bad1bc343eb6a6ab9072d8e..2222c1bb5f8625eee4d88946e4bfdfa2fe598977 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -161,4 +161,9 @@ public class PaperWorldConfig {
|
||||||
|
optimizeExplosions = getBoolean("optimize-explosions", false);
|
||||||
|
log("Optimize explosions: " + optimizeExplosions);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean disableExplosionKnockback;
|
||||||
|
+ private void disableExplosionKnockback(){
|
||||||
|
+ disableExplosionKnockback = getBoolean("disable-explosion-knockback", false);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
index e5f8cee6726ea9a90c540bb10fd8594a35bb5e40..afd114e1ce00db72534d470fed12101bb237f266 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
@@ -1280,6 +1280,7 @@ public abstract class LivingEntity extends Entity {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ boolean knockbackCancelled = level.paperConfig.disableExplosionKnockback && source.isExplosion() && this instanceof net.minecraft.world.entity.player.Player; // Paper - Disable explosion knockback
|
||||||
|
if (flag1) {
|
||||||
|
if (flag) {
|
||||||
|
this.level.broadcastEntityEvent(this, (byte) 29);
|
||||||
|
@@ -1298,6 +1299,7 @@ public abstract class LivingEntity extends Entity {
|
||||||
|
b0 = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (!knockbackCancelled) // Paper - Disable explosion knockback
|
||||||
|
this.level.broadcastEntityEvent(this, b0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1321,6 +1323,7 @@ public abstract class LivingEntity extends Entity {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (knockbackCancelled) this.level.broadcastEntityEvent(this, (byte) 2); // Paper - Disable explosion knockback
|
||||||
|
if (this.isDeadOrDying()) {
|
||||||
|
if (!this.checkTotemDeathProtection(source)) {
|
||||||
|
SoundEvent soundeffect = this.getDeathSound();
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
index db46caaa5ad5f129d313c65c5006cb24853768be..45a75f7be308678336e192828becf6cf5c9047bc 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
@@ -215,14 +215,14 @@ public class Explosion {
|
||||||
|
double d14 = d13;
|
||||||
|
|
||||||
|
if (entity instanceof LivingEntity) {
|
||||||
|
- d14 = ProtectionEnchantment.getExplosionKnockbackAfterDampener((LivingEntity) entity, d13);
|
||||||
|
+ d14 = entity instanceof Player && level.paperConfig.disableExplosionKnockback ? 0 : ProtectionEnchantment.getExplosionKnockbackAfterDampener((LivingEntity) entity, d13); // Paper - Disable explosion knockback
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.setDeltaMovement(entity.getDeltaMovement().add(d8 * d14, d9 * d14, d10 * d14));
|
||||||
|
if (entity instanceof Player) {
|
||||||
|
Player entityhuman = (Player) entity;
|
||||||
|
|
||||||
|
- if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.abilities.flying)) {
|
||||||
|
+ if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.abilities.flying) && !level.paperConfig.disableExplosionKnockback) { // Paper - Disable explosion knockback
|
||||||
|
this.hitPlayers.put(entityhuman, new Vec3(d8 * d13, d9 * d13, d10 * d13));
|
||||||
|
}
|
||||||
|
}
|
33
Remapped-Spigot-Server-Patches/0035-Disable-thunder.patch
Normal file
33
Remapped-Spigot-Server-Patches/0035-Disable-thunder.patch
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sudzzy <originmc@outlook.com>
|
||||||
|
Date: Wed, 2 Mar 2016 14:52:43 -0600
|
||||||
|
Subject: [PATCH] Disable thunder
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 2222c1bb5f8625eee4d88946e4bfdfa2fe598977..083e421f8496b5336af473b108498ed28b984774 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -166,4 +166,9 @@ public class PaperWorldConfig {
|
||||||
|
private void disableExplosionKnockback(){
|
||||||
|
disableExplosionKnockback = getBoolean("disable-explosion-knockback", false);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean disableThunder;
|
||||||
|
+ private void disableThunder() {
|
||||||
|
+ disableThunder = getBoolean("disable-thunder", false);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index d2bb9385fbc21cdef6cef06680fac685d3da3570..3fc8fb197400c63bc85f57ff484803659619f775 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -580,7 +580,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||||
|
gameprofilerfiller.push("thunder");
|
||||||
|
BlockPos blockposition;
|
||||||
|
|
||||||
|
- if (flag && this.isThundering() && this.random.nextInt(100000) == 0) {
|
||||||
|
+ if (!this.paperConfig.disableThunder && flag && this.isThundering() && this.random.nextInt(100000) == 0) { // Paper - Disable thunder
|
||||||
|
blockposition = this.findLightingTargetAround(this.getBlockRandomPos(j, 0, k, 15));
|
||||||
|
if (this.isRainingAt(blockposition)) {
|
||||||
|
DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);
|
|
@ -0,0 +1,33 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sudzzy <originmc@outlook.com>
|
||||||
|
Date: Wed, 2 Mar 2016 14:57:24 -0600
|
||||||
|
Subject: [PATCH] Disable ice and snow
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 083e421f8496b5336af473b108498ed28b984774..2f7a5a4a5a7b29750cfd777e0bc5d19a14e93fa2 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -171,4 +171,9 @@ public class PaperWorldConfig {
|
||||||
|
private void disableThunder() {
|
||||||
|
disableThunder = getBoolean("disable-thunder", false);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean disableIceAndSnow;
|
||||||
|
+ private void disableIceAndSnow(){
|
||||||
|
+ disableIceAndSnow = getBoolean("disable-ice-and-snow", false);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index 3fc8fb197400c63bc85f57ff484803659619f775..6c6098731752d61b5241710b075d4ffe3826daac 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -604,7 +604,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||||
|
}
|
||||||
|
|
||||||
|
gameprofilerfiller.popPush("iceandsnow");
|
||||||
|
- if (this.random.nextInt(16) == 0) {
|
||||||
|
+ if (!this.paperConfig.disableIceAndSnow && this.random.nextInt(16) == 0) { // Paper - Disable ice and snow
|
||||||
|
blockposition = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.getBlockRandomPos(j, 0, k, 15));
|
||||||
|
BlockPos blockposition1 = blockposition.below();
|
||||||
|
Biome biomebase = this.getBiome(blockposition);
|
|
@ -0,0 +1,65 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sudzzy <originmc@outlook.com>
|
||||||
|
Date: Wed, 2 Mar 2016 15:03:53 -0600
|
||||||
|
Subject: [PATCH] Configurable mob spawner tick rate
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 2f7a5a4a5a7b29750cfd777e0bc5d19a14e93fa2..4de86b09c6bc3c1974ce61b550ccb73d37f6f170 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -176,4 +176,9 @@ public class PaperWorldConfig {
|
||||||
|
private void disableIceAndSnow(){
|
||||||
|
disableIceAndSnow = getBoolean("disable-ice-and-snow", false);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public int mobSpawnerTickRate;
|
||||||
|
+ private void mobSpawnerTickRate() {
|
||||||
|
+ mobSpawnerTickRate = getInt("mob-spawner-tick-rate", 1);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||||
|
index 10058d3c3565382faa893b79119c5caf845bf29a..ed631d5bfba5d2543e8eed017a7c484ad3ddb453 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||||
|
@@ -41,6 +41,7 @@ public abstract class BaseSpawner {
|
||||||
|
public int maxNearbyEntities = 6;
|
||||||
|
public int requiredPlayerRange = 16;
|
||||||
|
public int spawnRange = 4;
|
||||||
|
+ private int tickDelay = 0; // Paper
|
||||||
|
|
||||||
|
public BaseSpawner() {}
|
||||||
|
|
||||||
|
@@ -70,6 +71,10 @@ public abstract class BaseSpawner {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
+ // Paper start - Configurable mob spawner tick rate
|
||||||
|
+ if (spawnDelay > 0 && --tickDelay > 0) return;
|
||||||
|
+ tickDelay = this.getLevel().paperConfig.mobSpawnerTickRate;
|
||||||
|
+ // Paper end
|
||||||
|
if (!this.isNearPlayer()) {
|
||||||
|
this.oSpin = this.spin;
|
||||||
|
} else {
|
||||||
|
@@ -84,18 +89,18 @@ public abstract class BaseSpawner {
|
||||||
|
world.addParticle(ParticleTypes.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D);
|
||||||
|
world.addParticle(ParticleTypes.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D);
|
||||||
|
if (this.spawnDelay > 0) {
|
||||||
|
- --this.spawnDelay;
|
||||||
|
+ this.spawnDelay -= tickDelay; // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
this.oSpin = this.spin;
|
||||||
|
this.spin = (this.spin + (double) (1000.0F / ((float) this.spawnDelay + 200.0F))) % 360.0D;
|
||||||
|
} else {
|
||||||
|
- if (this.spawnDelay == -1) {
|
||||||
|
+ if (this.spawnDelay < -tickDelay) { // Paper
|
||||||
|
this.delay();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.spawnDelay > 0) {
|
||||||
|
- --this.spawnDelay;
|
||||||
|
+ this.spawnDelay -= tickDelay; // Paper
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jedediah Smith <jedediah@silencegreys.com>
|
||||||
|
Date: Wed, 2 Mar 2016 23:13:07 -0600
|
||||||
|
Subject: [PATCH] Send absolute position the first time an entity is seen
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
index 59a5f82c9f57d760ba4959a040ce8cbf0f49e4aa..d1bc927c8b429f43de2cdad98f8b329ff4c8b4db 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
@@ -1301,10 +1301,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
private final Entity entity;
|
||||||
|
private final int range;
|
||||||
|
private SectionPos lastSectionPos;
|
||||||
|
- public final Set<ServerPlayer> seenBy = Sets.newHashSet();
|
||||||
|
+ // Paper start
|
||||||
|
+ // Replace trackedPlayers Set with a Map. The value is true until the player receives
|
||||||
|
+ // their first update (which is forced to have absolute coordinates), false afterward.
|
||||||
|
+ public java.util.Map<ServerPlayer, Boolean> trackedPlayerMap = new java.util.HashMap<>();
|
||||||
|
+ public Set<ServerPlayer> seenBy = trackedPlayerMap.keySet();
|
||||||
|
|
||||||
|
public TrackedEntity(Entity entity, int i, int j, boolean flag) {
|
||||||
|
- this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, seenBy); // CraftBukkit
|
||||||
|
+ this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, trackedPlayerMap); // CraftBukkit // Paper
|
||||||
|
this.entity = entity;
|
||||||
|
this.range = i;
|
||||||
|
this.lastSectionPos = SectionPos.of(entity);
|
||||||
|
@@ -1386,7 +1390,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
player.entitiesToRemove.remove(Integer.valueOf(this.entity.getId()));
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
- if (flag1 && this.seenBy.add(player)) {
|
||||||
|
+ if (flag1 && this.trackedPlayerMap.putIfAbsent(player, true) == null) { // Paper
|
||||||
|
this.serverEntity.addPairing(player);
|
||||||
|
}
|
||||||
|
} else if (this.seenBy.remove(player)) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||||
|
index 3d386627b6d3d33da76372e4a14d0c5000eb8ffc..fa6893055fa5617742bfb4b7eff60c8139395cb6 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||||
|
@@ -4,6 +4,7 @@ import com.google.common.collect.Lists;
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
+import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
@@ -51,7 +52,7 @@ public class ServerEntity {
|
||||||
|
private final Entity entity;
|
||||||
|
private final int updateInterval;
|
||||||
|
private final boolean trackDelta;
|
||||||
|
- private final Consumer<Packet<?>> broadcast;
|
||||||
|
+ private final Consumer<Packet<?>> broadcast; private Consumer<Packet<?>> getPacketConsumer() { return broadcast; } // Paper - OBFHELPER
|
||||||
|
private long xp;
|
||||||
|
private long yp;
|
||||||
|
private long zp;
|
||||||
|
@@ -66,8 +67,23 @@ public class ServerEntity {
|
||||||
|
private boolean wasOnGround;
|
||||||
|
// CraftBukkit start
|
||||||
|
private final Set<ServerPlayer> trackedPlayers;
|
||||||
|
+ // Paper start
|
||||||
|
+ private java.util.Map<ServerPlayer, Boolean> trackedPlayerMap = null;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Requested in https://github.com/PaperMC/Paper/issues/1537 to allow intercepting packets
|
||||||
|
+ */
|
||||||
|
+ public void sendPlayerPacket(ServerPlayer player, Packet packet) {
|
||||||
|
+ player.connection.send(packet);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public ServerEntity(ServerLevel worldserver, Entity entity, int i, boolean flag, Consumer<Packet<?>> consumer, java.util.Map<ServerPlayer, Boolean> trackedPlayers) {
|
||||||
|
+ this(worldserver, entity, i, flag, consumer, trackedPlayers.keySet());
|
||||||
|
+ trackedPlayerMap = trackedPlayers;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
public ServerEntity(ServerLevel worldserver, Entity entity, int i, boolean flag, Consumer<Packet<?>> consumer, Set<ServerPlayer> trackedPlayers) {
|
||||||
|
+ // Paper end
|
||||||
|
this.trackedPlayers = trackedPlayers;
|
||||||
|
// CraftBukkit end
|
||||||
|
this.ap = Vec3.ZERO;
|
||||||
|
@@ -188,7 +204,25 @@ public class ServerEntity {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet1 != null) {
|
||||||
|
- this.broadcast.accept(packet1);
|
||||||
|
+ // paper start
|
||||||
|
+ if (trackedPlayerMap == null || packet1 instanceof ClientboundTeleportEntityPacket) {
|
||||||
|
+ this.broadcast.accept((packet1));
|
||||||
|
+ } else {
|
||||||
|
+ ClientboundTeleportEntityPacket teleportPacket = null;
|
||||||
|
+
|
||||||
|
+ for (java.util.Map.Entry<ServerPlayer, Boolean> viewer : trackedPlayerMap.entrySet()) {
|
||||||
|
+ if (viewer.getValue()) {
|
||||||
|
+ viewer.setValue(false);
|
||||||
|
+ if (teleportPacket == null) {
|
||||||
|
+ teleportPacket = new ClientboundTeleportEntityPacket(this.entity);
|
||||||
|
+ }
|
||||||
|
+ sendPlayerPacket(viewer.getKey(), teleportPacket);
|
||||||
|
+ } else {
|
||||||
|
+ sendPlayerPacket(viewer.getKey(), packet1);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sendDirtyEntityData();
|
103
Remapped-Spigot-Server-Patches/0039-Add-BeaconEffectEvent.patch
Normal file
103
Remapped-Spigot-Server-Patches/0039-Add-BeaconEffectEvent.patch
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Byteflux <byte@byteflux.net>
|
||||||
|
Date: Wed, 2 Mar 2016 23:30:53 -0600
|
||||||
|
Subject: [PATCH] Add BeaconEffectEvent
|
||||||
|
|
||||||
|
|
||||||
|
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 c91f7bcfab2da6a23114a3cff63ca31dab443393..5f75c6d653a31f65fcf9c0e280d796e15d059c00 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
|
||||||
|
@@ -25,7 +25,6 @@ import net.minecraft.world.effect.MobEffect;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
import net.minecraft.world.effect.MobEffects;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
-import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
import net.minecraft.world.inventory.BeaconMenu;
|
||||||
|
import net.minecraft.world.inventory.ContainerData;
|
||||||
|
@@ -41,6 +40,11 @@ import net.minecraft.world.phys.AABB;
|
||||||
|
import org.bukkit.craftbukkit.potion.CraftPotionUtil;
|
||||||
|
import org.bukkit.potion.PotionEffect;
|
||||||
|
// CraftBukkit end
|
||||||
|
+// Paper start
|
||||||
|
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||||
|
+import org.bukkit.entity.Player;
|
||||||
|
+import com.destroystokyo.paper.event.block.BeaconEffectEvent;
|
||||||
|
+// Paper end
|
||||||
|
|
||||||
|
public class BeaconBlockEntity extends BlockEntity implements MenuProvider, TickableBlockEntity {
|
||||||
|
|
||||||
|
@@ -260,21 +264,37 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Tick
|
||||||
|
double d0 = (double) (this.levels * 10 + 10);
|
||||||
|
|
||||||
|
AABB axisalignedbb = (new AABB(this.worldPosition)).inflate(d0).expandTowards(0.0D, (double) this.level.getMaxBuildHeight(), 0.0D);
|
||||||
|
- List<Player> list = this.level.getEntitiesOfClass(Player.class, axisalignedbb);
|
||||||
|
+ List<net.minecraft.world.entity.player.Player> list = this.level.getEntitiesOfClass(net.minecraft.world.entity.player.Player.class, axisalignedbb);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyEffect(List list, MobEffect effects, int i, int b0) {
|
||||||
|
+ // Paper - BeaconEffectEvent
|
||||||
|
+ applyEffect(list, effects, i, b0, true);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void applyEffect(List list, MobEffect effects, int i, int b0, boolean isPrimary) {
|
||||||
|
+ // Paper - BeaconEffectEvent
|
||||||
|
{
|
||||||
|
Iterator iterator = list.iterator();
|
||||||
|
|
||||||
|
- Player entityhuman;
|
||||||
|
+ net.minecraft.world.entity.player.Player entityhuman;
|
||||||
|
+
|
||||||
|
+ // Paper start - BeaconEffectEvent
|
||||||
|
+ org.bukkit.block.Block block = level.getWorld().getBlockAt(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ());
|
||||||
|
+ PotionEffect effect = CraftPotionUtil.toBukkit(new MobEffectInstance(effects, i, b0, true, true));
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
- entityhuman = (Player) iterator.next();
|
||||||
|
- entityhuman.addEffect(new MobEffectInstance(effects, i, b0, true, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.BEACON);
|
||||||
|
+ entityhuman = (net.minecraft.world.entity.player.Player) iterator.next();
|
||||||
|
+
|
||||||
|
+ // Paper start - BeaconEffectEvent
|
||||||
|
+ BeaconEffectEvent event = new BeaconEffectEvent(block, effect, (Player) entityhuman.getBukkitEntity(), isPrimary);
|
||||||
|
+ if (CraftEventFactory.callEvent(event).isCancelled()) continue;
|
||||||
|
+ entityhuman.addEffect(new MobEffectInstance(CraftPotionUtil.fromBukkit(event.getEffect())), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.BEACON);
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -297,10 +317,10 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Tick
|
||||||
|
int i = getLevelCb();
|
||||||
|
List list = getHumansInRange();
|
||||||
|
|
||||||
|
- applyEffect(list, this.primaryPower, i, b0);
|
||||||
|
+ applyEffect(list, this.primaryPower, i, b0, true); // Paper - BeaconEffectEvent
|
||||||
|
|
||||||
|
if (hasSecondaryEffect()) {
|
||||||
|
- applyEffect(list, this.secondaryPower, i, 0);
|
||||||
|
+ applyEffect(list, this.secondaryPower, i, 0, false); // Paper - BeaconEffectEvent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -308,7 +328,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Tick
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
public void playSound(SoundEvent soundeffect) {
|
||||||
|
- this.level.playSound((Player) null, this.worldPosition, soundeffect, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||||
|
+ this.level.playSound((net.minecraft.world.entity.player.Player) null, this.worldPosition, soundeffect, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLevels() {
|
||||||
|
@@ -368,7 +388,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Tick
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
- public AbstractContainerMenu createMenu(int syncId, Inventory inv, Player player) {
|
||||||
|
+ public AbstractContainerMenu createMenu(int syncId, Inventory inv, net.minecraft.world.entity.player.Player player) {
|
||||||
|
return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName()) ? new BeaconMenu(syncId, inv, this.dataAccess, ContainerLevelAccess.create(this.level, this.getBlockPos())) : null;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sudzzy <originmc@outlook.com>
|
||||||
|
Date: Wed, 2 Mar 2016 23:34:44 -0600
|
||||||
|
Subject: [PATCH] Configurable container update tick rate
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 4de86b09c6bc3c1974ce61b550ccb73d37f6f170..5a4c3a8c511f22c8c3240c9c7cd83a65119c1054 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -181,4 +181,9 @@ public class PaperWorldConfig {
|
||||||
|
private void mobSpawnerTickRate() {
|
||||||
|
mobSpawnerTickRate = getInt("mob-spawner-tick-rate", 1);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public int containerUpdateTickRate;
|
||||||
|
+ private void containerUpdateTickRate() {
|
||||||
|
+ containerUpdateTickRate = getInt("container-update-tick-rate", 1);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
index f3797bd761c2c6782cce3fca25bc9ef37e5c4978..ffad931c72e52855a3f139354f5e85c460e2a80b 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
@@ -207,6 +207,7 @@ public class ServerPlayer extends Player implements ContainerListener {
|
||||||
|
public boolean ignoreSlotUpdateHack;
|
||||||
|
public int latency;
|
||||||
|
public boolean wonGame;
|
||||||
|
+ private int containerUpdateDelay; // Paper
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
public String displayName;
|
||||||
|
@@ -531,7 +532,12 @@ public class ServerPlayer extends Player implements ContainerListener {
|
||||||
|
--this.invulnerableTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
- this.containerMenu.broadcastChanges();
|
||||||
|
+ // Paper start - Configurable container update tick rate
|
||||||
|
+ if (--containerUpdateDelay <= 0) {
|
||||||
|
+ this.containerMenu.broadcastChanges();
|
||||||
|
+ containerUpdateDelay = level.paperConfig.containerUpdateTickRate;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
if (!this.level.isClientSide && !this.containerMenu.stillValid(this)) {
|
||||||
|
this.closeContainer();
|
||||||
|
this.containerMenu = this.inventoryMenu;
|
|
@ -0,0 +1,25 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Techcable <Techcable@outlook.com>
|
||||||
|
Date: Wed, 2 Mar 2016 23:42:37 -0600
|
||||||
|
Subject: [PATCH] Use UserCache for player heads
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
|
||||||
|
index 11baf6fd5f7e408a570d5a48ae6b2fc05cd7e243..313ddd6b64e395a8caab77b3da005e52006ab2d7 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
|
||||||
|
@@ -166,7 +166,13 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
|
||||||
|
if (name == null) {
|
||||||
|
setProfile(null);
|
||||||
|
} else {
|
||||||
|
- setProfile(new GameProfile(null, name));
|
||||||
|
+ // Paper start - Use Online Players Skull
|
||||||
|
+ GameProfile newProfile = null;
|
||||||
|
+ net.minecraft.server.EntityPlayer player = net.minecraft.server.MinecraftServer.getServer().getPlayerList().getPlayerByName(name);
|
||||||
|
+ if (player != null) newProfile = player.getProfile();
|
||||||
|
+ if (newProfile == null) newProfile = new GameProfile(null, name);
|
||||||
|
+ setProfile(newProfile);
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
|
@ -0,0 +1,21 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Wed, 2 Mar 2016 23:45:17 -0600
|
||||||
|
Subject: [PATCH] Disable spigot tick limiters
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index f71b56fa079e2c7b2123061a8e1a7cb41935bab6..e25666328dbf433b8358f2637d93b4128034bbaa 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -707,9 +707,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
// Spigot start
|
||||||
|
// Iterator iterator = this.tileEntityListTick.iterator();
|
||||||
|
int tilesThisCycle = 0;
|
||||||
|
- for (tileLimiter.initTick();
|
||||||
|
- tilesThisCycle < tickableBlockEntities.size() && (tilesThisCycle % 10 != 0 || tileLimiter.shouldContinue());
|
||||||
|
- tileTickPosition++, tilesThisCycle++) {
|
||||||
|
+ for (tileTickPosition = 0; tileTickPosition < tickableBlockEntities.size(); tileTickPosition++) { // Paper - Disable tick limiters
|
||||||
|
tileTickPosition = (tileTickPosition < tickableBlockEntities.size()) ? tileTickPosition : 0;
|
||||||
|
BlockEntity tileentity = (BlockEntity) this.tickableBlockEntities.get(tileTickPosition);
|
||||||
|
// Spigot start
|
|
@ -0,0 +1,48 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Steve Anton <anxuiz.nx@gmail.com>
|
||||||
|
Date: Thu, 3 Mar 2016 00:09:38 -0600
|
||||||
|
Subject: [PATCH] Add PlayerInitialSpawnEvent
|
||||||
|
|
||||||
|
For modifying a player's initial spawn location as they join the server
|
||||||
|
|
||||||
|
This is a duplicate API from spigot, so use our duplicate subclass and
|
||||||
|
improve setPosition to use raw
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||||
|
index 8cdecaf2f63c78196e0c5046fe2431b40e072c8a..a63babe123fad398b07685ec57cd88756435457c 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||||
|
@@ -209,7 +209,7 @@ public abstract class PlayerList {
|
||||||
|
|
||||||
|
// Spigot start - spawn location event
|
||||||
|
Player bukkitPlayer = player.getBukkitEntity();
|
||||||
|
- org.spigotmc.event.player.PlayerSpawnLocationEvent ev = new org.spigotmc.event.player.PlayerSpawnLocationEvent(bukkitPlayer, bukkitPlayer.getLocation());
|
||||||
|
+ org.spigotmc.event.player.PlayerSpawnLocationEvent ev = new com.destroystokyo.paper.event.player.PlayerInitialSpawnEvent(bukkitPlayer, bukkitPlayer.getLocation()); // Paper use our duplicate event
|
||||||
|
cserver.getPluginManager().callEvent(ev);
|
||||||
|
|
||||||
|
Location loc = ev.getSpawnLocation();
|
||||||
|
@@ -217,7 +217,10 @@ public abstract class PlayerList {
|
||||||
|
|
||||||
|
player.setLevel(worldserver1);
|
||||||
|
player.gameMode.setLevel((ServerLevel) player.level);
|
||||||
|
- player.absMoveTo(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
|
||||||
|
+ // Paper start - set raw so we aren't fully joined to the world (not added to chunk or world)
|
||||||
|
+ player.setPosRaw(loc.getX(), loc.getY(), loc.getZ());
|
||||||
|
+ player.setRot(loc.getYaw(), loc.getPitch());
|
||||||
|
+ // Paper end
|
||||||
|
// Spigot end
|
||||||
|
|
||||||
|
// CraftBukkit - Moved message to after join
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index f3f48c268639937874dd39eea9bd8e119eebdce7..72eb40f748c33572c2828f48ebd1ca7d5d5712c8 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -397,7 +397,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
return d1 * d1 + d2 * d2 + d3 * d3 < radius * radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
- protected void setRot(float yaw, float pitch) {
|
||||||
|
+ public void setRot(float yaw, float pitch) { // Paper - protected -> public
|
||||||
|
// CraftBukkit start - yaw was sometimes set to NaN, so we need to set it back to 0
|
||||||
|
if (Float.isNaN(yaw)) {
|
||||||
|
yaw = 0;
|
|
@ -0,0 +1,37 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Thu, 3 Mar 2016 01:13:45 -0600
|
||||||
|
Subject: [PATCH] Configurable Disabling Cat Chest Detection
|
||||||
|
|
||||||
|
Offers a gameplay feature to stop cats from blocking chests
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 5a4c3a8c511f22c8c3240c9c7cd83a65119c1054..70e074cdf2087e638af8e0f3878d0ef8eb7305cc 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -186,4 +186,9 @@ public class PaperWorldConfig {
|
||||||
|
private void containerUpdateTickRate() {
|
||||||
|
containerUpdateTickRate = getInt("container-update-tick-rate", 1);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean disableChestCatDetection;
|
||||||
|
+ private void disableChestCatDetection() {
|
||||||
|
+ disableChestCatDetection = getBoolean("game-mechanics.disable-chest-cat-detection", false);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
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 1bda9a158eb4372b9ab7cf3097732e64810aefc6..6b95cd2e2af66eef324dfcc8f7642da2f9e39d4e 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/ChestBlock.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/ChestBlock.java
|
||||||
|
@@ -312,6 +312,11 @@ public class ChestBlock extends AbstractChestBlock<ChestBlockEntity> implements
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isCatSittingOnChest(LevelAccessor world, BlockPos pos) {
|
||||||
|
+ // Paper start - Option to disable chest cat detection
|
||||||
|
+ if (((Level) world).paperConfig.disableChestCatDetection) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
List<Cat> list = world.getEntitiesOfClass(Cat.class, new AABB((double) pos.getX(), (double) (pos.getY() + 1), (double) pos.getZ(), (double) (pos.getX() + 1), (double) (pos.getY() + 2), (double) (pos.getZ() + 1)));
|
||||||
|
|
||||||
|
if (!list.isEmpty()) {
|
|
@ -0,0 +1,119 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Thu, 3 Mar 2016 01:17:12 -0600
|
||||||
|
Subject: [PATCH] Ensure commands are not ran async
|
||||||
|
|
||||||
|
Plugins calling Player.chat("/foo") or Server.dispatchCommand() could
|
||||||
|
trigger the server to execute a command while on another thread.
|
||||||
|
|
||||||
|
These commands would then process EXPECTING to be on the main thread, leaving to
|
||||||
|
very hard to trace concurrency issues.
|
||||||
|
|
||||||
|
This change will synchronize the command execution back to the main thread, causing a
|
||||||
|
big slowdown in execution but throwing an exception at same time to raise awareness
|
||||||
|
that it is happening so that plugin authors can fix their code to stop executing commands async.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
index 016e91a6ca1c8457e3e367ac0597b73e81919b68..00689dc07625a02781052c5df2e466e8abe85708 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
@@ -1852,6 +1852,29 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!async && s.startsWith("/")) {
|
||||||
|
+ // Paper Start
|
||||||
|
+ if (!org.spigotmc.AsyncCatcher.shuttingDown && !org.bukkit.Bukkit.isPrimaryThread()) {
|
||||||
|
+ final String fCommandLine = s;
|
||||||
|
+ MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Command Dispatched Async: " + fCommandLine);
|
||||||
|
+ MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable());
|
||||||
|
+ Waitable wait = new Waitable() {
|
||||||
|
+ @Override
|
||||||
|
+ protected Object evaluate() {
|
||||||
|
+ chat(fCommandLine, false);
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+ server.processQueue.add(wait);
|
||||||
|
+ try {
|
||||||
|
+ wait.get();
|
||||||
|
+ return;
|
||||||
|
+ } catch (InterruptedException e) {
|
||||||
|
+ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on!
|
||||||
|
+ } catch (Exception e) {
|
||||||
|
+ throw new RuntimeException("Exception processing chat command", e.getCause());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper End
|
||||||
|
this.handleCommand(s);
|
||||||
|
} else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) {
|
||||||
|
// Do nothing, this is coming from a plugin
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index 6fa31ca31128b1094eebd5f848c5b506dfeedeeb..783da25e189c0264ebf31e244677a6b653ff7b26 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -759,6 +759,29 @@ public final class CraftServer implements Server {
|
||||||
|
Validate.notNull(commandLine, "CommandLine cannot be null");
|
||||||
|
org.spigotmc.AsyncCatcher.catchOp("command dispatch"); // Spigot
|
||||||
|
|
||||||
|
+ // Paper Start
|
||||||
|
+ if (!org.spigotmc.AsyncCatcher.shuttingDown && !Bukkit.isPrimaryThread()) {
|
||||||
|
+ final CommandSender fSender = sender;
|
||||||
|
+ final String fCommandLine = commandLine;
|
||||||
|
+ Bukkit.getLogger().log(Level.SEVERE, "Command Dispatched Async: " + commandLine);
|
||||||
|
+ Bukkit.getLogger().log(Level.SEVERE, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable());
|
||||||
|
+ org.bukkit.craftbukkit.util.Waitable<Boolean> wait = new org.bukkit.craftbukkit.util.Waitable<Boolean>() {
|
||||||
|
+ @Override
|
||||||
|
+ protected Boolean evaluate() {
|
||||||
|
+ return dispatchCommand(fSender, fCommandLine);
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+ net.minecraft.server.MinecraftServer.getServer().processQueue.add(wait);
|
||||||
|
+ try {
|
||||||
|
+ return wait.get();
|
||||||
|
+ } catch (InterruptedException e) {
|
||||||
|
+ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on!
|
||||||
|
+ } catch (Exception e) {
|
||||||
|
+ throw new RuntimeException("Exception processing dispatch command", e.getCause());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper End
|
||||||
|
+
|
||||||
|
if (commandMap.dispatch(sender, commandLine)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||||
|
index ddef523ea8762c927f37f7d16d581e43367e8c6b..70f8d42992aa348ef7b2d03d22cdd59d7c73f0fe 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||||
|
@@ -13,6 +13,7 @@ public class ServerShutdownThread extends Thread {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
org.spigotmc.AsyncCatcher.enabled = false; // Spigot
|
||||||
|
+ org.spigotmc.AsyncCatcher.shuttingDown = true; // Paper
|
||||||
|
server.close();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java
|
||||||
|
index aeed7697254af17ffefe8e578353ad216e15f9f3..9f7d2ef932ab41cef5d3d0736d20a7c7e4a2c888 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/AsyncCatcher.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/AsyncCatcher.java
|
||||||
|
@@ -6,6 +6,7 @@ public class AsyncCatcher
|
||||||
|
{
|
||||||
|
|
||||||
|
public static boolean enabled = true;
|
||||||
|
+ public static boolean shuttingDown = false; // Paper
|
||||||
|
|
||||||
|
public static void catchOp(String reason)
|
||||||
|
{
|
||||||
|
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
|
||||||
|
index a4223094802a7e996cc57c617df92d23bc48f5b5..04ae5fec376af006ec828d1ae568338af5cfe6ce 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/RestartCommand.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/RestartCommand.java
|
||||||
|
@@ -43,6 +43,7 @@ public class RestartCommand extends Command
|
||||||
|
private static void restart(final String restartScript)
|
||||||
|
{
|
||||||
|
AsyncCatcher.enabled = false; // Disable async catcher incase it interferes with us
|
||||||
|
+ org.spigotmc.AsyncCatcher.shuttingDown = true; // Paper
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String[] split = restartScript.split( " " );
|
|
@ -0,0 +1,33 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: vemacs <d@nkmem.es>
|
||||||
|
Date: Thu, 3 Mar 2016 01:19:22 -0600
|
||||||
|
Subject: [PATCH] All chunks are slime spawn chunks toggle
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 70e074cdf2087e638af8e0f3878d0ef8eb7305cc..416a6760883cb40367535c7c5acd779742bb8af5 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -191,4 +191,9 @@ public class PaperWorldConfig {
|
||||||
|
private void disableChestCatDetection() {
|
||||||
|
disableChestCatDetection = getBoolean("game-mechanics.disable-chest-cat-detection", false);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean allChunksAreSlimeChunks;
|
||||||
|
+ private void allChunksAreSlimeChunks() {
|
||||||
|
+ allChunksAreSlimeChunks = getBoolean("all-chunks-are-slime-chunks", false);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
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 8ff8c19f0b258623b9f0a3cfd0ad5595a92f5899..fc8f26e988f1e4826dcfdcf071293bb356163e62 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/monster/Slime.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java
|
||||||
|
@@ -323,7 +323,7 @@ public class Slime extends Mob implements Enemy {
|
||||||
|
}
|
||||||
|
|
||||||
|
ChunkPos chunkcoordintpair = new ChunkPos(pos);
|
||||||
|
- boolean flag = WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getLevel().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot
|
||||||
|
+ boolean flag = world.getLevel().paperConfig.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getLevel().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper
|
||||||
|
|
||||||
|
if (random.nextInt(10) == 0 && flag && pos.getY() < 40) {
|
||||||
|
return checkMobSpawnRules(type, world, spawnReason, pos, random);
|
|
@ -0,0 +1,18 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: kashike <kashike@vq.lc>
|
||||||
|
Date: Thu, 3 Mar 2016 02:15:57 -0600
|
||||||
|
Subject: [PATCH] Expose server CommandMap
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index 783da25e189c0264ebf31e244677a6b653ff7b26..95d32f37db663a37f8fde927bdf9d3d4802ba1b4 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -1760,6 +1760,7 @@ public final class CraftServer implements Server {
|
||||||
|
return helpMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ @Override // Paper - add override
|
||||||
|
public SimpleCommandMap getCommandMap() {
|
||||||
|
return commandMap;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: kashike <kashike@vq.lc>
|
||||||
|
Date: Thu, 3 Mar 2016 02:18:39 -0600
|
||||||
|
Subject: [PATCH] Be a bit more informative in maxHealth exception
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||||
|
index d8bfb0953f0b23c64f4e27fc84a6c5f3eb0cc8b8..3afdcb3013263a7e06876821d7d889fa48404041 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||||
|
@@ -99,7 +99,10 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||||
|
public void setHealth(double health) {
|
||||||
|
health = (float) health;
|
||||||
|
if ((health < 0) || (health > getMaxHealth())) {
|
||||||
|
- throw new IllegalArgumentException("Health must be between 0 and " + getMaxHealth() + "(" + health + ")");
|
||||||
|
+ // Paper - Be more informative
|
||||||
|
+ throw new IllegalArgumentException("Health must be between 0 and " + getMaxHealth() + ", but was " + health
|
||||||
|
+ + ". (attribute base value: " + this.getHandle().getAttribute(Attributes.MAX_HEALTH).getBaseValue()
|
||||||
|
+ + (this instanceof CraftPlayer ? ", player: " + this.getName() + ')' : ')'));
|
||||||
|
}
|
||||||
|
|
||||||
|
getHandle().setHealth((float) health);
|
|
@ -0,0 +1,173 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Techcable <Techcable@outlook.com>
|
||||||
|
Date: Thu, 3 Mar 2016 02:32:10 -0600
|
||||||
|
Subject: [PATCH] Player Tab List and Title APIs
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/network/FriendlyByteBuf.java b/src/main/java/net/minecraft/network/FriendlyByteBuf.java
|
||||||
|
index 59788eaef0dae5ee01ceba1bf45e85cb07f88e53..b4542ce6a8c37ab31e6ecaeb4cbad4742cca0f9b 100644
|
||||||
|
--- a/src/main/java/net/minecraft/network/FriendlyByteBuf.java
|
||||||
|
+++ b/src/main/java/net/minecraft/network/FriendlyByteBuf.java
|
||||||
|
@@ -170,6 +170,11 @@ public class FriendlyByteBuf extends ByteBuf {
|
||||||
|
public FriendlyByteBuf writeComponent(final net.kyori.adventure.text.Component component) {
|
||||||
|
return this.writeUtf(PaperAdventure.asJsonString(component, this.adventure$locale), 262144);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ @Deprecated
|
||||||
|
+ public FriendlyByteBuf writeComponent(final net.md_5.bungee.api.chat.BaseComponent[] component) {
|
||||||
|
+ return this.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(component), 262144);
|
||||||
|
+ }
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
public FriendlyByteBuf writeComponent(Component text) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/network/chat/Component.java b/src/main/java/net/minecraft/network/chat/Component.java
|
||||||
|
index 54d186a195aca6d0a4c412ed609d8c86dcc76072..06e9246f05e130be6a63ebb0c9def10c6c9675b7 100644
|
||||||
|
--- a/src/main/java/net/minecraft/network/chat/Component.java
|
||||||
|
+++ b/src/main/java/net/minecraft/network/chat/Component.java
|
||||||
|
@@ -363,6 +363,7 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
||||||
|
return Component.Serializer.GSON.toJsonTree(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ @Nullable public static Component jsonToComponent(String json) { return fromJson(json);} // Paper - OBFHELPER
|
||||||
|
@Nullable
|
||||||
|
public static MutableComponent fromJson(String json) {
|
||||||
|
return (MutableComponent) GsonHelper.fromJson(Component.Serializer.GSON, json, MutableComponent.class, false);
|
||||||
|
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitlesPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitlesPacket.java
|
||||||
|
index 69ff8df7340e60c476803256750a48f0b43414d3..df444daeb181ff78170f7b92bd02f1f1862dfa2e 100644
|
||||||
|
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitlesPacket.java
|
||||||
|
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitlesPacket.java
|
||||||
|
@@ -47,6 +47,17 @@ public class ClientboundSetTitlesPacket implements Packet<ClientGamePacketListen
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
+ // Paper start
|
||||||
|
+ public net.md_5.bungee.api.chat.BaseComponent[] components;
|
||||||
|
+
|
||||||
|
+ public ClientboundSetTitlesPacket(Type action, net.md_5.bungee.api.chat.BaseComponent[] components, int fadeIn, int stay, int fadeOut) {
|
||||||
|
+ this.type = action;
|
||||||
|
+ this.components = components;
|
||||||
|
+ this.fadeInTime = fadeIn;
|
||||||
|
+ this.stayTime = stay;
|
||||||
|
+ this.fadeOutTime = fadeOut;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FriendlyByteBuf buf) throws IOException {
|
||||||
|
@@ -55,6 +66,8 @@ public class ClientboundSetTitlesPacket implements Packet<ClientGamePacketListen
|
||||||
|
// Paper start
|
||||||
|
if (this.adventure$text != null) {
|
||||||
|
buf.writeComponent(this.adventure$text);
|
||||||
|
+ } else if (this.components != null) {
|
||||||
|
+ buf.writeComponent(this.components);
|
||||||
|
} else
|
||||||
|
// Paper end
|
||||||
|
buf.writeComponent(this.text);
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
index 2920ba3d8eeb62670897ea19b50aaf395ab84c5a..63933bd455ad72a772d4db160e946600b84a1791 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
@@ -1,5 +1,6 @@
|
||||||
|
package org.bukkit.craftbukkit.entity;
|
||||||
|
|
||||||
|
+import com.destroystokyo.paper.Title;
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.io.BaseEncoding;
|
||||||
|
@@ -236,6 +237,96 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ @Override
|
||||||
|
+ public void setPlayerListHeaderFooter(BaseComponent[] header, BaseComponent[] footer) {
|
||||||
|
+ if (header != null) {
|
||||||
|
+ String headerJson = net.md_5.bungee.chat.ComponentSerializer.toString(header);
|
||||||
|
+ playerListHeader = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(headerJson);
|
||||||
|
+ } else {
|
||||||
|
+ playerListHeader = null;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (footer != null) {
|
||||||
|
+ String footerJson = net.md_5.bungee.chat.ComponentSerializer.toString(footer);
|
||||||
|
+ playerListFooter = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(footerJson);
|
||||||
|
+ } else {
|
||||||
|
+ playerListFooter = null;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ updatePlayerListHeaderFooter();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setPlayerListHeaderFooter(BaseComponent header, BaseComponent footer) {
|
||||||
|
+ this.setPlayerListHeaderFooter(header == null ? null : new BaseComponent[]{header},
|
||||||
|
+ footer == null ? null : new BaseComponent[]{footer});
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setTitleTimes(int fadeInTicks, int stayTicks, int fadeOutTicks) {
|
||||||
|
+ getHandle().connection.send(new ClientboundSetTitlesPacket(ClientboundSetTitlesPacket.Type.TIMES, (BaseComponent[]) null, fadeInTicks, stayTicks, fadeOutTicks));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setSubtitle(BaseComponent[] subtitle) {
|
||||||
|
+ getHandle().connection.send(new ClientboundSetTitlesPacket(ClientboundSetTitlesPacket.Type.SUBTITLE, subtitle, 0, 0, 0));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setSubtitle(BaseComponent subtitle) {
|
||||||
|
+ setSubtitle(new BaseComponent[]{subtitle});
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void showTitle(BaseComponent[] title) {
|
||||||
|
+ getHandle().connection.send(new ClientboundSetTitlesPacket(ClientboundSetTitlesPacket.Type.TITLE, title, 0, 0, 0));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void showTitle(BaseComponent title) {
|
||||||
|
+ showTitle(new BaseComponent[]{title});
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void showTitle(BaseComponent[] title, BaseComponent[] subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
|
||||||
|
+ setTitleTimes(fadeInTicks, stayTicks, fadeOutTicks);
|
||||||
|
+ setSubtitle(subtitle);
|
||||||
|
+ showTitle(title);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void showTitle(BaseComponent title, BaseComponent subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
|
||||||
|
+ setTitleTimes(fadeInTicks, stayTicks, fadeOutTicks);
|
||||||
|
+ setSubtitle(subtitle);
|
||||||
|
+ showTitle(title);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void sendTitle(Title title) {
|
||||||
|
+ Preconditions.checkNotNull(title, "Title is null");
|
||||||
|
+ setTitleTimes(title.getFadeIn(), title.getStay(), title.getFadeOut());
|
||||||
|
+ setSubtitle(title.getSubtitle() == null ? new BaseComponent[0] : title.getSubtitle());
|
||||||
|
+ showTitle(title.getTitle());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void updateTitle(Title title) {
|
||||||
|
+ Preconditions.checkNotNull(title, "Title is null");
|
||||||
|
+ setTitleTimes(title.getFadeIn(), title.getStay(), title.getFadeOut());
|
||||||
|
+ if (title.getSubtitle() != null) {
|
||||||
|
+ setSubtitle(title.getSubtitle());
|
||||||
|
+ }
|
||||||
|
+ showTitle(title.getTitle());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void hideTitle() {
|
||||||
|
+ getHandle().connection.send(new ClientboundSetTitlesPacket(ClientboundSetTitlesPacket.Type.CLEAR, (BaseComponent[]) null, 0, 0, 0));
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
if(true) return io.papermc.paper.adventure.DisplayNames.getLegacy(this); // Paper
|
|
@ -0,0 +1,19 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Joseph Hirschfeld <joe@ibj.io>
|
||||||
|
Date: Thu, 3 Mar 2016 02:33:53 -0600
|
||||||
|
Subject: [PATCH] Ensure inv drag is in bounds
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||||
|
index c377a425dc3274b8aa25f94ce8f76efda2652def..72b0cfcc5aab03e14e63440c734436e9c1432111 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||||
|
@@ -238,7 +238,7 @@ public abstract class AbstractContainerMenu {
|
||||||
|
this.resetQuickCraft();
|
||||||
|
}
|
||||||
|
} else if (this.quickcraftStatus == 1) {
|
||||||
|
- Slot slot = (Slot) this.slots.get(i);
|
||||||
|
+ Slot slot = i < this.slots.size() ? this.slots.get(i) : null; // Paper - Ensure drag in bounds
|
||||||
|
|
||||||
|
itemstack1 = playerinventory.getCarried();
|
||||||
|
if (slot != null && canItemQuickReplace(slot, itemstack1, true) && slot.isAllowed(itemstack1) && (this.quickcraftType == 2 || itemstack1.getCount() > this.quickcraftSlots.size()) && this.canDragTo(slot)) {
|
|
@ -0,0 +1,48 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Joseph Hirschfeld <joe@ibj.io>
|
||||||
|
Date: Thu, 3 Mar 2016 02:39:54 -0600
|
||||||
|
Subject: [PATCH] Change implementation of (tile)entity removal list
|
||||||
|
|
||||||
|
use sets for faster removal
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index 6c6098731752d61b5241710b075d4ffe3826daac..89472b6e8f38921db50440d0213e40ac893892f1 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -1122,7 +1122,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Spigot End
|
||||||
|
- this.blockEntitiesToUnload.addAll(chunk.getBlockEntities().values());
|
||||||
|
+ this.tileEntityListUnload.addAll(chunk.getBlockEntities().values());
|
||||||
|
List[] aentityslice = chunk.getEntitySlices(); // Spigot
|
||||||
|
int i = aentityslice.length;
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index e25666328dbf433b8358f2637d93b4128034bbaa..7b4475807cca0e92ea9ae6ea49a82a8634cc0ff5 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -89,7 +89,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
public final List<BlockEntity> blockEntityList = Lists.newArrayList();
|
||||||
|
public final List<BlockEntity> tickableBlockEntities = Lists.newArrayList();
|
||||||
|
protected final List<BlockEntity> pendingBlockEntities = Lists.newArrayList();
|
||||||
|
- protected final List<BlockEntity> blockEntitiesToUnload = Lists.newArrayList();
|
||||||
|
+ protected final java.util.Set<BlockEntity> tileEntityListUnload = com.google.common.collect.Sets.newHashSet();
|
||||||
|
public final Thread thread;
|
||||||
|
private final boolean isDebug;
|
||||||
|
private int skyDarken;
|
||||||
|
@@ -697,10 +697,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
|
||||||
|
gameprofilerfiller.push("blockEntities");
|
||||||
|
timings.tileEntityTick.startTiming(); // Spigot
|
||||||
|
- if (!this.blockEntitiesToUnload.isEmpty()) {
|
||||||
|
- this.tickableBlockEntities.removeAll(this.blockEntitiesToUnload);
|
||||||
|
- this.blockEntityList.removeAll(this.blockEntitiesToUnload);
|
||||||
|
- this.blockEntitiesToUnload.clear();
|
||||||
|
+ if (!this.tileEntityListUnload.isEmpty()) {
|
||||||
|
+ this.tickableBlockEntities.removeAll(this.tileEntityListUnload);
|
||||||
|
+ this.blockEntityList.removeAll(this.tileEntityListUnload);
|
||||||
|
+ this.tileEntityListUnload.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updatingBlockEntities = true;
|
|
@ -0,0 +1,56 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Joseph Hirschfeld <joe@ibj.io>
|
||||||
|
Date: Thu, 3 Mar 2016 02:46:17 -0600
|
||||||
|
Subject: [PATCH] Add configurable portal search radius
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 416a6760883cb40367535c7c5acd779742bb8af5..670efbe53241a0ae32d618c83da601ccc1f26e37 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -196,4 +196,13 @@ public class PaperWorldConfig {
|
||||||
|
private void allChunksAreSlimeChunks() {
|
||||||
|
allChunksAreSlimeChunks = getBoolean("all-chunks-are-slime-chunks", false);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public int portalSearchRadius;
|
||||||
|
+ public int portalCreateRadius;
|
||||||
|
+ public boolean portalSearchVanillaDimensionScaling;
|
||||||
|
+ private void portalSearchRadius() {
|
||||||
|
+ portalSearchRadius = getInt("portal-search-radius", 128);
|
||||||
|
+ portalCreateRadius = getInt("portal-create-radius", 16);
|
||||||
|
+ portalSearchVanillaDimensionScaling = getBoolean("portal-search-vanilla-dimension-scaling", true);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 72eb40f748c33572c2828f48ebd1ca7d5d5712c8..a6f2e671cc9b2ef086dfa3d127a7b33272acbd56 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -2617,7 +2617,13 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
double d4 = DimensionType.getTeleportationScale(this.level.dimensionType(), destination.dimensionType());
|
||||||
|
BlockPos blockposition = new BlockPos(Mth.clamp(this.getX() * d4, d0, d2), this.getY(), Mth.clamp(this.getZ() * d4, d1, d3));
|
||||||
|
// CraftBukkit start
|
||||||
|
- CraftPortalEvent event = callPortalEvent(this, destination, blockposition, PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, flag2 ? 16 : 128, 16);
|
||||||
|
+ // Paper start
|
||||||
|
+ int portalSearchRadius = destination.paperConfig.portalSearchRadius;
|
||||||
|
+ if (level.paperConfig.portalSearchVanillaDimensionScaling && flag2) { // == THE_NETHER
|
||||||
|
+ portalSearchRadius = (int) (portalSearchRadius / destination.dimensionType().coordinateScale());
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+ CraftPortalEvent event = callPortalEvent(this, destination, blockposition, PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, portalSearchRadius, destination.paperConfig.portalCreateRadius); // Paper start - configurable portal radius
|
||||||
|
if (event == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||||
|
index 948d031627435bfce442b1fe7d3eff4addc85bc4..21c01302635d23bc21e6bb373cbe277ea1eb6a56 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||||
|
@@ -30,7 +30,7 @@ public class PortalForcer {
|
||||||
|
|
||||||
|
public Optional<BlockUtil.FoundRectangle> findPortalAround(BlockPos blockposition, boolean flag) {
|
||||||
|
// CraftBukkit start
|
||||||
|
- return findPortalAround(blockposition, flag ? 16 : 128); // Search Radius
|
||||||
|
+ return findPortalAround(blockposition, flag ? level.paperConfig.portalCreateRadius : level.paperConfig.portalSearchRadius); // Paper - search Radius
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<BlockUtil.FoundRectangle> findPortal(BlockPos blockposition, int i) {
|
|
@ -0,0 +1,89 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Joseph Hirschfeld <joe@ibj.io>
|
||||||
|
Date: Thu, 3 Mar 2016 02:48:12 -0600
|
||||||
|
Subject: [PATCH] Add velocity warnings
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index 95d32f37db663a37f8fde927bdf9d3d4802ba1b4..35d3df7ded4904414a9a61895950b56be530d244 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -260,6 +260,7 @@ public final class CraftServer implements Server {
|
||||||
|
public boolean ignoreVanillaPermissions = false;
|
||||||
|
private final List<CraftPlayer> playerView;
|
||||||
|
public int reloadCount;
|
||||||
|
+ public static Exception excessiveVelEx; // Paper - Velocity warnings
|
||||||
|
|
||||||
|
static {
|
||||||
|
ConfigurationSerialization.registerClass(CraftOfflinePlayer.class);
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
index e7a59a8e0424a0839dfa73fc65f44c5b04bd3dec..b028946de7c8f52091635fe154c816453f1ddc93 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
@@ -424,10 +424,41 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||||
|
public void setVelocity(Vector velocity) {
|
||||||
|
Preconditions.checkArgument(velocity != null, "velocity");
|
||||||
|
velocity.checkFinite();
|
||||||
|
+ // Paper start - Warn server owners when plugins try to set super high velocities
|
||||||
|
+ if (!(this instanceof org.bukkit.entity.Projectile) && isUnsafeVelocity(velocity)) {
|
||||||
|
+ CraftServer.excessiveVelEx = new Exception("Excessive velocity set detected: tried to set velocity of entity " + entity.getScoreboardName() + " id #" + getEntityId() + " to (" + velocity.getX() + "," + velocity.getY() + "," + velocity.getZ() + ").");
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
entity.setDeltaMovement(CraftVector.toNMS(velocity));
|
||||||
|
entity.hurtMarked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ /**
|
||||||
|
+ * Checks if the given velocity is not necessarily safe in all situations.
|
||||||
|
+ * This function returning true does not mean the velocity is dangerous or to be avoided, only that it may be
|
||||||
|
+ * a detriment to performance on the server.
|
||||||
|
+ *
|
||||||
|
+ * It is not to be used as a hard rule of any sort.
|
||||||
|
+ * Paper only uses it to warn server owners in watchdog crashes.
|
||||||
|
+ *
|
||||||
|
+ * @param vel incoming velocity to check
|
||||||
|
+ * @return if the velocity has the potential to be a performance detriment
|
||||||
|
+ */
|
||||||
|
+ private static boolean isUnsafeVelocity(Vector vel) {
|
||||||
|
+ final double x = vel.getX();
|
||||||
|
+ final double y = vel.getY();
|
||||||
|
+ final double z = vel.getZ();
|
||||||
|
+
|
||||||
|
+ if (x > 4 || x < -4 || y > 4 || y < -4 || z > 4 || z < -4) {
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public double getHeight() {
|
||||||
|
return getHandle().getBbHeight();
|
||||||
|
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
index 21d7b483920841456707fe3f08b180c1f072b7f7..0ed95268364ea7f6a92a39b726a1e03bc815be07 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
@@ -80,7 +80,19 @@ public class WatchdogThread extends Thread
|
||||||
|
log.log( Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed" );
|
||||||
|
log.log( Level.SEVERE, "near " + net.minecraft.world.level.Level.lastPhysicsProblem );
|
||||||
|
}
|
||||||
|
- //
|
||||||
|
+ // Paper start - Warn in watchdog if an excessive velocity was ever set
|
||||||
|
+ if ( org.bukkit.craftbukkit.CraftServer.excessiveVelEx != null )
|
||||||
|
+ {
|
||||||
|
+ log.log( Level.SEVERE, "------------------------------" );
|
||||||
|
+ log.log( Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity" );
|
||||||
|
+ log.log( Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated" );
|
||||||
|
+ log.log( Level.SEVERE, org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getMessage());
|
||||||
|
+ for ( StackTraceElement stack : org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getStackTrace() )
|
||||||
|
+ {
|
||||||
|
+ log.log( Level.SEVERE, "\t\t" + stack );
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
log.log( Level.SEVERE, "------------------------------" );
|
||||||
|
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
||||||
|
dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
|
@ -0,0 +1,44 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sudzzy <originmc@outlook.com>
|
||||||
|
Date: Thu, 3 Mar 2016 02:50:31 -0600
|
||||||
|
Subject: [PATCH] Configurable inter-world teleportation safety
|
||||||
|
|
||||||
|
People are able to abuse the way Bukkit handles teleportation across worlds since it provides a built in teleportation
|
||||||
|
safety check.
|
||||||
|
|
||||||
|
To abuse the safety check, players are required to get into a location deemed unsafe by Bukkit e.g. be within a chest
|
||||||
|
or door block. While they are in this block, they accept a teleport request from a player within a different world. Once
|
||||||
|
the player teleports, Minecraft will recursively search upwards for a safe location, this could eventually land within a
|
||||||
|
player's skybase.
|
||||||
|
|
||||||
|
Example setup to perform the glitch: http://puu.sh/ng3PC/cf072dcbdb.png
|
||||||
|
The wanted destination was on top of the emerald block however the player ended on top of the diamond block.
|
||||||
|
This only is the case if the player is teleporting between worlds.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 670efbe53241a0ae32d618c83da601ccc1f26e37..abbbe1786eb68af02f9d39650aad730ac44aac8a 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -205,4 +205,9 @@ public class PaperWorldConfig {
|
||||||
|
portalCreateRadius = getInt("portal-create-radius", 16);
|
||||||
|
portalSearchVanillaDimensionScaling = getBoolean("portal-search-vanilla-dimension-scaling", true);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean disableTeleportationSuffocationCheck;
|
||||||
|
+ private void disableTeleportationSuffocationCheck() {
|
||||||
|
+ disableTeleportationSuffocationCheck = getBoolean("disable-teleportation-suffocation-check", false);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
index 63933bd455ad72a772d4db160e946600b84a1791..3b9d61b524441f65646edf7d403b6c5b5345b1e5 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
@@ -861,7 +861,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
if (fromWorld == toWorld) {
|
||||||
|
entity.connection.teleport(to);
|
||||||
|
} else {
|
||||||
|
- server.getHandle().moveToWorld(entity, toWorld, true, to, true);
|
||||||
|
+ server.getHandle().moveToWorld(entity, toWorld, true, to, !toWorld.paperConfig.disableTeleportationSuffocationCheck); // Paper
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,264 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Joseph Hirschfeld <joe@ibj.io>
|
||||||
|
Date: Thu, 3 Mar 2016 03:15:41 -0600
|
||||||
|
Subject: [PATCH] Add exception reporting event
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java b/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..f699ce18ca044f813e194ef2786b7ea853ea86e7
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java
|
||||||
|
@@ -0,0 +1,38 @@
|
||||||
|
+package com.destroystokyo.paper;
|
||||||
|
+
|
||||||
|
+import com.google.common.base.Preconditions;
|
||||||
|
+import org.bukkit.craftbukkit.scheduler.CraftTask;
|
||||||
|
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
|
||||||
|
+import com.destroystokyo.paper.exception.ServerSchedulerException;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * Reporting wrapper to catch exceptions not natively
|
||||||
|
+ */
|
||||||
|
+public class ServerSchedulerReportingWrapper implements Runnable {
|
||||||
|
+
|
||||||
|
+ private final CraftTask internalTask;
|
||||||
|
+
|
||||||
|
+ public ServerSchedulerReportingWrapper(CraftTask internalTask) {
|
||||||
|
+ this.internalTask = Preconditions.checkNotNull(internalTask, "internalTask");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void run() {
|
||||||
|
+ try {
|
||||||
|
+ internalTask.run();
|
||||||
|
+ } catch (RuntimeException e) {
|
||||||
|
+ internalTask.getOwner().getServer().getPluginManager().callEvent(
|
||||||
|
+ new ServerExceptionEvent(new ServerSchedulerException(e, internalTask))
|
||||||
|
+ );
|
||||||
|
+ throw e;
|
||||||
|
+ } catch (Throwable t) {
|
||||||
|
+ internalTask.getOwner().getServer().getPluginManager().callEvent(
|
||||||
|
+ new ServerExceptionEvent(new ServerSchedulerException(t, internalTask))
|
||||||
|
+ ); //Do not rethrow, since it is not permitted with Runnable#run
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public CraftTask getInternalTask() {
|
||||||
|
+ return internalTask;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
index d1bc927c8b429f43de2cdad98f8b329ff4c8b4db..0597c0c3e881dd43cf91bd3088ed30dfecfe8098 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
@@ -813,6 +813,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
return true;
|
||||||
|
} catch (Exception exception) {
|
||||||
|
ChunkMap.LOGGER.error("Failed to save chunk {},{}", chunkcoordintpair.x, chunkcoordintpair.z, exception);
|
||||||
|
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||||
|
index c167d2fd99a7a352e69e2930551678bd9c9def83..09c5fa2dbcbed05da51ef2d63e6d6112d22d7877 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||||
|
@@ -1,5 +1,6 @@
|
||||||
|
package net.minecraft.server.players;
|
||||||
|
|
||||||
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
@@ -360,6 +361,7 @@ public class OldUsersConverter {
|
||||||
|
root = NbtIo.readCompressed(new java.io.FileInputStream(file5));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
+ ServerInternalException.reportInternalException(exception); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root != null) {
|
||||||
|
@@ -373,6 +375,7 @@ public class OldUsersConverter {
|
||||||
|
NbtIo.writeCompressed(root, new java.io.FileOutputStream(file2));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
+ ServerInternalException.reportInternalException(exception); // Paper
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
|
||||||
|
index 78cea15142f9fd7988f5df397061b90625070eef..f50774f022c78813982bfe08f764b54bde779e04 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
|
||||||
|
@@ -1,5 +1,7 @@
|
||||||
|
package net.minecraft.world.entity.ai.village;
|
||||||
|
|
||||||
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
||||||
|
+
|
||||||
|
import java.util.Iterator;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
@@ -119,6 +121,7 @@ public class VillageSiege implements CustomSpawner {
|
||||||
|
entityzombie.finalizeSpawn(world, world.getCurrentDifficultyAt(entityzombie.blockPosition()), MobSpawnType.EVENT, (SpawnGroupData) null, (CompoundTag) null);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
VillageSiege.LOGGER.warn("Failed to create zombie for village siege at {}", vec3d, exception);
|
||||||
|
+ ServerInternalException.reportInternalException(exception); // Paper
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index 7b4475807cca0e92ea9ae6ea49a82a8634cc0ff5..94e268a05b4601c29b6d2845f0fc2311643a161f 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -1,5 +1,10 @@
|
||||||
|
package net.minecraft.world.level;
|
||||||
|
|
||||||
|
+import co.aikar.timings.Timing;
|
||||||
|
+import co.aikar.timings.Timings;
|
||||||
|
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
|
||||||
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
||||||
|
+import com.google.common.base.MoreObjects;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import java.io.IOException;
|
||||||
|
@@ -737,8 +742,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
gameprofilerfiller.pop();
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
// Paper start - Prevent tile entity and entity crashes
|
||||||
|
- System.err.println("TileEntity threw exception at " + tileentity.level.getWorld().getName() + ":" + tileentity.worldPosition.getX() + "," + tileentity.worldPosition.getY() + "," + tileentity.worldPosition.getZ());
|
||||||
|
+ String msg = "TileEntity threw exception at " + tileentity.getLevel().getWorld().getName() + ":" + tileentity.getBlockPos().getX() + "," + tileentity.getBlockPos().getY() + "," + tileentity.getBlockPos().getZ();
|
||||||
|
+ System.err.println(msg);
|
||||||
|
throwable.printStackTrace();
|
||||||
|
+ getCraftServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable)));
|
||||||
|
+ // Paper end
|
||||||
|
tilesThisCycle--;
|
||||||
|
this.tickableBlockEntities.remove(tileTickPosition--);
|
||||||
|
continue;
|
||||||
|
@@ -808,8 +816,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
tickConsumer.accept(entity);
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
// Paper start - Prevent tile entity and entity crashes
|
||||||
|
- System.err.println("Entity threw exception at " + entity.level.getWorld().getName() + ":" + entity.getX() + "," + entity.getY() + "," + entity.getZ());
|
||||||
|
+ String msg = "Entity threw exception at " + entity.level.getWorld().getName() + ":" + entity.getX() + "," + entity.getY() + "," + entity.getZ();
|
||||||
|
+ System.err.println(msg);
|
||||||
|
throwable.printStackTrace();
|
||||||
|
+ getCraftServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable)));
|
||||||
|
entity.removed = true;
|
||||||
|
return;
|
||||||
|
// Paper end
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||||
|
index fc134b916e95231af8478a4f97bf11a0f37f7f0b..a19ac1cb7e4d8d478648a048b2bfa0daf85a80c9 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||||
|
@@ -299,6 +299,7 @@ public final class NaturalSpawner {
|
||||||
|
}
|
||||||
|
} catch (Exception exception) {
|
||||||
|
NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
|
||||||
|
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -405,6 +406,7 @@ public final class NaturalSpawner {
|
||||||
|
entity = biomesettingsmobs_c.type.create((Level) worldaccess.getLevel());
|
||||||
|
} catch (Exception exception) {
|
||||||
|
NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
|
||||||
|
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 300749822d52f9f973e71c6ec9c8bf29d6a6938e..9ca05aa06696883adc8b67a68ca6d2d850e95d25 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
@@ -1,5 +1,6 @@
|
||||||
|
package net.minecraft.world.level.chunk;
|
||||||
|
|
||||||
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||||
|
@@ -654,10 +655,15 @@ public class LevelChunk implements ChunkAccess {
|
||||||
|
this.blockEntities.remove(pos);
|
||||||
|
// Paper end
|
||||||
|
} else {
|
||||||
|
- System.out.println("Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + "," + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
|
||||||
|
- + " (" + getBlockState(pos) + ") where there was no entity tile!");
|
||||||
|
- System.out.println("Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16));
|
||||||
|
- new Exception().printStackTrace();
|
||||||
|
+ // Paper start
|
||||||
|
+ ServerInternalException e = new ServerInternalException(
|
||||||
|
+ "Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + ","
|
||||||
|
+ + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
|
||||||
|
+ + " (" + getBlockState(pos) + ") where there was no entity tile!\n" +
|
||||||
|
+ "Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16));
|
||||||
|
+ e.printStackTrace();
|
||||||
|
+ ServerInternalException.reportInternalException(e);
|
||||||
|
+ // Paper end
|
||||||
|
// CraftBukkit end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||||
|
index 60f410a4f838048bbfd2cde52caa7c4c9434b0ba..1598da3449ee1c559cf503e1b20a0daaf6a033dd 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||||
|
@@ -265,6 +265,7 @@ public class RegionFile implements AutoCloseable {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (IOException ioexception) {
|
||||||
|
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(ioexception); // Paper
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -337,6 +338,7 @@ public class RegionFile implements AutoCloseable {
|
||||||
|
filechannel.write(bytebuffer);
|
||||||
|
} catch (Throwable throwable1) {
|
||||||
|
throwable = throwable1;
|
||||||
|
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(throwable); // Paper
|
||||||
|
throw throwable1;
|
||||||
|
} finally {
|
||||||
|
if (filechannel != null) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
|
||||||
|
index 60b7fdf9c092e8105d41f4af02a08651624f3eb9..99cfd693ea705d45a5eab181cb80c354a2d1159f 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
|
||||||
|
@@ -150,6 +150,7 @@ public class DimensionDataStorage {
|
||||||
|
}
|
||||||
|
} catch (Throwable throwable6) {
|
||||||
|
throwable = throwable6;
|
||||||
|
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(throwable); // Paper
|
||||||
|
throw throwable6;
|
||||||
|
} finally {
|
||||||
|
if (fileinputstream != null) {
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||||
|
index ffe9cc1011226d604dc5499e7692e9a9a5132b72..9b6d9373abb59a30c2835ca891282d07559281f5 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||||
|
@@ -16,6 +16,9 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
+import com.destroystokyo.paper.ServerSchedulerReportingWrapper;
|
||||||
|
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
|
||||||
|
+import com.destroystokyo.paper.exception.ServerSchedulerException;
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.plugin.IllegalPluginAccessException;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
@@ -419,6 +422,8 @@ public class CraftScheduler implements BukkitScheduler {
|
||||||
|
msg,
|
||||||
|
throwable);
|
||||||
|
}
|
||||||
|
+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(
|
||||||
|
+ new ServerExceptionEvent(new ServerSchedulerException(msg, throwable, task)));
|
||||||
|
// Paper end
|
||||||
|
} finally {
|
||||||
|
currentTask = null;
|
||||||
|
@@ -426,7 +431,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||||
|
parsePending();
|
||||||
|
} else {
|
||||||
|
debugTail = debugTail.setNext(new CraftAsyncDebugger(currentTick + RECENT_TICKS, task.getOwner(), task.getTaskClass()));
|
||||||
|
- executor.execute(task);
|
||||||
|
+ executor.execute(new ServerSchedulerReportingWrapper(task)); // Paper
|
||||||
|
// 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)
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: kashike <kashike@vq.lc>
|
||||||
|
Date: Tue, 8 Mar 2016 18:28:43 -0800
|
||||||
|
Subject: [PATCH] Don't nest if we don't need to when cerealising text
|
||||||
|
components
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundChatPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundChatPacket.java
|
||||||
|
index e47102cadb40ed8a9c011386445f15fd30de7596..f13da9e7d014bc00fbabf0a495b548bba2f59468 100644
|
||||||
|
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundChatPacket.java
|
||||||
|
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundChatPacket.java
|
||||||
|
@@ -40,7 +40,14 @@ public class ClientboundChatPacket implements Packet<ClientGamePacketListener> {
|
||||||
|
// Paper end
|
||||||
|
// Spigot start
|
||||||
|
if (components != null) {
|
||||||
|
- buf.writeByteArray(net.md_5.bungee.chat.ComponentSerializer.toString(components));
|
||||||
|
+ //packetdataserializer.a(net.md_5.bungee.chat.ComponentSerializer.toString(components)); // Paper - comment, replaced with below
|
||||||
|
+ // Paper start - don't nest if we don't need to so that we can preserve formatting
|
||||||
|
+ if (this.components.length == 1) {
|
||||||
|
+ buf.writeByteArray(net.md_5.bungee.chat.ComponentSerializer.toString(this.components[0]));
|
||||||
|
+ } else {
|
||||||
|
+ buf.writeByteArray(net.md_5.bungee.chat.ComponentSerializer.toString(this.components));
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
} else {
|
||||||
|
buf.writeComponent(this.message);
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Tue, 8 Mar 2016 23:25:45 -0500
|
||||||
|
Subject: [PATCH] Disable Scoreboards for non players by default
|
||||||
|
|
||||||
|
Entities collision is checking for scoreboards setting.
|
||||||
|
This is very heavy to do map lookups for every collision to check
|
||||||
|
this setting.
|
||||||
|
|
||||||
|
So avoid looking up scoreboards and short circuit to the "not on a team"
|
||||||
|
logic which is most likely to be true.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index abbbe1786eb68af02f9d39650aad730ac44aac8a..3ac2ac3db9b1c271b3c21930bb13716669ff64d3 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -210,4 +210,9 @@ public class PaperWorldConfig {
|
||||||
|
private void disableTeleportationSuffocationCheck() {
|
||||||
|
disableTeleportationSuffocationCheck = getBoolean("disable-teleportation-suffocation-check", false);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean nonPlayerEntitiesOnScoreboards = false;
|
||||||
|
+ private void nonPlayerEntitiesOnScoreboards() {
|
||||||
|
+ nonPlayerEntitiesOnScoreboards = getBoolean("allow-non-player-entities-on-scoreboards", false);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index a6f2e671cc9b2ef086dfa3d127a7b33272acbd56..93d3408231a177cf6d2086594756adffe3efa702 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -2288,6 +2288,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Team getTeam() {
|
||||||
|
+ if (!this.level.paperConfig.nonPlayerEntitiesOnScoreboards && !(this instanceof Player)) { return null; } // Paper
|
||||||
|
return this.level.getScoreboard().getPlayerTeam(this.getScoreboardName());
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
index afd114e1ce00db72534d470fed12101bb237f266..d483d552092c901fec262c43e488784d9cd8acb9 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
@@ -738,6 +738,7 @@ public abstract class LivingEntity extends Entity {
|
||||||
|
if (tag.contains("Team", 8)) {
|
||||||
|
String s = tag.getString("Team");
|
||||||
|
PlayerTeam scoreboardteam = this.level.getScoreboard().getTeam(s);
|
||||||
|
+ if (!level.paperConfig.nonPlayerEntitiesOnScoreboards && !(this instanceof net.minecraft.world.entity.player.Player)) { scoreboardteam = null; } // Paper
|
||||||
|
boolean flag = scoreboardteam != null && this.level.getScoreboard().addPlayerToTeam(this.getStringUUID(), scoreboardteam);
|
||||||
|
|
||||||
|
if (!flag) {
|
|
@ -0,0 +1,27 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: mrapple <tony@oc.tc>
|
||||||
|
Date: Sun, 25 Nov 2012 13:43:39 -0600
|
||||||
|
Subject: [PATCH] Add methods for working with arrows stuck in living entities
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||||
|
index 3afdcb3013263a7e06876821d7d889fa48404041..d8cd88d62f9abfc7960c187dd74239f61267ca57 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||||
|
@@ -677,4 +677,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||||
|
getHandle().persistentInvisibility = invisible;
|
||||||
|
getHandle().setSharedFlag(5, invisible);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Paper start
|
||||||
|
+ @Override
|
||||||
|
+ public int getArrowsStuck() {
|
||||||
|
+ return getHandle().getArrowCount();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setArrowsStuck(int arrows) {
|
||||||
|
+ getHandle().setArrowCount(arrows);
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jedediah Smith <jedediah@silencegreys.com>
|
||||||
|
Date: Sat, 4 Apr 2015 23:17:52 -0400
|
||||||
|
Subject: [PATCH] Complete resource pack API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
index 00689dc07625a02781052c5df2e466e8abe85708..73683ba59d0aff3a61f555b4ae15753e9e4e6141 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
@@ -1603,7 +1603,11 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
|
||||||
|
// CraftBukkit start
|
||||||
|
public void handleResourcePackResponse(ServerboundResourcePackPacket packet) {
|
||||||
|
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
|
||||||
|
- this.craftServer.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(getPlayer(), PlayerResourcePackStatusEvent.Status.values()[packet.action.ordinal()]));
|
||||||
|
+ // Paper start
|
||||||
|
+ PlayerResourcePackStatusEvent.Status packStatus = PlayerResourcePackStatusEvent.Status.values()[packet.action.ordinal()];
|
||||||
|
+ player.getBukkitEntity().setResourcePackStatus(packStatus);
|
||||||
|
+ this.craftServer.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(getPlayer(), packStatus));
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
index 3b9d61b524441f65646edf7d403b6c5b5345b1e5..dd29038778d73fae84df360515f3c670915f1d48 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
@@ -136,6 +136,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
private double health = 20;
|
||||||
|
private boolean scaledHealth = false;
|
||||||
|
private double healthScale = 20;
|
||||||
|
+ // Paper start
|
||||||
|
+ private org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus;
|
||||||
|
+ private String resourcePackHash;
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
public CraftPlayer(CraftServer server, ServerPlayer entity) {
|
||||||
|
super(server, entity);
|
||||||
|
@@ -1872,6 +1876,32 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
public boolean getAffectsSpawning() {
|
||||||
|
return this.getHandle().affectsSpawning;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setResourcePack(String url, String hash) {
|
||||||
|
+ Validate.notNull(url, "Resource pack URL cannot be null");
|
||||||
|
+ Validate.notNull(hash, "Hash cannot be null");
|
||||||
|
+ this.getHandle().sendTexturePack(url, hash);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status getResourcePackStatus() {
|
||||||
|
+ return this.resourcePackStatus;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public String getResourcePackHash() {
|
||||||
|
+ return this.resourcePackHash;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean hasResourcePack() {
|
||||||
|
+ return this.resourcePackStatus == org.bukkit.event.player.PlayerResourcePackStatusEvent.Status.SUCCESSFULLY_LOADED;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void setResourcePackStatus(org.bukkit.event.player.PlayerResourcePackStatusEvent.Status status) {
|
||||||
|
+ this.resourcePackStatus = status;
|
||||||
|
+ }
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
@Override
|
|
@ -0,0 +1,59 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Mon, 4 Mar 2013 23:46:10 -0500
|
||||||
|
Subject: [PATCH] Chunk Save Reattempt
|
||||||
|
|
||||||
|
We commonly have "Stream Closed" errors on chunk saving, so this code should re-try to save the chunk in the event of failure and hopefully prevent rollbacks.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||||
|
index 1598da3449ee1c559cf503e1b20a0daaf6a033dd..1aa4d342b97f8be71c108194a6f1e0e2828aa364 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||||
|
@@ -265,7 +265,7 @@ public class RegionFile implements AutoCloseable {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (IOException ioexception) {
|
||||||
|
- com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(ioexception); // Paper
|
||||||
|
+ com.destroystokyo.paper.util.SneakyThrow.sneaky(ioexception); // Paper - we want the upper try/catch to retry this
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 1e49d17b54704e1b99c3ded458c4bc6842bd32bd..97a58da9d64d812942ceb71426d35b490bbbe817 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
|
||||||
|
@@ -11,6 +11,7 @@ import java.io.IOException;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.NbtIo;
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.util.ExceptionCollector;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
|
||||||
|
@@ -92,6 +93,7 @@ public final class RegionFileStorage implements AutoCloseable {
|
||||||
|
|
||||||
|
protected void write(ChunkPos pos, CompoundTag tag) throws IOException {
|
||||||
|
RegionFile regionfile = this.getFile(pos, false); // CraftBukkit
|
||||||
|
+ int attempts = 0; Exception laste = null; while (attempts++ < 5) { try { // Paper
|
||||||
|
DataOutputStream dataoutputstream = regionfile.getChunkDataOutputStream(pos);
|
||||||
|
Throwable throwable = null;
|
||||||
|
|
||||||
|
@@ -115,6 +117,18 @@ public final class RegionFileStorage implements AutoCloseable {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ return;
|
||||||
|
+ } catch (Exception ex) {
|
||||||
|
+ laste = ex;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (laste != null) {
|
||||||
|
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(laste);
|
||||||
|
+ MinecraftServer.LOGGER.error("Failed to save chunk", laste);
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
|
@ -0,0 +1,52 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Fri, 18 Mar 2016 13:17:38 -0400
|
||||||
|
Subject: [PATCH] Default loading permissions.yml before plugins
|
||||||
|
|
||||||
|
Under previous behavior, plugins were not able to check if a player had a permission
|
||||||
|
if it was defined in permissions.yml. there is no clean way for a plugin to fix that either.
|
||||||
|
|
||||||
|
This will change the order so that by default, permissions.yml loads BEFORE plugins instead of after.
|
||||||
|
|
||||||
|
This gives plugins expected permission checks.
|
||||||
|
|
||||||
|
It also helps improve the expected logic, as servers should set the initial defaults, and then let plugins
|
||||||
|
modify that. Under the previous logic, plugins were unable (cleanly) override permissions.yml.
|
||||||
|
|
||||||
|
A config option has been added for those who depend on the previous behavior, but I don't expect that.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
index 429b74474ced04d8dd8f038b8590b8dfe178bf4d..716f285e67019b8a62922d09c15883c99f9421aa 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
@@ -222,4 +222,9 @@ public class PaperConfig {
|
||||||
|
private static void useDisplayNameInQuit() {
|
||||||
|
useDisplayNameInQuit = getBoolean("use-display-name-in-quit-message", useDisplayNameInQuit);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public static boolean loadPermsBeforePlugins = true;
|
||||||
|
+ private static void loadPermsBeforePlugins() {
|
||||||
|
+ loadPermsBeforePlugins = getBoolean("settings.load-permissions-yml-before-plugins", true);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index 35d3df7ded4904414a9a61895950b56be530d244..662fc88e2e118a57a6c35a8981d4622188adec3b 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -397,6 +397,7 @@ public final class CraftServer implements Server {
|
||||||
|
if (type == PluginLoadOrder.STARTUP) {
|
||||||
|
helpMap.clear();
|
||||||
|
helpMap.initializeGeneralTopics();
|
||||||
|
+ if (com.destroystokyo.paper.PaperConfig.loadPermsBeforePlugins) loadCustomPermissions(); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
Plugin[] plugins = pluginManager.getPlugins();
|
||||||
|
@@ -416,7 +417,7 @@ public final class CraftServer implements Server {
|
||||||
|
commandMap.registerServerAliases();
|
||||||
|
DefaultPermissions.registerCorePermissions();
|
||||||
|
CraftDefaultPermissions.registerCorePermissions();
|
||||||
|
- loadCustomPermissions();
|
||||||
|
+ if (!com.destroystokyo.paper.PaperConfig.loadPermsBeforePlugins) loadCustomPermissions(); // Paper
|
||||||
|
helpMap.initializeCommands();
|
||||||
|
syncCommands();
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: William <admin@domnian.com>
|
||||||
|
Date: Fri, 18 Mar 2016 03:30:17 -0400
|
||||||
|
Subject: [PATCH] Allow Reloading of Custom Permissions
|
||||||
|
|
||||||
|
https://github.com/PaperMC/Paper/issues/49
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index 662fc88e2e118a57a6c35a8981d4622188adec3b..50da8e292c131176c263f0bc140ff4f6d890c737 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -2252,5 +2252,23 @@ public final class CraftServer implements Server {
|
||||||
|
}
|
||||||
|
return this.adventure$audiences;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void reloadPermissions() {
|
||||||
|
+ pluginManager.clearPermissions();
|
||||||
|
+ if (com.destroystokyo.paper.PaperConfig.loadPermsBeforePlugins) loadCustomPermissions();
|
||||||
|
+ for (Plugin plugin : pluginManager.getPlugins()) {
|
||||||
|
+ for (Permission perm : plugin.getDescription().getPermissions()) {
|
||||||
|
+ try {
|
||||||
|
+ pluginManager.addPermission(perm);
|
||||||
|
+ } catch (IllegalArgumentException ex) {
|
||||||
|
+ getLogger().log(Level.WARNING, "Plugin " + plugin.getDescription().getFullName() + " tried to register permission '" + perm.getName() + "' but it's already registered", ex);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (!com.destroystokyo.paper.PaperConfig.loadPermsBeforePlugins) loadCustomPermissions();
|
||||||
|
+ DefaultPermissions.registerCorePermissions();
|
||||||
|
+ CraftDefaultPermissions.registerCorePermissions();
|
||||||
|
+ }
|
||||||
|
// Paper end
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Fri, 18 Mar 2016 13:50:14 -0400
|
||||||
|
Subject: [PATCH] Remove Metadata on reload
|
||||||
|
|
||||||
|
Metadata is not meant to persist reload as things break badly with non primitive types
|
||||||
|
This will remove metadata on reload so it does not crash everything if a plugin uses it.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index 50da8e292c131176c263f0bc140ff4f6d890c737..2828936fe294d9d6750a8838da49ec8398835214 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -870,8 +870,18 @@ public final class CraftServer implements Server {
|
||||||
|
world.paperConfig.init(); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
|
||||||
|
pluginManager.clearPlugins();
|
||||||
|
commandMap.clearCommands();
|
||||||
|
+
|
||||||
|
+ // Paper start
|
||||||
|
+ for (Plugin plugin : pluginClone) {
|
||||||
|
+ entityMetadata.removeAll(plugin);
|
||||||
|
+ worldMetadata.removeAll(plugin);
|
||||||
|
+ playerMetadata.removeAll(plugin);
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
resetRecipes();
|
||||||
|
reloadData();
|
||||||
|
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
|
|
@ -0,0 +1,339 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Thu, 28 May 2015 23:00:19 -0400
|
||||||
|
Subject: [PATCH] Handle Item Meta Inconsistencies
|
||||||
|
|
||||||
|
First, Enchantment order would blow away seeing 2 items as the same,
|
||||||
|
however the Client forces enchantment list in a certain order, as well
|
||||||
|
as does the /enchant command. Anvils can insert it into forced order,
|
||||||
|
causing 2 same items to be considered different.
|
||||||
|
|
||||||
|
This change makes unhandled NBT Tags and Enchantments use a sorted tree map,
|
||||||
|
so they will always be in a consistent order.
|
||||||
|
|
||||||
|
Additionally, the old enchantment API was never updated when ItemMeta
|
||||||
|
was added, resulting in 2 different ways to modify an items enchantments.
|
||||||
|
|
||||||
|
For consistency, the old API methods now forward to use the
|
||||||
|
ItemMeta API equivalents, and should deprecate the old API's.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||||
|
index 3faf52e7ac5e7e22d09cfb73cfda6b9f622137d4..123025c6dc9a2eea56c7db5cb508cdfd7c6cc97b 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||||
|
@@ -9,6 +9,8 @@ import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.text.DecimalFormatSymbols;
|
||||||
|
+import java.util.Collections;
|
||||||
|
+import java.util.Comparator;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
@@ -118,6 +120,23 @@ public final class ItemStack {
|
||||||
|
private BlockInWorld cachedPlaceBlock;
|
||||||
|
private boolean cachedPlaceBlockResult;
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ private static final java.util.Comparator<? super CompoundTag> enchantSorter = java.util.Comparator.comparing(o -> o.getString("id"));
|
||||||
|
+ private void processEnchantOrder(CompoundTag tag) {
|
||||||
|
+ if (tag == null || !tag.contains("Enchantments", 9)) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ ListTag list = tag.getList("Enchantments", 10);
|
||||||
|
+ if (list.size() < 2) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ try {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ list.sort((Comparator<? super Tag>) enchantSorter); // Paper
|
||||||
|
+ } catch (Exception ignored) {}
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
public ItemStack(ItemLike item) {
|
||||||
|
this(item, 1);
|
||||||
|
}
|
||||||
|
@@ -160,6 +179,7 @@ public final class ItemStack {
|
||||||
|
if (nbttagcompound.contains("tag", 10)) {
|
||||||
|
// CraftBukkit start - make defensive copy as this data may be coming from the save thread
|
||||||
|
this.tag = (CompoundTag) nbttagcompound.getCompound("tag").copy();
|
||||||
|
+ processEnchantOrder(this.tag); // Paper
|
||||||
|
this.getItem().verifyTagAfterLoad(this.tag);
|
||||||
|
// CraftBukkit end
|
||||||
|
}
|
||||||
|
@@ -678,6 +698,7 @@ public final class ItemStack {
|
||||||
|
// Paper end
|
||||||
|
public void setTag(@Nullable CompoundTag tag) {
|
||||||
|
this.tag = tag;
|
||||||
|
+ processEnchantOrder(this.tag); // Paper
|
||||||
|
if (this.getItem().canBeDepleted()) {
|
||||||
|
this.setDamageValue(this.getDamageValue());
|
||||||
|
}
|
||||||
|
@@ -768,6 +789,7 @@ public final class ItemStack {
|
||||||
|
nbttagcompound.putString("id", String.valueOf(Registry.ENCHANTMENT.getKey(enchantment)));
|
||||||
|
nbttagcompound.putShort("lvl", (short) ((byte) level));
|
||||||
|
nbttaglist.add(nbttagcompound);
|
||||||
|
+ processEnchantOrder(nbttagcompound); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnchanted() {
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||||
|
index 01df5263d77771a296ca091a0feec620e6e37229..5f0ccdeb8565505278caa591f7390047eab49cf4 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||||
|
@@ -6,7 +6,6 @@ import java.util.Map;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.ListTag;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
-import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.configuration.serialization.DelegateDeserialization;
|
||||||
|
@@ -178,28 +177,11 @@ public final class CraftItemStack extends ItemStack {
|
||||||
|
public void addUnsafeEnchantment(Enchantment ench, int level) {
|
||||||
|
Validate.notNull(ench, "Cannot add null enchantment");
|
||||||
|
|
||||||
|
- if (!makeTag(handle)) {
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
- ListTag list = getEnchantmentList(handle);
|
||||||
|
- if (list == null) {
|
||||||
|
- list = new ListTag();
|
||||||
|
- handle.getTag().put(ENCHANTMENTS.NBT, list);
|
||||||
|
- }
|
||||||
|
- int size = list.size();
|
||||||
|
-
|
||||||
|
- for (int i = 0; i < size; i++) {
|
||||||
|
- CompoundTag tag = (CompoundTag) list.get(i);
|
||||||
|
- String id = tag.getString(ENCHANTMENTS_ID.NBT);
|
||||||
|
- if (id.equals(ench.getKey().toString())) {
|
||||||
|
- tag.putShort(ENCHANTMENTS_LVL.NBT, (short) level);
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- CompoundTag tag = new CompoundTag();
|
||||||
|
- tag.putString(ENCHANTMENTS_ID.NBT, ench.getKey().toString());
|
||||||
|
- tag.putShort(ENCHANTMENTS_LVL.NBT, (short) level);
|
||||||
|
- list.add(tag);
|
||||||
|
+ // Paper start - Replace whole method
|
||||||
|
+ final ItemMeta itemMeta = getItemMeta();
|
||||||
|
+ itemMeta.addEnchant(ench, level, true);
|
||||||
|
+ setItemMeta(itemMeta);
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean makeTag(net.minecraft.world.item.ItemStack item) {
|
||||||
|
@@ -216,66 +198,33 @@ public final class CraftItemStack extends ItemStack {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsEnchantment(Enchantment ench) {
|
||||||
|
- return getEnchantmentLevel(ench) > 0;
|
||||||
|
+ return hasItemMeta() && getItemMeta().hasEnchant(ench); // Paper - use meta
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEnchantmentLevel(Enchantment ench) {
|
||||||
|
- Validate.notNull(ench, "Cannot find null enchantment");
|
||||||
|
- if (handle == null) {
|
||||||
|
- return 0;
|
||||||
|
- }
|
||||||
|
- return EnchantmentHelper.getItemEnchantmentLevel(CraftEnchantment.getRaw(ench), handle);
|
||||||
|
+ return hasItemMeta() ? getItemMeta().getEnchantLevel(ench) : 0; // Paper - replace entire method with meta
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int removeEnchantment(Enchantment ench) {
|
||||||
|
Validate.notNull(ench, "Cannot remove null enchantment");
|
||||||
|
|
||||||
|
- ListTag list = getEnchantmentList(handle), listCopy;
|
||||||
|
- if (list == null) {
|
||||||
|
- return 0;
|
||||||
|
- }
|
||||||
|
- int index = Integer.MIN_VALUE;
|
||||||
|
- int level = Integer.MIN_VALUE;
|
||||||
|
- int size = list.size();
|
||||||
|
-
|
||||||
|
- for (int i = 0; i < size; i++) {
|
||||||
|
- CompoundTag enchantment = (CompoundTag) list.get(i);
|
||||||
|
- String id = enchantment.getString(ENCHANTMENTS_ID.NBT);
|
||||||
|
- if (id.equals(ench.getKey().toString())) {
|
||||||
|
- index = i;
|
||||||
|
- level = 0xffff & enchantment.getShort(ENCHANTMENTS_LVL.NBT);
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if (index == Integer.MIN_VALUE) {
|
||||||
|
- return 0;
|
||||||
|
- }
|
||||||
|
- if (size == 1) {
|
||||||
|
- handle.getTag().remove(ENCHANTMENTS.NBT);
|
||||||
|
- if (handle.getTag().isEmpty()) {
|
||||||
|
- handle.setTag(null);
|
||||||
|
- }
|
||||||
|
- return level;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- // This is workaround for not having an index removal
|
||||||
|
- listCopy = new ListTag();
|
||||||
|
- for (int i = 0; i < size; i++) {
|
||||||
|
- if (i != index) {
|
||||||
|
- listCopy.add(list.get(i));
|
||||||
|
- }
|
||||||
|
+ // Paper start - replace entire method
|
||||||
|
+ final ItemMeta itemMeta = getItemMeta();
|
||||||
|
+ int level = itemMeta.getEnchantLevel(ench);
|
||||||
|
+ if (level > 0) {
|
||||||
|
+ itemMeta.removeEnchant(ench);
|
||||||
|
+ setItemMeta(itemMeta);
|
||||||
|
}
|
||||||
|
- handle.getTag().put(ENCHANTMENTS.NBT, listCopy);
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Enchantment, Integer> getEnchantments() {
|
||||||
|
- return getEnchantments(handle);
|
||||||
|
+ return hasItemMeta() ? getItemMeta().getEnchants() : ImmutableMap.<Enchantment, Integer>of(); // Paper - use Item Meta
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<Enchantment, Integer> getEnchantments(net.minecraft.world.item.ItemStack item) {
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||||
|
index cca04daf84e506382365c0ba945cb024bd4d4475..521699615778c4b724d10edfee1d3915e036eb2e 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||||
|
@@ -6,6 +6,7 @@ import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
|
import com.google.common.collect.LinkedHashMultimap;
|
||||||
|
+import com.google.common.collect.ImmutableSortedMap; // Paper
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.google.common.collect.SetMultimap;
|
||||||
|
@@ -22,6 +23,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
+import java.util.Comparator; // Paper
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
@@ -32,6 +34,7 @@ import java.util.Map;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
+import java.util.TreeMap; // Paper
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
@@ -270,7 +273,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||||
|
private List<String> lore; // null and empty are two different states internally
|
||||||
|
private Integer customModelData;
|
||||||
|
private CompoundTag blockData;
|
||||||
|
- private Map<Enchantment, Integer> enchantments;
|
||||||
|
+ private EnchantmentMap enchantments; // Paper
|
||||||
|
private Multimap<Attribute, AttributeModifier> attributeModifiers;
|
||||||
|
private int repairCost;
|
||||||
|
private int hideFlag;
|
||||||
|
@@ -281,7 +284,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||||
|
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
|
||||||
|
|
||||||
|
private CompoundTag internalTag;
|
||||||
|
- private final Map<String, Tag> unhandledTags = new HashMap<String, Tag>();
|
||||||
|
+ private final Map<String, Tag> unhandledTags = new TreeMap<>(); // Paper
|
||||||
|
private CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(DATA_TYPE_REGISTRY);
|
||||||
|
|
||||||
|
private int version = CraftMagicNumbers.INSTANCE.getDataVersion(); // Internal use only
|
||||||
|
@@ -302,7 +305,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||||
|
this.blockData = meta.blockData;
|
||||||
|
|
||||||
|
if (meta.enchantments != null) { // Spigot
|
||||||
|
- this.enchantments = new LinkedHashMap<Enchantment, Integer>(meta.enchantments);
|
||||||
|
+ this.enchantments = new EnchantmentMap(meta.enchantments); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta.hasAttributeModifiers()) {
|
||||||
|
@@ -385,13 +388,13 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- static Map<Enchantment, Integer> buildEnchantments(CompoundTag tag, ItemMetaKey key) {
|
||||||
|
+ static EnchantmentMap buildEnchantments(CompoundTag tag, ItemMetaKey key) { // Paper
|
||||||
|
if (!tag.contains(key.NBT)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListTag ench = tag.getList(key.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND);
|
||||||
|
- Map<Enchantment, Integer> enchantments = new LinkedHashMap<Enchantment, Integer>(ench.size());
|
||||||
|
+ EnchantmentMap enchantments = new EnchantmentMap(); // Paper
|
||||||
|
|
||||||
|
for (int i = 0; i < ench.size(); i++) {
|
||||||
|
String id = ((CompoundTag) ench.get(i)).getString(ENCHANTMENTS_ID.NBT);
|
||||||
|
@@ -544,13 +547,13 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- static Map<Enchantment, Integer> buildEnchantments(Map<String, Object> map, ItemMetaKey key) {
|
||||||
|
+ static EnchantmentMap buildEnchantments(Map<String, Object> map, ItemMetaKey key) { // Paper
|
||||||
|
Map<?, ?> ench = SerializableMeta.getObject(Map.class, map, key.BUKKIT, true);
|
||||||
|
if (ench == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
- Map<Enchantment, Integer> enchantments = new LinkedHashMap<Enchantment, Integer>(ench.size());
|
||||||
|
+ EnchantmentMap enchantments = new EnchantmentMap(); // Paper
|
||||||
|
for (Map.Entry<?, ?> entry : ench.entrySet()) {
|
||||||
|
// Doctor older enchants
|
||||||
|
String enchantKey = entry.getKey().toString();
|
||||||
|
@@ -826,14 +829,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Enchantment, Integer> getEnchants() {
|
||||||
|
- return hasEnchants() ? ImmutableMap.copyOf(enchantments) : ImmutableMap.<Enchantment, Integer>of();
|
||||||
|
+ return hasEnchants() ? ImmutableSortedMap.copyOfSorted(enchantments) : ImmutableMap.<Enchantment, Integer>of(); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addEnchant(Enchantment ench, int level, boolean ignoreRestrictions) {
|
||||||
|
Validate.notNull(ench, "Enchantment cannot be null");
|
||||||
|
if (enchantments == null) {
|
||||||
|
- enchantments = new LinkedHashMap<Enchantment, Integer>(4);
|
||||||
|
+ enchantments = new EnchantmentMap(); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignoreRestrictions || level >= ench.getStartLevel() && level <= ench.getMaxLevel()) {
|
||||||
|
@@ -1214,7 +1217,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||||
|
clone.customModelData = this.customModelData;
|
||||||
|
clone.blockData = this.blockData;
|
||||||
|
if (this.enchantments != null) {
|
||||||
|
- clone.enchantments = new LinkedHashMap<Enchantment, Integer>(this.enchantments);
|
||||||
|
+ clone.enchantments = new EnchantmentMap(this.enchantments); // Paper
|
||||||
|
}
|
||||||
|
if (this.hasAttributeModifiers()) {
|
||||||
|
clone.attributeModifiers = LinkedHashMultimap.create(this.attributeModifiers);
|
||||||
|
@@ -1446,4 +1449,22 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||||
|
return HANDLED_TAGS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Paper start
|
||||||
|
+ private static class EnchantmentMap extends TreeMap<Enchantment, Integer> {
|
||||||
|
+ private EnchantmentMap(Map<Enchantment, Integer> enchantments) {
|
||||||
|
+ this();
|
||||||
|
+ putAll(enchantments);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private EnchantmentMap() {
|
||||||
|
+ super(Comparator.comparing(o -> o.getKey().toString()));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public EnchantmentMap clone() {
|
||||||
|
+ return (EnchantmentMap) super.clone();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Fri, 18 Mar 2016 15:12:22 -0400
|
||||||
|
Subject: [PATCH] Configurable Non Player Arrow Despawn Rate
|
||||||
|
|
||||||
|
Can set a much shorter despawn rate for arrows that players can not pick up.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 3ac2ac3db9b1c271b3c21930bb13716669ff64d3..3c78d3234054ce2dc46ef77decb6adb0cbd10620 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -215,4 +215,19 @@ public class PaperWorldConfig {
|
||||||
|
private void nonPlayerEntitiesOnScoreboards() {
|
||||||
|
nonPlayerEntitiesOnScoreboards = getBoolean("allow-non-player-entities-on-scoreboards", false);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public int nonPlayerArrowDespawnRate = -1;
|
||||||
|
+ public int creativeArrowDespawnRate = -1;
|
||||||
|
+ private void nonPlayerArrowDespawnRate() {
|
||||||
|
+ nonPlayerArrowDespawnRate = getInt("non-player-arrow-despawn-rate", -1);
|
||||||
|
+ if (nonPlayerArrowDespawnRate == -1) {
|
||||||
|
+ nonPlayerArrowDespawnRate = spigotConfig.arrowDespawnRate;
|
||||||
|
+ }
|
||||||
|
+ creativeArrowDespawnRate = getInt("creative-arrow-despawn-rate", -1);
|
||||||
|
+ if (creativeArrowDespawnRate == -1) {
|
||||||
|
+ creativeArrowDespawnRate = spigotConfig.arrowDespawnRate;
|
||||||
|
+ }
|
||||||
|
+ log("Non Player Arrow Despawn Rate: " + nonPlayerArrowDespawnRate);
|
||||||
|
+ log("Creative Arrow Despawn Rate: " + creativeArrowDespawnRate);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
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 371fdcbf1f9c01f6a356393f6c3767511f230930..0dc5792d542658107c9c22c1f920986decd13920 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
|
||||||
|
@@ -281,7 +281,7 @@ public abstract class AbstractArrow extends Projectile {
|
||||||
|
|
||||||
|
protected void tickDespawn() {
|
||||||
|
++this.life;
|
||||||
|
- if (this.life >= ((this instanceof ThrownTrident) ? level.spigotConfig.tridentDespawnRate : level.spigotConfig.arrowDespawnRate)) { // Spigot
|
||||||
|
+ if (this.life >= (pickup == Pickup.CREATIVE_ONLY ? level.paperConfig.creativeArrowDespawnRate : (pickup == Pickup.DISALLOWED ? level.paperConfig.nonPlayerArrowDespawnRate : ((this instanceof ThrownTrident) ? level.spigotConfig.tridentDespawnRate : level.spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - TODO: Extract this to init?
|
||||||
|
this.remove();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Fri, 18 Mar 2016 20:16:03 -0400
|
||||||
|
Subject: [PATCH] Add World Util Methods
|
||||||
|
|
||||||
|
Methods that can be used for other patches to help improve logic.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index 89472b6e8f38921db50440d0213e40ac893892f1..e1f9a12c7fb4818a785b9a4819f94fccde02b6a2 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -191,7 +191,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||||
|
public final LevelStorageSource.LevelStorageAccess convertable;
|
||||||
|
public final UUID uuid;
|
||||||
|
|
||||||
|
- public LevelChunk getChunkIfLoaded(int x, int z) {
|
||||||
|
+ @Override public LevelChunk getChunkIfLoaded(int x, int z) { // Paper - this was added in world too but keeping here for NMS ABI
|
||||||
|
return this.chunkSource.getChunk(x, z, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index 94e268a05b4601c29b6d2845f0fc2311643a161f..799721ac63f0c08dd03a788b87eafa9a8cc976cc 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -297,11 +297,27 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
- public FluidState getFluidIfLoaded(BlockPos blockposition) {
|
||||||
|
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
|
||||||
|
ChunkAccess chunk = this.getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4);
|
||||||
|
|
||||||
|
return chunk == null ? null : chunk.getFluidState(blockposition);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public final boolean isLoadedAndInBounds(BlockPos blockposition) { // Paper - final for inline
|
||||||
|
+ return getWorldBorder().isInBounds(blockposition) && getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4) != null;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public LevelChunk getChunkIfLoaded(int x, int z) { // Overridden in WorldServer for ABI compat which has final
|
||||||
|
+ return ((ServerLevel) this).getChunkSource().getChunkAtIfLoadedImmediately(x, z);
|
||||||
|
+ }
|
||||||
|
+ public final LevelChunk getChunkIfLoaded(BlockPos blockposition) {
|
||||||
|
+ return ((ServerLevel) this).getChunkSource().getChunkAtIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // reduces need to do isLoaded before getType
|
||||||
|
+ public final BlockState getTypeIfLoadedAndInBounds(BlockPos blockposition) {
|
||||||
|
+ return getWorldBorder().isInBounds(blockposition) ? getTypeIfLoaded(blockposition) : null;
|
||||||
|
+ }
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
@Override
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/border/WorldBorder.java b/src/main/java/net/minecraft/world/level/border/WorldBorder.java
|
||||||
|
index 31f17956b3b031d1a47bda4d282554c8a7853097..0846f649dca3422dbab3bb0a4826e27430cc8186 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/border/WorldBorder.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/border/WorldBorder.java
|
||||||
|
@@ -31,6 +31,7 @@ public class WorldBorder {
|
||||||
|
|
||||||
|
public WorldBorder() {}
|
||||||
|
|
||||||
|
+ public final boolean isInBounds(BlockPos blockposition) { return this.isWithinBounds(blockposition); } // Paper - OBFHELPER
|
||||||
|
public boolean isWithinBounds(BlockPos pos) {
|
||||||
|
return (double) (pos.getX() + 1) > this.getMinX() && (double) pos.getX() < this.getMaxX() && (double) (pos.getZ() + 1) > this.getMinZ() && (double) pos.getZ() < this.getMaxZ();
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jedediah Smith <jedediah@silencegreys.com>
|
||||||
|
Date: Sun, 21 Jun 2015 15:07:20 -0400
|
||||||
|
Subject: [PATCH] Custom replacement for eaten items
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
index d483d552092c901fec262c43e488784d9cd8acb9..3c707ca6b56e89b671db6316d4db90a2903f33b4 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
@@ -3202,9 +3202,10 @@ public abstract class LivingEntity extends Entity {
|
||||||
|
this.triggerItemUseEffects(this.useItem, 16);
|
||||||
|
// CraftBukkit start - fire PlayerItemConsumeEvent
|
||||||
|
ItemStack itemstack;
|
||||||
|
+ PlayerItemConsumeEvent event = null; // Paper
|
||||||
|
if (this instanceof ServerPlayer) {
|
||||||
|
org.bukkit.inventory.ItemStack craftItem = CraftItemStack.asBukkitCopy(this.useItem);
|
||||||
|
- PlayerItemConsumeEvent event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem);
|
||||||
|
+ event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem); // Paper
|
||||||
|
level.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
@@ -3218,6 +3219,13 @@ public abstract class LivingEntity extends Entity {
|
||||||
|
} else {
|
||||||
|
itemstack = this.useItem.finishUsingItem(this.level, this);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Paper start - save the default replacement item and change it if necessary
|
||||||
|
+ final ItemStack defaultReplacement = itemstack;
|
||||||
|
+ if (event != null && event.getReplacement() != null) {
|
||||||
|
+ itemstack = CraftItemStack.asNMSCopy(event.getReplacement());
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
if (itemstack != this.useItem) {
|
||||||
|
@@ -3225,6 +3233,11 @@ public abstract class LivingEntity extends Entity {
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopUsingItem();
|
||||||
|
+ // Paper start - if the replacement is anything but the default, update the client inventory
|
||||||
|
+ if (this instanceof ServerPlayer && !com.google.common.base.Objects.equal(defaultReplacement, itemstack)) {
|
||||||
|
+ ((ServerPlayer) this).getBukkitEntity().updateInventory();
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Sun, 27 Sep 2015 01:18:02 -0400
|
||||||
|
Subject: [PATCH] handle NaN health/absorb values and repair bad data
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
index 3c707ca6b56e89b671db6316d4db90a2903f33b4..a326e5b4ac055f2f8a95c6eaccd8d0a97762da1f 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
@@ -699,7 +699,13 @@ public abstract class LivingEntity extends Entity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readAdditionalSaveData(CompoundTag tag) {
|
||||||
|
- this.setAbsorptionAmount(tag.getFloat("AbsorptionAmount"));
|
||||||
|
+ // Paper start - jvm keeps optimizing the setter
|
||||||
|
+ float absorptionAmount = tag.getFloat("AbsorptionAmount");
|
||||||
|
+ if (Float.isNaN(absorptionAmount)) {
|
||||||
|
+ absorptionAmount = 0;
|
||||||
|
+ }
|
||||||
|
+ this.setAbsorptionAmount(absorptionAmount);
|
||||||
|
+ // Paper end
|
||||||
|
if (tag.contains("Attributes", 9) && this.level != null && !this.level.isClientSide) {
|
||||||
|
this.getAttributes().load(tag.getList("Attributes", 10));
|
||||||
|
}
|
||||||
|
@@ -1148,6 +1154,10 @@ public abstract class LivingEntity extends Entity {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHealth(float health) {
|
||||||
|
+ // Paper start
|
||||||
|
+ if (Float.isNaN(health)) { health = getMaxHealth(); if (this.valid) {
|
||||||
|
+ System.err.println("[NAN-HEALTH] " + getScoreboardName() + " had NaN health set");
|
||||||
|
+ } } // Paper end
|
||||||
|
// CraftBukkit start - Handle scaled health
|
||||||
|
if (this instanceof ServerPlayer) {
|
||||||
|
org.bukkit.craftbukkit.entity.CraftPlayer player = ((ServerPlayer) this).getBukkitEntity();
|
||||||
|
@@ -3042,7 +3052,7 @@ public abstract class LivingEntity extends Entity {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAbsorptionAmount(float amount) {
|
||||||
|
- if (amount < 0.0F) {
|
||||||
|
+ if (amount < 0.0F || Float.isNaN(amount)) { // Paper
|
||||||
|
amount = 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
index dd29038778d73fae84df360515f3c670915f1d48..b7d5a718375083a4162df4bb41de3acd57b297fb 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
@@ -1678,6 +1678,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRealHealth(double health) {
|
||||||
|
+ if (Double.isNaN(health)) {return;} // Paper
|
||||||
|
this.health = health;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Tue, 22 Mar 2016 00:33:47 -0400
|
||||||
|
Subject: [PATCH] Use a Shared Random for Entities
|
||||||
|
|
||||||
|
Reduces memory usage and provides ensures more randomness, Especially since a lot of garbage entity objects get created.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 93d3408231a177cf6d2086594756adffe3efa702..61048140cf0adca03bfb57193ada0adaee73b1bb 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -142,6 +142,21 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
return tag.contains("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ public static Random SHARED_RANDOM = new Random() {
|
||||||
|
+ private boolean locked = false;
|
||||||
|
+ @Override
|
||||||
|
+ public synchronized void setSeed(long seed) {
|
||||||
|
+ if (locked) {
|
||||||
|
+ LogManager.getLogger().error("Ignoring setSeed on Entity.SHARED_RANDOM", new Throwable());
|
||||||
|
+ } else {
|
||||||
|
+ super.setSeed(seed);
|
||||||
|
+ locked = true;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
private CraftEntity bukkitEntity;
|
||||||
|
|
||||||
|
public CraftEntity getBukkitEntity() {
|
||||||
|
@@ -271,7 +286,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
this.stuckSpeedMultiplier = Vec3.ZERO;
|
||||||
|
this.nextStep = 1.0F;
|
||||||
|
this.nextFlap = 1.0F;
|
||||||
|
- this.random = new Random();
|
||||||
|
+ this.random = SHARED_RANDOM; // Paper
|
||||||
|
this.remainingFireTicks = -this.getFireImmuneTicks();
|
||||||
|
this.fluidHeight = new Object2DoubleArrayMap(2);
|
||||||
|
this.firstTick = true;
|
|
@ -0,0 +1,36 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Tue, 22 Mar 2016 12:04:28 -0500
|
||||||
|
Subject: [PATCH] Configurable spawn chances for skeleton horses
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 3c78d3234054ce2dc46ef77decb6adb0cbd10620..cd64fb9d0c6d123e1c86cb33f12cd9cefc9f80d0 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -230,4 +230,12 @@ public class PaperWorldConfig {
|
||||||
|
log("Non Player Arrow Despawn Rate: " + nonPlayerArrowDespawnRate);
|
||||||
|
log("Creative Arrow Despawn Rate: " + creativeArrowDespawnRate);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public double skeleHorseSpawnChance;
|
||||||
|
+ private void skeleHorseSpawnChance() {
|
||||||
|
+ skeleHorseSpawnChance = getDouble("skeleton-horse-thunder-spawn-chance", 0.01D);
|
||||||
|
+ if (skeleHorseSpawnChance < 0) {
|
||||||
|
+ skeleHorseSpawnChance = 0.01D; // Vanilla value
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index e1f9a12c7fb4818a785b9a4819f94fccde02b6a2..22c687e3db79bcfbc512ce3993d6e8a6db062360 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -584,7 +584,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||||
|
blockposition = this.findLightingTargetAround(this.getBlockRandomPos(j, 0, k, 15));
|
||||||
|
if (this.isRainingAt(blockposition)) {
|
||||||
|
DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);
|
||||||
|
- boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * 0.01D;
|
||||||
|
+ boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * paperConfig.skeleHorseSpawnChance; // Paper
|
||||||
|
|
||||||
|
if (flag1) {
|
||||||
|
SkeletonHorse entityhorseskeleton = (SkeletonHorse) EntityType.SKELETON_HORSE.create((net.minecraft.world.level.Level) this);
|
|
@ -0,0 +1,206 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Thu, 3 Mar 2016 02:07:55 -0600
|
||||||
|
Subject: [PATCH] Optimize isValidLocation, getType and getBlockData for
|
||||||
|
inlining
|
||||||
|
|
||||||
|
Hot methods, so reduce # of instructions for the method.
|
||||||
|
|
||||||
|
Move is valid location test to the BlockPosition class so that it can access local variables.
|
||||||
|
|
||||||
|
Replace all calls to the new place to the unnecessary forward.
|
||||||
|
|
||||||
|
Optimize getType and getBlockData to manually inline and optimize the calls
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/core/Vec3i.java b/src/main/java/net/minecraft/core/Vec3i.java
|
||||||
|
index 3e79b274b8e0406a3cbdd94c7cec091b583109ca..c22de593be404c4e921724bba6a69c13759a95fd 100644
|
||||||
|
--- a/src/main/java/net/minecraft/core/Vec3i.java
|
||||||
|
+++ b/src/main/java/net/minecraft/core/Vec3i.java
|
||||||
|
@@ -22,6 +22,15 @@ public class Vec3i implements Comparable<Vec3i> {
|
||||||
|
private int y;public final void setY(final int y) { this.y = y; } // Paper - OBFHELPER
|
||||||
|
private int z;public final void setZ(final int z) { this.z = z; } // Paper - OBFHELPER
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ public boolean isValidLocation() {
|
||||||
|
+ return getX() >= -30000000 && getZ() >= -30000000 && getX() < 30000000 && getZ() < 30000000 && getY() >= 0 && getY() < 256;
|
||||||
|
+ }
|
||||||
|
+ public boolean isInvalidYLocation() {
|
||||||
|
+ return y < 0 || y >= 256;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
public Vec3i(int x, int y, int z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index 799721ac63f0c08dd03a788b87eafa9a8cc976cc..24a6429059f58f51c97386ca2823ca0910288dec 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -239,7 +239,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isInWorldBounds(BlockPos pos) {
|
||||||
|
- return !isOutsideBuildHeight(pos) && isInWorldBoundsHorizontal(pos);
|
||||||
|
+ return pos.isValidLocation(); // Paper - use better/optimized check
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isInSpawnableBounds(BlockPos pos) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||||
|
index 3ca6289ba4952b5036367451b50cd90a78c0f938..e6303cdb433ee2b6782e2a0bd6b03e4f6ecb18ba 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||||
|
@@ -25,6 +25,7 @@ import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
|
public interface ChunkAccess extends BlockGetter, FeatureAccess {
|
||||||
|
|
||||||
|
+ BlockState getType(final int x, final int y, final int z); // Paper
|
||||||
|
@Nullable
|
||||||
|
BlockState setBlockState(BlockPos pos, BlockState state, boolean moved);
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java
|
||||||
|
index a26de06252207cf333ea4a8d73f0af6ddc239103..e369730ac6909ff5343468bd685c9ea2b6b3cfed 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java
|
||||||
|
@@ -23,7 +23,7 @@ import net.minecraft.world.phys.AABB;
|
||||||
|
|
||||||
|
public class EmptyLevelChunk extends LevelChunk {
|
||||||
|
|
||||||
|
- private static final Biome[] BIOMES = (Biome[]) Util.make((Object) (new Biome[ChunkBiomeContainer.BIOMES_SIZE]), (abiomebase) -> {
|
||||||
|
+ private static final Biome[] BIOMES = Util.make((new Biome[ChunkBiomeContainer.BIOMES_SIZE]), (abiomebase) -> { // Paper - decompile error
|
||||||
|
Arrays.fill(abiomebase, Biomes.PLAINS);
|
||||||
|
});
|
||||||
|
|
||||||
|
@@ -31,6 +31,11 @@ public class EmptyLevelChunk extends LevelChunk {
|
||||||
|
super(world, pos, new ChunkBiomeContainer(world.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), EmptyLevelChunk.BIOMES));
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ @Override public BlockState getType(int x, int y, int z) {
|
||||||
|
+ return Blocks.VOID_AIR.defaultBlockState();
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
@Override
|
||||||
|
public BlockState getBlockState(BlockPos pos) {
|
||||||
|
return Blocks.VOID_AIR.defaultBlockState();
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||||
|
index 04940ab2814cf39157d234dc4615646d7c760460..17fa8b23d1000ae53f2b4f1a6e8817c1005c1c81 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||||
|
@@ -42,6 +42,11 @@ public class ImposterProtoChunk extends ProtoChunk {
|
||||||
|
public BlockState getBlockState(BlockPos pos) {
|
||||||
|
return this.wrapped.getBlockState(pos);
|
||||||
|
}
|
||||||
|
+ // Paper start
|
||||||
|
+ public final BlockState getType(final int x, final int y, final int z) {
|
||||||
|
+ return this.wrapped.getBlockData(x, y, z);
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidState getFluidState(BlockPos pos) {
|
||||||
|
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 9ca05aa06696883adc8b67a68ca6d2d850e95d25..546fb2f42e6bf333582b504d0a29991698505df3 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
@@ -347,12 +347,27 @@ public class LevelChunk implements ChunkAccess {
|
||||||
|
return this.sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
- @Override
|
||||||
|
+ // Paper start - Optimize getBlockData to reduce instructions
|
||||||
|
+ public final BlockState getBlockData(BlockPos pos) { return getBlockData(pos.getX(), pos.getY(), pos.getZ()); } // Paper
|
||||||
|
public BlockState getBlockState(BlockPos pos) {
|
||||||
|
- int i = pos.getX();
|
||||||
|
- int j = pos.getY();
|
||||||
|
- int k = pos.getZ();
|
||||||
|
+ return this.getBlockData(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
+ }
|
||||||
|
|
||||||
|
+ public BlockState getType(final int x, final int y, final int z) {
|
||||||
|
+ return getBlockData(x, y, z);
|
||||||
|
+ }
|
||||||
|
+ public final BlockState getBlockData(final int x, final int y, final int z) {
|
||||||
|
+ // Method body / logic copied from below
|
||||||
|
+ final int i = y >> 4;
|
||||||
|
+ if (y < 0 || i >= this.sections.length || this.sections[i] == null || this.sections[i].nonEmptyBlockCount == 0) {
|
||||||
|
+ return Blocks.AIR.defaultBlockState();
|
||||||
|
+ }
|
||||||
|
+ // Inlined ChunkSection.getType() and DataPaletteBlock.a(int,int,int)
|
||||||
|
+ return this.sections[i].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public BlockState getBlockData_unused(int i, int j, int k) {
|
||||||
|
+ // Paper end
|
||||||
|
if (this.world.isDebug()) {
|
||||||
|
BlockState iblockdata = null;
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||||
|
index b54d82e0f41a03c91e0de8df8249a91da3c04d0e..f5db97fb0dac78e1d9aa68d0417aa13f39914f52 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||||
|
@@ -13,10 +13,10 @@ public class LevelChunkSection {
|
||||||
|
|
||||||
|
public static final Palette<BlockState> GLOBAL_BLOCKSTATE_PALETTE = new GlobalPalette<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState());
|
||||||
|
private final int bottomBlockY;
|
||||||
|
- private short nonEmptyBlockCount;
|
||||||
|
+ short nonEmptyBlockCount; // Paper - package-private
|
||||||
|
private short tickingBlockCount;
|
||||||
|
private short tickingFluidCount;
|
||||||
|
- private final PalettedContainer<BlockState> states;
|
||||||
|
+ final PalettedContainer<BlockState> states; // Paper - package-private
|
||||||
|
|
||||||
|
public LevelChunkSection(int yOffset) {
|
||||||
|
this(yOffset, (short) 0, (short) 0, (short) 0);
|
||||||
|
@@ -30,8 +30,8 @@ public class LevelChunkSection {
|
||||||
|
this.states = new PalettedContainer<>(LevelChunkSection.GLOBAL_BLOCKSTATE_PALETTE, Block.BLOCK_STATE_REGISTRY, NbtUtils::readBlockState, NbtUtils::writeBlockState, Blocks.AIR.defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
- public BlockState getBlockState(int x, int y, int z) {
|
||||||
|
- return (BlockState) this.states.get(x, y, z);
|
||||||
|
+ public final BlockState getBlockState(int x, int y, int z) { // Paper
|
||||||
|
+ return this.states.get(y << 8 | z << 4 | x); // Paper - inline
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidState getFluidState(int x, int y, int z) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||||
|
index d4db27421736f665739436c1ac4d3c6d5cae95cd..6d3dcd19ce1abc9d502903b8008949b5174a13c3 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||||
|
@@ -133,7 +133,7 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
||||||
|
}
|
||||||
|
|
||||||
|
public T get(int x, int y, int z) {
|
||||||
|
- return this.get(getIndex(x, y, z));
|
||||||
|
+ return this.get(y << 8 | z << 4 | x); // Paper - inline
|
||||||
|
}
|
||||||
|
|
||||||
|
protected T get(int index) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||||
|
index 7cd3f89004b0a64772fc3dfbdd132ba5a850b63e..d8b7b210484079c9ca2c34831c84102cba6692f5 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||||
|
@@ -113,16 +113,18 @@ public class ProtoChunk implements ChunkAccess {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getBlockState(BlockPos pos) {
|
||||||
|
- int i = pos.getY();
|
||||||
|
-
|
||||||
|
- if (Level.isOutsideBuildHeight(i)) {
|
||||||
|
+ return getType(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
+ }
|
||||||
|
+ // Paper start
|
||||||
|
+ public BlockState getType(final int x, final int y, final int z) {
|
||||||
|
+ if (y < 0 || y >= 256) {
|
||||||
|
return Blocks.VOID_AIR.defaultBlockState();
|
||||||
|
} else {
|
||||||
|
- LevelChunkSection chunksection = this.getSections()[i >> 4];
|
||||||
|
-
|
||||||
|
- return LevelChunkSection.isEmpty(chunksection) ? Blocks.AIR.defaultBlockState() : chunksection.getBlockState(pos.getX() & 15, i & 15, pos.getZ() & 15);
|
||||||
|
+ LevelChunkSection chunksection = this.getSections()[y >> 4];
|
||||||
|
+ return chunksection == LevelChunk.EMPTY_CHUNK_SECTION || chunksection.isEmpty() ? Blocks.AIR.defaultBlockState() : chunksection.getBlockState(x & 15, y & 15, z & 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidState getFluidState(BlockPos pos) {
|
|
@ -0,0 +1,95 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Mon, 28 Mar 2016 19:55:45 -0400
|
||||||
|
Subject: [PATCH] Only process BlockPhysicsEvent if a plugin has a listener
|
||||||
|
|
||||||
|
Saves on some object allocation and processing when no plugin listens to this
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index 901d5497667706c049718dc4fca37a1bc489c465..f7763a773bce4d8d947c8c859fe84d8a601034c5 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -1290,6 +1290,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
ServerLevel worldserver = (ServerLevel) iterator.next();
|
||||||
|
+ worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
|
||||||
|
|
||||||
|
this.profiler.push(() -> {
|
||||||
|
return worldserver + " " + worldserver.dimension().location();
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index 22c687e3db79bcfbc512ce3993d6e8a6db062360..8b0a384caa09848d61b3a6259dd56590cd52d0a0 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -190,6 +190,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||||
|
private int tickPosition;
|
||||||
|
public final LevelStorageSource.LevelStorageAccess convertable;
|
||||||
|
public final UUID uuid;
|
||||||
|
+ public boolean hasPhysicsEvent = true; // Paper
|
||||||
|
|
||||||
|
@Override public LevelChunk getChunkIfLoaded(int x, int z) { // Paper - this was added in world too but keeping here for NMS ABI
|
||||||
|
return this.chunkSource.getChunk(x, z, false);
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index 24a6429059f58f51c97386ca2823ca0910288dec..d47ed15382f98aabd509e32a3c202a91088adf6b 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -458,7 +458,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
// CraftBukkit start
|
||||||
|
iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam
|
||||||
|
CraftWorld world = ((ServerLevel) this).getWorld();
|
||||||
|
- if (world != null) {
|
||||||
|
+ if (world != null && ((ServerLevel)this).hasPhysicsEvent) { // Paper
|
||||||
|
BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata));
|
||||||
|
this.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
|
||||||
|
@@ -560,7 +560,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
try {
|
||||||
|
// CraftBukkit start
|
||||||
|
CraftWorld world = ((ServerLevel) this).getWorld();
|
||||||
|
- if (world != null) {
|
||||||
|
+ if (world != null && ((ServerLevel)this).hasPhysicsEvent) { // Paper
|
||||||
|
BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(sourcePos.getX(), sourcePos.getY(), sourcePos.getZ()), CraftBlockData.fromData(iblockdata), world.getBlockAt(neighborPos.getX(), neighborPos.getY(), neighborPos.getZ()));
|
||||||
|
this.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
|
||||||
|
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 d6cb341d4d8e20b77979a241dd2e4346455796d7..42635b6115187abeffb290ca040350fd97cf89f7 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/BushBlock.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/BushBlock.java
|
||||||
|
@@ -2,6 +2,7 @@ package net.minecraft.world.level.block;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
+import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
@@ -23,7 +24,7 @@ public class BushBlock extends Block {
|
||||||
|
public BlockState updateShape(BlockState state, Direction direction, BlockState newState, LevelAccessor world, BlockPos pos, BlockPos posFrom) {
|
||||||
|
// CraftBukkit start
|
||||||
|
if (!state.canSurvive(world, pos)) {
|
||||||
|
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) {
|
||||||
|
+ if (!(world instanceof ServerLevel && ((ServerLevel) world).hasPhysicsEvent) || !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) { // Paper
|
||||||
|
return Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
|
||||||
|
index db444689092f537dd736dc73c532bd540fadcf86..86c5025d1b21dc35782124eca66288c63626147a 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
|
||||||
|
@@ -3,6 +3,7 @@ package net.minecraft.world.level.block;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
+import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
@@ -83,7 +84,7 @@ public class DoublePlantBlock extends BushBlock {
|
||||||
|
|
||||||
|
protected static void preventCreativeDropFromBottomPart(Level world, BlockPos pos, BlockState state, Player player) {
|
||||||
|
// CraftBukkit start
|
||||||
|
- if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) {
|
||||||
|
+ if (((ServerLevel)world).hasPhysicsEvent && org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) { // Paper
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
|
@ -0,0 +1,27 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Mon, 28 Mar 2016 20:32:58 -0400
|
||||||
|
Subject: [PATCH] Entity AddTo/RemoveFrom World Events
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index 8b0a384caa09848d61b3a6259dd56590cd52d0a0..f7eddb39985072afeb79ec0cbfc084d7e84638e6 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -1208,7 +1208,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||||
|
if (entity instanceof Mob) {
|
||||||
|
this.navigations.remove(((Mob) entity).getNavigation());
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+ new com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid
|
||||||
|
entity.valid = false; // CraftBukkit
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1246,6 +1246,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||||
|
entity.origin = entity.getBukkitEntity().getLocation();
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
+ new com.destroystokyo.paper.event.entity.EntityAddToWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Mon, 28 Mar 2016 20:46:14 -0400
|
||||||
|
Subject: [PATCH] Configurable Chunk Inhabited Time
|
||||||
|
|
||||||
|
Vanilla stores how long a chunk has been active on a server, and dynamically scales some
|
||||||
|
aspects of vanilla gameplay to this factor.
|
||||||
|
|
||||||
|
For people who want all chunks to be treated equally, you can chose a fixed value.
|
||||||
|
|
||||||
|
This allows to fine-tune vanilla gameplay.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index cd64fb9d0c6d123e1c86cb33f12cd9cefc9f80d0..74ba5dbb83c13ce1721619b755036a7864a1fb90 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -238,4 +238,14 @@ public class PaperWorldConfig {
|
||||||
|
skeleHorseSpawnChance = 0.01D; // Vanilla value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public int fixedInhabitedTime;
|
||||||
|
+ private void fixedInhabitedTime() {
|
||||||
|
+ if (PaperConfig.version < 16) {
|
||||||
|
+ if (!config.getBoolean("world-settings.default.use-chunk-inhabited-timer", true)) config.set("world-settings.default.fixed-chunk-inhabited-time", 0);
|
||||||
|
+ if (!config.getBoolean("world-settings." + worldName + ".use-chunk-inhabited-timer", true)) config.set("world-settings." + worldName + ".fixed-chunk-inhabited-time", 0);
|
||||||
|
+ set("use-chunk-inhabited-timer", null);
|
||||||
|
+ }
|
||||||
|
+ fixedInhabitedTime = getInt("fixed-chunk-inhabited-time", -1);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
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 546fb2f42e6bf333582b504d0a29991698505df3..70f5b025c2b803df3de8a51cbcfafbe915866f42 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
@@ -1021,7 +1021,7 @@ public class LevelChunk implements ChunkAccess {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getInhabitedTime() {
|
||||||
|
- return this.inhabitedTime;
|
||||||
|
+ return world.paperConfig.fixedInhabitedTime < 0 ? this.inhabitedTime : world.paperConfig.fixedInhabitedTime; // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
125
Remapped-Spigot-Server-Patches/0075-EntityPathfindEvent.patch
Normal file
125
Remapped-Spigot-Server-Patches/0075-EntityPathfindEvent.patch
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Mon, 28 Mar 2016 21:22:26 -0400
|
||||||
|
Subject: [PATCH] EntityPathfindEvent
|
||||||
|
|
||||||
|
Fires when an Entity decides to start moving to a location.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
|
||||||
|
index 0af2c5dde41043a6fb2fcd07db96288c7f96e0c7..5e7e678c4469e34c7ae39656f547243fbcf1d0da 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
|
||||||
|
@@ -37,7 +37,7 @@ public class FlyingPathNavigation extends PathNavigation {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path createPath(Entity entity, int distance) {
|
||||||
|
- return this.createPath(entity.blockPosition(), distance);
|
||||||
|
+ return this.a(entity.blockPosition(), entity, distance); // Paper - Forward target entity
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
|
||||||
|
index cd7cb7cbe55a36282de394efc95f4ba7cc6a75cf..01be1de9d9ca0a86d69b2e82693bd0fea61a969f 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
|
||||||
|
@@ -75,7 +75,7 @@ public class GroundPathNavigation extends PathNavigation {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path createPath(Entity entity, int distance) {
|
||||||
|
- return this.createPath(entity.blockPosition(), distance);
|
||||||
|
+ return this.a(entity.blockPosition(), entity, distance); // Paper - Forward target entity
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSurfaceY() {
|
||||||
|
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 3cfd913e31236e35e7225ba19d292cacb8b4134a..ae8d430382b20ddd837c47e39515c7995f25312a 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
|
||||||
|
@@ -10,6 +10,7 @@ import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Position;
|
||||||
|
import net.minecraft.core.Vec3i;
|
||||||
|
import net.minecraft.network.protocol.game.DebugPackets;
|
||||||
|
+import net.minecraft.server.MCUtil;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
@@ -28,7 +29,7 @@ import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public abstract class PathNavigation {
|
||||||
|
|
||||||
|
- protected final Mob mob;
|
||||||
|
+ protected final Mob mob; public Entity getEntity() { return mob; } // Paper - OBFHELPER
|
||||||
|
protected final Level level;
|
||||||
|
@Nullable
|
||||||
|
protected Path path;
|
||||||
|
@@ -115,36 +116,63 @@ public abstract class PathNavigation {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Path createPath(BlockPos target, int distance) {
|
||||||
|
- return this.createPath(ImmutableSet.of(target), 8, false, distance);
|
||||||
|
+ // Paper start - add target parameter
|
||||||
|
+ return this.a(target, null, distance);
|
||||||
|
+ }
|
||||||
|
+ @Nullable public Path a(BlockPos blockposition, Entity target, int i) {
|
||||||
|
+ return this.a(ImmutableSet.of(blockposition), target, 8, false, i);
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Path createPath(Entity entity, int distance) {
|
||||||
|
- return this.createPath(ImmutableSet.of(entity.blockPosition()), 16, true, distance);
|
||||||
|
+ return this.a(ImmutableSet.of(entity.blockPosition()), entity, 16, true, distance); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
+ // Paper start - Add target
|
||||||
|
protected Path createPath(Set<BlockPos> positions, int range, boolean flag, int distance) {
|
||||||
|
- if (positions.isEmpty()) {
|
||||||
|
+ return this.a(positions, null, range, flag, distance);
|
||||||
|
+ }
|
||||||
|
+ @Nullable protected Path a(Set<BlockPos> set, Entity target, int i, boolean flag, int j) {
|
||||||
|
+ // Paper end
|
||||||
|
+ if (set.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
} else if (this.mob.getY() < 0.0D) {
|
||||||
|
return null;
|
||||||
|
} else if (!this.canUpdatePath()) {
|
||||||
|
return null;
|
||||||
|
- } else if (this.path != null && !this.path.isDone() && positions.contains(this.targetPos)) {
|
||||||
|
+ } else if (this.path != null && !this.path.isDone() && set.contains(this.targetPos)) {
|
||||||
|
return this.path;
|
||||||
|
} else {
|
||||||
|
+ // Paper start - Pathfind event
|
||||||
|
+ boolean copiedSet = false;
|
||||||
|
+ for (BlockPos possibleTarget : set) {
|
||||||
|
+ if (!new com.destroystokyo.paper.event.entity.EntityPathfindEvent(getEntity().getBukkitEntity(),
|
||||||
|
+ MCUtil.toLocation(getEntity().level, possibleTarget), target == null ? null : target.getBukkitEntity()).callEvent()) {
|
||||||
|
+ if (!copiedSet) {
|
||||||
|
+ copiedSet = true;
|
||||||
|
+ set = new java.util.HashSet<>(set);
|
||||||
|
+ }
|
||||||
|
+ // note: since we copy the set this remove call is safe, since we're iterating over the old copy
|
||||||
|
+ set.remove(possibleTarget);
|
||||||
|
+ if (set.isEmpty()) {
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
this.level.getProfiler().push("pathfind");
|
||||||
|
float f = (float) this.mob.getAttributeValue(Attributes.FOLLOW_RANGE);
|
||||||
|
BlockPos blockposition = flag ? this.mob.blockPosition().above() : this.mob.blockPosition();
|
||||||
|
- int k = (int) (f + (float) range);
|
||||||
|
+ int k = (int) (f + (float) i);
|
||||||
|
PathNavigationRegion chunkcache = new PathNavigationRegion(this.level, blockposition.offset(-k, -k, -k), blockposition.offset(k, k, k));
|
||||||
|
- Path pathentity = this.pathFinder.findPath(chunkcache, this.mob, positions, f, distance, this.maxVisitedNodesMultiplier);
|
||||||
|
+ Path pathentity = this.pathFinder.findPath(chunkcache, this.mob, set, f, j, this.maxVisitedNodesMultiplier);
|
||||||
|
|
||||||
|
this.level.getProfiler().pop();
|
||||||
|
if (pathentity != null && pathentity.getTarget() != null) {
|
||||||
|
this.targetPos = pathentity.getTarget();
|
||||||
|
- this.reachRange = distance;
|
||||||
|
+ this.reachRange = j;
|
||||||
|
this.resetStuckTimeout();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Antony Riley <antony@cyberiantiger.org>
|
||||||
|
Date: Tue, 29 Mar 2016 08:22:55 +0300
|
||||||
|
Subject: [PATCH] Sanitise RegionFileCache and make configurable.
|
||||||
|
|
||||||
|
RegionFileCache prior to this patch would close every single open region
|
||||||
|
file upon reaching a size of 256.
|
||||||
|
This patch modifies that behaviour so it closes the the least recently
|
||||||
|
used RegionFile.
|
||||||
|
The implementation uses a LinkedHashMap as an LRU cache (modified from HashMap).
|
||||||
|
The maximum size of the RegionFileCache is also made configurable.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
index 716f285e67019b8a62922d09c15883c99f9421aa..439dcc6effdc91830d2b7ede9063982998b37120 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
@@ -227,4 +227,9 @@ public class PaperConfig {
|
||||||
|
private static void loadPermsBeforePlugins() {
|
||||||
|
loadPermsBeforePlugins = getBoolean("settings.load-permissions-yml-before-plugins", true);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public static int regionFileCacheSize = 256;
|
||||||
|
+ private static void regionFileCacheSize() {
|
||||||
|
+ regionFileCacheSize = Math.max(getInt("settings.region-file-cache-size", 256), 4);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
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 97a58da9d64d812942ceb71426d35b490bbbe817..f33a5fc725d1d5e895f8878d82ebc4172237ad29 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
|
||||||
|
@@ -33,7 +33,7 @@ public final class RegionFileStorage implements AutoCloseable {
|
||||||
|
if (regionfile != null) {
|
||||||
|
return regionfile;
|
||||||
|
} else {
|
||||||
|
- if (this.regionCache.size() >= 256) {
|
||||||
|
+ if (this.regionCache.size() >= com.destroystokyo.paper.PaperConfig.regionFileCacheSize) { // Paper - configurable
|
||||||
|
((RegionFile) this.regionCache.removeLast()).close();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Thu, 31 Mar 2016 19:17:58 -0400
|
||||||
|
Subject: [PATCH] Do not load chunks for Pathfinding
|
||||||
|
|
||||||
|
|
||||||
|
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 ae8d430382b20ddd837c47e39515c7995f25312a..25bc3adfad956157cef0953e6e632b7b7e352f3a 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
|
||||||
|
@@ -48,7 +48,7 @@ public abstract class PathNavigation {
|
||||||
|
private BlockPos targetPos;
|
||||||
|
private int reachRange;
|
||||||
|
private float maxVisitedNodesMultiplier;
|
||||||
|
- private final PathFinder pathFinder;
|
||||||
|
+ private final PathFinder pathFinder; public PathFinder getPathfinder() { return this.pathFinder; } // Paper - OBFHELPER
|
||||||
|
private boolean isStuck;
|
||||||
|
|
||||||
|
public PathNavigation(Mob mob, Level world) {
|
||||||
|
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 99f3f0b895295229b75d93e98141c0cd75789b69..ba8ee93032aabe7ec4ecf52d452e1a580d6ebc20 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||||
|
@@ -20,7 +20,7 @@ public class PathFinder {
|
||||||
|
|
||||||
|
private final Node[] neighbors = new Node[32];
|
||||||
|
private final int maxVisitedNodes;
|
||||||
|
- private final NodeEvaluator nodeEvaluator;
|
||||||
|
+ private final NodeEvaluator nodeEvaluator; public NodeEvaluator getPathfinder() { return this.nodeEvaluator; } // Paper - OBFHELPER
|
||||||
|
private final BinaryHeap openSet = new BinaryHeap();
|
||||||
|
|
||||||
|
public PathFinder(NodeEvaluator pathNodeMaker, int range) {
|
||||||
|
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 0b378348cb9e9576e2a209e651264e2caccfd182..7ae24381b91c282745b7fe5f6897865e74bc0acf 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
||||||
|
@@ -479,7 +479,12 @@ public class WalkNodeEvaluator extends NodeEvaluator {
|
||||||
|
for (int j1 = -1; j1 <= 1; ++j1) {
|
||||||
|
if (l != 0 || j1 != 0) {
|
||||||
|
blockposition_mutableblockposition.set(i + l, j + i1, k + j1);
|
||||||
|
- BlockState iblockdata = iblockaccess.getBlockState(blockposition_mutableblockposition);
|
||||||
|
+ // Paper start
|
||||||
|
+ BlockState iblockdata = iblockaccess.getTypeIfLoaded(blockposition_mutableblockposition);
|
||||||
|
+ if (iblockdata == null) {
|
||||||
|
+ pathtype = BlockPathTypes.BLOCKED;
|
||||||
|
+ } else {
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
if (iblockdata.is(Blocks.CACTUS)) {
|
||||||
|
return BlockPathTypes.DANGER_CACTUS;
|
||||||
|
@@ -496,6 +501,7 @@ public class WalkNodeEvaluator extends NodeEvaluator {
|
||||||
|
if (iblockaccess.getFluidState(blockposition_mutableblockposition).is((Tag) FluidTags.WATER)) {
|
||||||
|
return BlockPathTypes.WATER_BORDER;
|
||||||
|
}
|
||||||
|
+ } // Paper
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -505,7 +511,8 @@ public class WalkNodeEvaluator extends NodeEvaluator {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static BlockPathTypes getBlockPathTypeRaw(BlockGetter iblockaccess, BlockPos blockposition) {
|
||||||
|
- BlockState iblockdata = iblockaccess.getBlockState(blockposition);
|
||||||
|
+ BlockState iblockdata = iblockaccess.getTypeIfLoaded(blockposition); // Paper
|
||||||
|
+ if (iblockdata == null) return BlockPathTypes.BLOCKED; // Paper
|
||||||
|
Block block = iblockdata.getBlock();
|
||||||
|
Material material = iblockdata.getMaterial();
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jedediah Smith <jedediah@silencegreys.com>
|
||||||
|
Date: Sat, 2 Apr 2016 05:09:16 -0400
|
||||||
|
Subject: [PATCH] Add PlayerUseUnknownEntityEvent
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java
|
||||||
|
index 9ff5b938f97da5ca1f13fd2bcbf3d13e8b8f760c..e1d219550006d22b0a8e949e820488c6ed96dc58 100644
|
||||||
|
--- a/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java
|
||||||
|
+++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java
|
||||||
|
@@ -11,7 +11,7 @@ import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public class ServerboundInteractPacket implements Packet<ServerGamePacketListener> {
|
||||||
|
|
||||||
|
- private int entityId;
|
||||||
|
+ private int entityId; public int getEntityId() { return this.entityId; } // Paper - add accessor
|
||||||
|
private ServerboundInteractPacket.Action action;
|
||||||
|
private Vec3 location;
|
||||||
|
private InteractionHand hand;
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
index 73683ba59d0aff3a61f555b4ae15753e9e4e6141..e2bfe8e916c9e59af81627ea0ee449970527034d 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
@@ -2198,6 +2198,16 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ // Paper start - fire event
|
||||||
|
+ else {
|
||||||
|
+ this.craftServer.getPluginManager().callEvent(new com.destroystokyo.paper.event.player.PlayerUseUnknownEntityEvent(
|
||||||
|
+ this.getPlayer(),
|
||||||
|
+ packet.getEntityId(),
|
||||||
|
+ packet.getAction() == ServerboundInteractPacket.Action.ATTACK,
|
||||||
|
+ packet.getHand() == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND
|
||||||
|
+ ));
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jedediah Smith <jedediah@silencegreys.com>
|
||||||
|
Date: Sat, 2 Apr 2016 20:37:03 -0400
|
||||||
|
Subject: [PATCH] Fix reducedDebugInfo not initialized on client
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||||
|
index a63babe123fad398b07685ec57cd88756435457c..aa440a6341a6d30aba8fd5f6bcd122bd5d8760cd 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||||
|
@@ -242,6 +242,7 @@ public abstract class PlayerList {
|
||||||
|
playerconnection.send(new ClientboundSetCarriedItemPacket(player.inventory.selected));
|
||||||
|
playerconnection.send(new ClientboundUpdateRecipesPacket(this.server.getRecipeManager().getRecipes()));
|
||||||
|
playerconnection.send(new ClientboundUpdateTagsPacket(this.server.getTags()));
|
||||||
|
+ playerconnection.send(new ClientboundEntityEventPacket(player, (byte) (worldserver1.getGameRules().getBoolean(GameRules.RULE_REDUCEDDEBUGINFO) ? 22 : 23))); // Paper - fix this rule not being initialized on the client
|
||||||
|
this.sendPlayerPermissionLevel(player);
|
||||||
|
player.getStats().markAllDirty();
|
||||||
|
player.getRecipeBook().sendInitialRecipeBook(player);
|
|
@ -0,0 +1,41 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Sun, 3 Apr 2016 16:28:17 -0400
|
||||||
|
Subject: [PATCH] Configurable Grass Spread Tick Rate
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 74ba5dbb83c13ce1721619b755036a7864a1fb90..db2dddd12f54e6d15916c4cee623676541de37fb 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -248,4 +248,10 @@ public class PaperWorldConfig {
|
||||||
|
}
|
||||||
|
fixedInhabitedTime = getInt("fixed-chunk-inhabited-time", -1);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public int grassUpdateRate = 1;
|
||||||
|
+ private void grassUpdateRate() {
|
||||||
|
+ grassUpdateRate = Math.max(0, getInt("grass-spread-tick-rate", grassUpdateRate));
|
||||||
|
+ log("Grass Spread Tick Rate: " + grassUpdateRate);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||||
|
index d54f097afc455a01486d7f7459b0cfc4ab4f3970..813a5b0598eca28aa173cd6e34bc16381f313604 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||||
|
@@ -3,6 +3,7 @@ package net.minecraft.world.level.block;
|
||||||
|
import java.util.Random;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.tags.FluidTags;
|
||||||
|
import net.minecraft.tags.Tag;
|
||||||
|
@@ -41,6 +42,7 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||||
|
+ if (this instanceof GrassBlock && world.paperConfig.grassUpdateRate != 1 && (world.paperConfig.grassUpdateRate < 1 || (MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig.grassUpdateRate != 0)) { return; } // Paper
|
||||||
|
if (!canBeGrass(state, (LevelReader) world, pos)) {
|
||||||
|
// CraftBukkit start
|
||||||
|
if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) {
|
|
@ -0,0 +1,18 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Sun, 3 Apr 2016 17:48:50 -0400
|
||||||
|
Subject: [PATCH] Fix Cancelling BlockPlaceEvent triggering physics
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index d47ed15382f98aabd509e32a3c202a91088adf6b..89a6a0b4235cfcc1d3ad68ff59a21fa60df4508f 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -518,6 +518,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
public void setBlocksDirty(BlockPos pos, BlockState old, BlockState updated) {}
|
||||||
|
|
||||||
|
public void updateNeighborsAt(BlockPos pos, Block block) {
|
||||||
|
+ if (captureBlockStates) { return; } // Paper - Cancel all physics during placement
|
||||||
|
this.neighborChanged(pos.west(), block, pos);
|
||||||
|
this.neighborChanged(pos.east(), block, pos);
|
||||||
|
this.neighborChanged(pos.below(), block, pos);
|
84
Remapped-Spigot-Server-Patches/0082-Optimize-DataBits.patch
Normal file
84
Remapped-Spigot-Server-Patches/0082-Optimize-DataBits.patch
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Tue, 5 Apr 2016 21:38:58 -0400
|
||||||
|
Subject: [PATCH] Optimize DataBits
|
||||||
|
|
||||||
|
Remove Debug checks as these are super hot and causing noticeable hits
|
||||||
|
|
||||||
|
Before: http://i.imgur.com/nQsMzAE.png
|
||||||
|
After: http://i.imgur.com/nJ46crB.png
|
||||||
|
|
||||||
|
Optimize redundant converting of static fields into an unsigned long each call by precomputing it in ctor
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/util/BitStorage.java b/src/main/java/net/minecraft/util/BitStorage.java
|
||||||
|
index 97bde5f8402452e59b0da94edfe1b970cdb86748..dd84984f28484cf7129c294222696784e128221a 100644
|
||||||
|
--- a/src/main/java/net/minecraft/util/BitStorage.java
|
||||||
|
+++ b/src/main/java/net/minecraft/util/BitStorage.java
|
||||||
|
@@ -13,8 +13,8 @@ public class BitStorage {
|
||||||
|
private final long mask;
|
||||||
|
private final int size;
|
||||||
|
private final int valuesPerLong;
|
||||||
|
- private final int divideMul;
|
||||||
|
- private final int divideAdd;
|
||||||
|
+ private final int divideMul;private final long g_unsigned; // Paper - referenced in b(int) with 2 Integer.toUnsignedLong calls
|
||||||
|
+ private final int divideAdd;private final long h_unsigned; // Paper
|
||||||
|
private final int divideShift;
|
||||||
|
|
||||||
|
public BitStorage(int elementBits, int size) {
|
||||||
|
@@ -29,8 +29,8 @@ public class BitStorage {
|
||||||
|
this.valuesPerLong = (char) (64 / elementBits);
|
||||||
|
int k = 3 * (this.valuesPerLong - 1);
|
||||||
|
|
||||||
|
- this.divideMul = BitStorage.MAGIC[k + 0];
|
||||||
|
- this.divideAdd = BitStorage.MAGIC[k + 1];
|
||||||
|
+ this.divideMul = BitStorage.MAGIC[k + 0]; this.g_unsigned = Integer.toUnsignedLong(this.divideMul); // Paper
|
||||||
|
+ this.divideAdd = BitStorage.MAGIC[k + 1]; this.h_unsigned = Integer.toUnsignedLong(this.divideAdd); // Paper
|
||||||
|
this.divideShift = BitStorage.MAGIC[k + 2];
|
||||||
|
int l = (size + this.valuesPerLong - 1) / this.valuesPerLong;
|
||||||
|
|
||||||
|
@@ -47,15 +47,15 @@ public class BitStorage {
|
||||||
|
}
|
||||||
|
|
||||||
|
private int cellIndex(int i) {
|
||||||
|
- long j = Integer.toUnsignedLong(this.divideMul);
|
||||||
|
- long k = Integer.toUnsignedLong(this.divideAdd);
|
||||||
|
+ //long j = Integer.toUnsignedLong(this.g); // Paper
|
||||||
|
+ //long k = Integer.toUnsignedLong(this.h); // Paper
|
||||||
|
|
||||||
|
- return (int) ((long) i * j + k >> 32 >> this.divideShift);
|
||||||
|
+ return (int) ((long) i * this.g_unsigned + this.h_unsigned >> 32 >> this.divideShift); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
- public int getAndSet(int index, int value) {
|
||||||
|
- Validate.inclusiveBetween(0L, (long) (this.size - 1), (long) index);
|
||||||
|
- Validate.inclusiveBetween(0L, this.mask, (long) value);
|
||||||
|
+ public final int getAndSet(int index, int value) { // Paper - make final for inline
|
||||||
|
+ //Validate.inclusiveBetween(0L, (long) (this.e - 1), (long) i); // Paper
|
||||||
|
+ //Validate.inclusiveBetween(0L, this.d, (long) j); // Paper
|
||||||
|
int k = this.cellIndex(index);
|
||||||
|
long l = this.data[k];
|
||||||
|
int i1 = (index - k * this.valuesPerLong) * this.bits;
|
||||||
|
@@ -65,9 +65,9 @@ public class BitStorage {
|
||||||
|
return j1;
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void set(int index, int value) {
|
||||||
|
- Validate.inclusiveBetween(0L, (long) (this.size - 1), (long) index);
|
||||||
|
- Validate.inclusiveBetween(0L, this.mask, (long) value);
|
||||||
|
+ public final void set(int index, int value) { // Paper - make final for inline
|
||||||
|
+ //Validate.inclusiveBetween(0L, (long) (this.e - 1), (long) i); // Paper
|
||||||
|
+ //Validate.inclusiveBetween(0L, this.d, (long) j); // Paper
|
||||||
|
int k = this.cellIndex(index);
|
||||||
|
long l = this.data[k];
|
||||||
|
int i1 = (index - k * this.valuesPerLong) * this.bits;
|
||||||
|
@@ -75,8 +75,8 @@ public class BitStorage {
|
||||||
|
this.data[k] = l & ~(this.mask << i1) | ((long) value & this.mask) << i1;
|
||||||
|
}
|
||||||
|
|
||||||
|
- public int get(int index) {
|
||||||
|
- Validate.inclusiveBetween(0L, (long) (this.size - 1), (long) index);
|
||||||
|
+ public final int get(int index) { // Paper - make final for inline
|
||||||
|
+ //Validate.inclusiveBetween(0L, (long) (this.e - 1), (long) i); // Paper
|
||||||
|
int j = this.cellIndex(index);
|
||||||
|
long k = this.data[j];
|
||||||
|
int l = (index - j * this.valuesPerLong) * this.bits;
|
|
@ -0,0 +1,66 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Wed, 6 Apr 2016 01:04:23 -0500
|
||||||
|
Subject: [PATCH] Option to use vanilla per-world scoreboard coloring on names
|
||||||
|
|
||||||
|
This change is basically a bandaid to fix CB's complete and utter lack
|
||||||
|
of support for vanilla scoreboard name modifications.
|
||||||
|
|
||||||
|
In the future, finding a way to merge the vanilla expectations in with
|
||||||
|
bukkit's concept of a display name would be preferable. There was a PR
|
||||||
|
for this on CB at one point but I can't find it. We may need to do this
|
||||||
|
ourselves at some point in the future.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index db2dddd12f54e6d15916c4cee623676541de37fb..1942f5224aaebb18adb591d6f70a419cfc1a7bdd 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -254,4 +254,9 @@ public class PaperWorldConfig {
|
||||||
|
grassUpdateRate = Math.max(0, getInt("grass-spread-tick-rate", grassUpdateRate));
|
||||||
|
log("Grass Spread Tick Rate: " + grassUpdateRate);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean useVanillaScoreboardColoring;
|
||||||
|
+ private void useVanillaScoreboardColoring() {
|
||||||
|
+ useVanillaScoreboardColoring = getBoolean("use-vanilla-world-scoreboard-name-coloring", false);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
|
||||||
|
index a29b6aaafd529e56a83dd96c32211f21e4aad348..2039f83a718427d0969a1a2e2200f7922097449e 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
|
||||||
|
@@ -16,7 +16,11 @@ import net.kyori.adventure.text.TextReplacementConfig;
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
+import net.minecraft.world.scores.PlayerTeam;
|
||||||
|
+import net.minecraft.world.scores.Team;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
+import org.bukkit.ChatColor;
|
||||||
|
+import org.bukkit.craftbukkit.CraftWorld;
|
||||||
|
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.util.LazyPlayerSet;
|
||||||
|
import org.bukkit.craftbukkit.util.Waitable;
|
||||||
|
@@ -178,10 +182,22 @@ public final class ChatProcessor {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String legacyDisplayName(final CraftPlayer player) {
|
||||||
|
+ if (((CraftWorld) player.getWorld()).getHandle().paperConfig.useVanillaScoreboardColoring) {
|
||||||
|
+ final ServerPlayer ep = player.getHandle();
|
||||||
|
+ net.minecraft.network.chat.Component name = ep.getName();
|
||||||
|
+ final Team team = ep.getTeam();
|
||||||
|
+ if (team != null) {
|
||||||
|
+ name = team.getFormattedName(name);
|
||||||
|
+ }
|
||||||
|
+ return PaperAdventure.LEGACY_SECTION_UXRC.serialize(PaperAdventure.asAdventure(name)) + ChatColor.RESET;
|
||||||
|
+ }
|
||||||
|
return player.getDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Component displayName(final CraftPlayer player) {
|
||||||
|
+ if (((CraftWorld) player.getWorld()).getHandle().paperConfig.useVanillaScoreboardColoring) {
|
||||||
|
+ return PaperAdventure.asAdventure(PlayerTeam.formatNameForTeam(player.getHandle().getTeam(), player.getHandle().getName()));
|
||||||
|
+ }
|
||||||
|
return player.displayName();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Sun, 10 Apr 2016 03:23:32 -0500
|
||||||
|
Subject: [PATCH] Workaround for setting passengers on players
|
||||||
|
|
||||||
|
SPIGOT-1915 & GH-114
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
index b7d5a718375083a4162df4bb41de3acd57b297fb..b264cbe5f91da9e31c5fd00ee285735a19aaad35 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
@@ -870,6 +870,17 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start - Ugly workaround for SPIGOT-1915 & GH-114
|
||||||
|
+ @Override
|
||||||
|
+ public boolean setPassenger(org.bukkit.entity.Entity passenger) {
|
||||||
|
+ boolean wasSet = super.setPassenger(passenger);
|
||||||
|
+ if (wasSet) {
|
||||||
|
+ this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundSetPassengersPacket(this.getHandle()));
|
||||||
|
+ }
|
||||||
|
+ return wasSet;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public void setSneaking(boolean sneak) {
|
||||||
|
getHandle().setShiftKeyDown(sneak);
|
|
@ -0,0 +1,90 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Wed, 13 Apr 2016 00:25:28 -0400
|
||||||
|
Subject: [PATCH] Remove unused World Tile Entity List
|
||||||
|
|
||||||
|
Massive hit to performance and it is completely unnecessary.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index f7eddb39985072afeb79ec0cbfc084d7e84638e6..bb99d9fe5e274318d8480a6de2c45b0a57351f77 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -1715,7 +1715,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferedwriter.write(String.format("entities: %d\n", this.entitiesById.size()));
|
||||||
|
- bufferedwriter.write(String.format("block_entities: %d\n", this.blockEntityList.size()));
|
||||||
|
+ bufferedwriter.write(String.format("block_entities: %d\n", this.tickableBlockEntities.size())); // Paper - remove unused list
|
||||||
|
bufferedwriter.write(String.format("block_ticks: %d\n", this.getBlockTicks().size()));
|
||||||
|
bufferedwriter.write(String.format("fluid_ticks: %d\n", this.getLiquidTicks().size()));
|
||||||
|
bufferedwriter.write("distance_manager: " + playerchunkmap.getDistanceManager().getDebugStatus() + "\n");
|
||||||
|
@@ -1854,7 +1854,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||||
|
|
||||||
|
private void dumpBlockEntities(Writer writer) throws IOException {
|
||||||
|
CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("y").addColumn("z").addColumn("type").build(writer);
|
||||||
|
- Iterator iterator = this.blockEntityList.iterator();
|
||||||
|
+ Iterator iterator = this.tickableBlockEntities.iterator(); // Paper - remove unused list
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
BlockEntity tileentity = (BlockEntity) iterator.next();
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index 89a6a0b4235cfcc1d3ad68ff59a21fa60df4508f..8f0fec38b482465285057d3fd27d456cf036f2fd 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -91,7 +91,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
public static final ResourceKey<Level> NETHER = ResourceKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation("the_nether"));
|
||||||
|
public static final ResourceKey<Level> END = ResourceKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation("the_end"));
|
||||||
|
private static final Direction[] DIRECTIONS = Direction.values();
|
||||||
|
- public final List<BlockEntity> blockEntityList = Lists.newArrayList();
|
||||||
|
+ //public final List<TileEntity> tileEntityList = Lists.newArrayList(); // Paper - remove unused list
|
||||||
|
public final List<BlockEntity> tickableBlockEntities = Lists.newArrayList();
|
||||||
|
protected final List<BlockEntity> pendingBlockEntities = Lists.newArrayList();
|
||||||
|
protected final java.util.Set<BlockEntity> tileEntityListUnload = com.google.common.collect.Sets.newHashSet();
|
||||||
|
@@ -683,9 +683,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
}, blockEntity::getBlockPos});
|
||||||
|
}
|
||||||
|
|
||||||
|
- boolean flag = this.blockEntityList.add(blockEntity);
|
||||||
|
+ boolean flag = true; // Paper - remove unused list
|
||||||
|
|
||||||
|
- if (flag && blockEntity instanceof TickableBlockEntity) {
|
||||||
|
+ if (flag && blockEntity instanceof TickableBlockEntity && !this.tickableBlockEntities.contains(blockEntity)) { // Paper
|
||||||
|
this.tickableBlockEntities.add(blockEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -721,7 +721,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
timings.tileEntityTick.startTiming(); // Spigot
|
||||||
|
if (!this.tileEntityListUnload.isEmpty()) {
|
||||||
|
this.tickableBlockEntities.removeAll(this.tileEntityListUnload);
|
||||||
|
- this.blockEntityList.removeAll(this.tileEntityListUnload);
|
||||||
|
+ //this.tileEntityList.removeAll(this.tileEntityListUnload); // Paper - remove unused list
|
||||||
|
this.tileEntityListUnload.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -781,7 +781,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
tilesThisCycle--;
|
||||||
|
this.tickableBlockEntities.remove(tileTickPosition--);
|
||||||
|
// Spigot end
|
||||||
|
- this.blockEntityList.remove(tileentity);
|
||||||
|
+ //this.tileEntityList.remove(tileentity); // Paper - remove unused list
|
||||||
|
if (this.hasChunkAt(tileentity.getBlockPos())) {
|
||||||
|
this.getChunkAt(tileentity.getBlockPos()).removeBlockEntity(tileentity.getBlockPos());
|
||||||
|
}
|
||||||
|
@@ -811,7 +811,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
this.sendBlockUpdated(tileentity1.getBlockPos(), iblockdata, iblockdata, 3);
|
||||||
|
// CraftBukkit start
|
||||||
|
// From above, don't screw this up - SPIGOT-1746
|
||||||
|
- if (!this.blockEntityList.contains(tileentity1)) {
|
||||||
|
+ if (true) { // Paper - remove unused list
|
||||||
|
this.addBlockEntity(tileentity1);
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
@@ -957,7 +957,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
} else {
|
||||||
|
if (tileentity != null) {
|
||||||
|
this.pendingBlockEntities.remove(tileentity);
|
||||||
|
- this.blockEntityList.remove(tileentity);
|
||||||
|
+ //this.tileEntityList.remove(tileentity); // Paper - remove unused list
|
||||||
|
this.tickableBlockEntities.remove(tileentity);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Wed, 13 Apr 2016 00:30:10 -0400
|
||||||
|
Subject: [PATCH] Don't tick Skulls - unused code
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java
|
||||||
|
index 6a46517e4026971d8c050c685c710883b5976fa3..eebaeaccc3ba1a9ec089d84b8de6c9d36034868f 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java
|
||||||
|
@@ -31,7 +31,7 @@ import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.players.GameProfileCache;
|
||||||
|
import net.minecraft.util.StringUtil;
|
||||||
|
|
||||||
|
-public class SkullBlockEntity extends BlockEntity implements TickableBlockEntity {
|
||||||
|
+public class SkullBlockEntity extends BlockEntity /*implements ITickable*/ { // Paper - remove tickable
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static GameProfileCache profileCache;
|
||||||
|
@@ -134,7 +134,7 @@ public class SkullBlockEntity extends BlockEntity implements TickableBlockEntity
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- @Override
|
||||||
|
+ // Paper - remove override
|
||||||
|
public void tick() {
|
||||||
|
BlockState iblockdata = this.getBlockState();
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Wed, 13 Apr 2016 02:10:49 -0400
|
||||||
|
Subject: [PATCH] Configurable Player Collision
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
index 439dcc6effdc91830d2b7ede9063982998b37120..504efea7b6f50a0d17f4f353781953dfb18bdeca 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
@@ -232,4 +232,9 @@ public class PaperConfig {
|
||||||
|
private static void regionFileCacheSize() {
|
||||||
|
regionFileCacheSize = Math.max(getInt("settings.region-file-cache-size", 256), 4);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public static boolean enablePlayerCollisions = true;
|
||||||
|
+ private static void enablePlayerCollisions() {
|
||||||
|
+ enablePlayerCollisions = getBoolean("settings.enable-player-collisions", true);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
|
||||||
|
index 53f284b720d97ba8ce8fac90bc26e7930dcec6b2..d70e7079ea2c84edbc2a8501f115194e2a4ef2e4 100644
|
||||||
|
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
|
||||||
|
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
|
||||||
|
@@ -112,7 +112,7 @@ public class ClientboundSetPlayerTeamPacket implements Packet<ClientGamePacketLi
|
||||||
|
buf.writeComponent(this.displayName);
|
||||||
|
buf.writeByte(this.options);
|
||||||
|
buf.writeUtf(this.nametagVisibility);
|
||||||
|
- buf.writeUtf(this.collisionRule);
|
||||||
|
+ buf.writeUtf(!com.destroystokyo.paper.PaperConfig.enablePlayerCollisions ? "never" : this.collisionRule); // Paper
|
||||||
|
buf.writeEnum((Enum) this.color);
|
||||||
|
buf.writeComponent(this.playerPrefix);
|
||||||
|
buf.writeComponent(this.playerSuffix);
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index f7763a773bce4d8d947c8c859fe84d8a601034c5..d639ead95c36985fa0f5a9c51898c4237e373f0e 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -150,6 +150,7 @@ import net.minecraft.world.level.storage.loot.LootTables;
|
||||||
|
import net.minecraft.world.level.storage.loot.PredicateManager;
|
||||||
|
import net.minecraft.world.phys.Vec2;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
+import net.minecraft.world.scores.PlayerTeam;
|
||||||
|
import net.minecraft.world.scores.Scoreboard;
|
||||||
|
import net.minecraft.world.scores.ScoreboardSaveData;
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
|
@@ -549,6 +550,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(worldserver.getWorld()));
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start - Handle collideRule team for player collision toggle
|
||||||
|
+ final Scoreboard scoreboard = this.getScoreboard();
|
||||||
|
+ final java.util.Collection<String> toRemove = scoreboard.getTeams().stream().filter(team -> team.getName().startsWith("collideRule_")).map(PlayerTeam::getName).collect(java.util.stream.Collectors.toList());
|
||||||
|
+ for (String teamName : toRemove) {
|
||||||
|
+ scoreboard.removeTeam(scoreboard.getTeam(teamName)); // Clean up after ourselves
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!com.destroystokyo.paper.PaperConfig.enablePlayerCollisions) {
|
||||||
|
+ this.getPlayerList().collideRuleTeamName = org.apache.commons.lang3.StringUtils.left("collideRule_" + java.util.concurrent.ThreadLocalRandom.current().nextInt(), 16);
|
||||||
|
+ PlayerTeam collideTeam = scoreboard.createTeam(this.getPlayerList().collideRuleTeamName);
|
||||||
|
+ collideTeam.setSeeFriendlyInvisibles(false); // Because we want to mimic them not being on a team at all
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
|
||||||
|
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
|
||||||
|
this.connection.acceptConnections();
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||||
|
index aa440a6341a6d30aba8fd5f6bcd122bd5d8760cd..59fb19cfebe4f488fd02f02db31029d44b65e408 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||||
|
@@ -79,6 +79,7 @@ import net.minecraft.world.level.storage.PlayerDataStorage;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.scores.Objective;
|
||||||
|
import net.minecraft.world.scores.PlayerTeam;
|
||||||
|
+import net.minecraft.world.scores.Scoreboard;
|
||||||
|
import net.minecraft.world.scores.Team;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
@@ -141,6 +142,7 @@ public abstract class PlayerList {
|
||||||
|
// CraftBukkit start
|
||||||
|
private CraftServer cserver;
|
||||||
|
private final Map<String,ServerPlayer> playersByName = new java.util.HashMap<>();
|
||||||
|
+ public @Nullable String collideRuleTeamName; // Paper - Team name used for collideRule
|
||||||
|
|
||||||
|
public PlayerList(MinecraftServer server, RegistryAccess.RegistryHolder registryManager, PlayerDataStorage saveHandler, int maxPlayers) {
|
||||||
|
this.cserver = server.server = new CraftServer((DedicatedServer) server, this);
|
||||||
|
@@ -372,6 +374,13 @@ public abstract class PlayerList {
|
||||||
|
}
|
||||||
|
|
||||||
|
player.initMenu();
|
||||||
|
+ // Paper start - Add to collideRule team if needed
|
||||||
|
+ final Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard();
|
||||||
|
+ final PlayerTeam collideRuleTeam = scoreboard.getTeam(collideRuleTeamName);
|
||||||
|
+ if (this.collideRuleTeamName != null && collideRuleTeam != null && player.getTeam() == null) {
|
||||||
|
+ scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
// CraftBukkit - Moved from above, added world
|
||||||
|
PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.worldDataServer.getLevelName(), player.getX(), player.getY(), player.getZ());
|
||||||
|
}
|
||||||
|
@@ -492,6 +501,16 @@ public abstract class PlayerList {
|
||||||
|
entityplayer.doTick(); // SPIGOT-924
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
+ // Paper start - Remove from collideRule team if needed
|
||||||
|
+ if (this.collideRuleTeamName != null) {
|
||||||
|
+ final Scoreboard scoreBoard = this.server.getLevel(Level.OVERWORLD).getScoreboard();
|
||||||
|
+ final PlayerTeam team = scoreBoard.getTeam(this.collideRuleTeamName);
|
||||||
|
+ if (entityplayer.getTeam() == team && team != null) {
|
||||||
|
+ scoreBoard.removePlayerFromTeam(entityplayer.getScoreboardName(), team);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
this.save(entityplayer);
|
||||||
|
if (entityplayer.isPassenger()) {
|
||||||
|
Entity entity = entityplayer.getRootVehicle();
|
||||||
|
@@ -1140,6 +1159,13 @@ public abstract class PlayerList {
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
+ // Paper start - Remove collideRule team if it exists
|
||||||
|
+ if (this.collideRuleTeamName != null) {
|
||||||
|
+ final Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard();
|
||||||
|
+ final PlayerTeam team = scoreboard.getTeam(this.collideRuleTeamName);
|
||||||
|
+ if (team != null) scoreboard.removeTeam(team);
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
// CraftBukkit start
|
|
@ -0,0 +1,57 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: kashike <kashike@vq.lc>
|
||||||
|
Date: Wed, 13 Apr 2016 20:21:38 -0700
|
||||||
|
Subject: [PATCH] Add handshake event to allow plugins to handle client
|
||||||
|
handshaking logic themselves
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||||
|
index 55b6412bb978abb6f8eaff83a7dd40fbc1ed8b9a..e56ab94ce65e81bb0383a1626a1790c43bd6920e 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||||
|
@@ -29,7 +29,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL
|
||||||
|
// CraftBukkit end
|
||||||
|
private static final Component IGNORE_STATUS_REASON = new TextComponent("Ignoring status request");
|
||||||
|
private final MinecraftServer server;
|
||||||
|
- private final Connection connection;
|
||||||
|
+ private final Connection connection; final Connection getNetworkManager() { return this.connection; } // Paper - OBFHELPER
|
||||||
|
|
||||||
|
public ServerHandshakePacketListenerImpl(MinecraftServer server, Connection connection) {
|
||||||
|
this.server = server;
|
||||||
|
@@ -88,8 +88,35 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL
|
||||||
|
this.connection.disconnect(chatmessage);
|
||||||
|
} else {
|
||||||
|
this.connection.setListener(new ServerLoginPacketListenerImpl(this.server, this.connection));
|
||||||
|
+ // Paper start - handshake event
|
||||||
|
+ boolean proxyLogicEnabled = org.spigotmc.SpigotConfig.bungee;
|
||||||
|
+ boolean handledByEvent = false;
|
||||||
|
+ // Try and handle the handshake through the event
|
||||||
|
+ if (com.destroystokyo.paper.event.player.PlayerHandshakeEvent.getHandlerList().getRegisteredListeners().length != 0) { // Hello? Can you hear me?
|
||||||
|
+ java.net.SocketAddress socketAddress = this.getNetworkManager().address;
|
||||||
|
+ String hostnameOfRemote = socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getHostString() : InetAddress.getLoopbackAddress().getHostAddress();
|
||||||
|
+ com.destroystokyo.paper.event.player.PlayerHandshakeEvent event = new com.destroystokyo.paper.event.player.PlayerHandshakeEvent(packet.hostName, hostnameOfRemote, !proxyLogicEnabled);
|
||||||
|
+ if (event.callEvent()) {
|
||||||
|
+ // If we've failed somehow, let the client know so and go no further.
|
||||||
|
+ if (event.isFailed()) {
|
||||||
|
+ chatmessage = new TranslatableComponent(event.getFailMessage());
|
||||||
|
+ this.getNetworkManager().send(new ClientboundLoginDisconnectPacket(chatmessage));
|
||||||
|
+ this.getNetworkManager().disconnect(chatmessage);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (event.getServerHostname() != null) packet.hostName = event.getServerHostname();
|
||||||
|
+ if (event.getSocketAddressHostname() != null) this.getNetworkManager().address = new java.net.InetSocketAddress(event.getSocketAddressHostname(), socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getPort() : 0);
|
||||||
|
+ this.getNetworkManager().spoofedUUID = event.getUniqueId();
|
||||||
|
+ this.getNetworkManager().spoofedProfile = gson.fromJson(event.getPropertiesJson(), com.mojang.authlib.properties.Property[].class);
|
||||||
|
+ handledByEvent = true; // Hooray, we did it!
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Don't try and handle default logic if it's been handled by the event.
|
||||||
|
+ if (!handledByEvent && proxyLogicEnabled) {
|
||||||
|
+ // Paper end
|
||||||
|
// Spigot Start
|
||||||
|
- if (org.spigotmc.SpigotConfig.bungee) {
|
||||||
|
+ //if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above!
|
||||||
|
String[] split = packet.hostName.split("\00");
|
||||||
|
if ( ( split.length == 3 || split.length == 4 ) && ( HOST_PATTERN.matcher( split[1] ).matches() ) ) {
|
||||||
|
packet.hostName = split[0];
|
|
@ -0,0 +1,59 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Sat, 16 Apr 2016 00:39:33 -0400
|
||||||
|
Subject: [PATCH] Configurable RCON IP address
|
||||||
|
|
||||||
|
For servers with multiple IP's, ability to bind to a specific interface.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||||
|
index d10f2e5a13a9e86c32ef5dd8c6732ad8b51ed6a0..545096d9ba403396b6aaa7bb6d912f2de08a967e 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||||
|
@@ -64,6 +64,8 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
||||||
|
public final Settings<DedicatedServerProperties>.MutableValue<Boolean> whiteList;
|
||||||
|
public final WorldGenSettings worldGenSettings;
|
||||||
|
|
||||||
|
+ public final String rconIp; // Paper - Add rcon ip
|
||||||
|
+
|
||||||
|
// CraftBukkit start
|
||||||
|
public DedicatedServerProperties(Properties properties, RegistryAccess iregistrycustom, OptionSet optionset) {
|
||||||
|
super(properties, optionset);
|
||||||
|
@@ -115,6 +117,10 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
||||||
|
this.textFilteringConfig = this.get("text-filtering-config", "");
|
||||||
|
this.playerIdleTimeout = this.getMutable("player-idle-timeout", 0);
|
||||||
|
this.whiteList = this.getMutable("white-list", false);
|
||||||
|
+ // Paper start - Configurable rcon ip
|
||||||
|
+ final String rconIp = this.getSettingIfExists("rcon.ip");
|
||||||
|
+ this.rconIp = rconIp == null ? this.serverIp : rconIp;
|
||||||
|
+ // Paper end
|
||||||
|
this.worldGenSettings = WorldGenSettings.create(iregistrycustom, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/dedicated/Settings.java b/src/main/java/net/minecraft/server/dedicated/Settings.java
|
||||||
|
index f87bc37a0dc3e7e0ecbdca587683eae6e1b3187d..9d0e8bd74944b402385fe7f44717c32ebbef99f8 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/dedicated/Settings.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/dedicated/Settings.java
|
||||||
|
@@ -129,8 +129,8 @@ public abstract class Settings<T extends Settings<T>> {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
- @Nullable
|
||||||
|
- private String getStringRaw(String key) {
|
||||||
|
+ @Nullable String getSettingIfExists(final String path) { return this.getStringRaw(path); } // Paper - OBFHELPER
|
||||||
|
+ @Nullable private String getStringRaw(String key) { // Paper - OBFHELPER
|
||||||
|
return (String) getOverride(key, this.properties.getProperty(key)); // CraftBukkit
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
|
||||||
|
index f2a94e9d9b57ece16873972bc5292f7cf3928848..ef9f659ae5f53a8effa807ecb955ef47d53aacd2 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
|
||||||
|
@@ -62,7 +62,7 @@ public class RconThread extends GenericThread {
|
||||||
|
@Nullable
|
||||||
|
public static RconThread create(ServerInterface server) {
|
||||||
|
DedicatedServerProperties dedicatedserverproperties = server.getProperties();
|
||||||
|
- String s = server.getServerIp();
|
||||||
|
+ String s = dedicatedserverproperties.rconIp; // Paper - Configurable rcon ip
|
||||||
|
|
||||||
|
if (s.isEmpty()) {
|
||||||
|
s = "0.0.0.0";
|
|
@ -0,0 +1,82 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Sun, 17 Apr 2016 17:27:09 -0400
|
||||||
|
Subject: [PATCH] Prevent Fire from loading chunks & wrongly spread
|
||||||
|
|
||||||
|
This causes the nether to spam unload/reload chunks, plus overall
|
||||||
|
bad behavior.
|
||||||
|
|
||||||
|
This also stops fire from spreading to illegal locations.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/block/FireBlock.java b/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||||
|
index 700078c2fd536cc22351eadf51503efb9acd9df9..85170008de6e77cfb8e4f55ae440a8428d868af4 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||||
|
@@ -134,7 +134,7 @@ public class FireBlock extends BaseFireBlock {
|
||||||
|
BooleanProperty blockstateboolean = (BooleanProperty) FireBlock.PROPERTY_BY_DIRECTION.get(enumdirection);
|
||||||
|
|
||||||
|
if (blockstateboolean != null) {
|
||||||
|
- iblockdata1 = (BlockState) iblockdata1.setValue(blockstateboolean, this.canBurn(world.getBlockState(pos.relative(enumdirection))));
|
||||||
|
+ iblockdata1 = (BlockState) iblockdata1.setValue(blockstateboolean, this.canBurn(world.getTypeIfLoaded(pos.relative(enumdirection)))); // Paper - prevent chunk loads
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -214,6 +214,7 @@ public class FireBlock extends BaseFireBlock {
|
||||||
|
}
|
||||||
|
|
||||||
|
blockposition_mutableblockposition.setWithOffset((Vec3i) pos, l, j1, i1);
|
||||||
|
+ if (blockposition_mutableblockposition.isInvalidYLocation() || !world.hasChunkAt(blockposition_mutableblockposition)) continue; // Paper
|
||||||
|
int l1 = this.getFireOdds((LevelReader) world, (BlockPos) blockposition_mutableblockposition);
|
||||||
|
|
||||||
|
if (l1 > 0) {
|
||||||
|
@@ -259,10 +260,16 @@ public class FireBlock extends BaseFireBlock {
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trySpread(Level world, BlockPos blockposition, int i, Random random, int j, BlockPos sourceposition) { // CraftBukkit add sourceposition
|
||||||
|
- int k = this.getBurnOdd(world.getBlockState(blockposition));
|
||||||
|
+ // Paper start
|
||||||
|
+ final BlockState iblockdata = world.getTypeIfLoaded(blockposition);
|
||||||
|
+ if (iblockdata == null) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ int k = this.getBurnOdd(iblockdata);
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
if (random.nextInt(i) < k) {
|
||||||
|
- BlockState iblockdata = world.getBlockState(blockposition);
|
||||||
|
+ //IBlockData iblockdata = world.getType(blockposition); // Paper
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
org.bukkit.block.Block theBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());
|
||||||
|
@@ -308,7 +315,7 @@ public class FireBlock extends BaseFireBlock {
|
||||||
|
for (int j = 0; j < i; ++j) {
|
||||||
|
Direction enumdirection = aenumdirection[j];
|
||||||
|
|
||||||
|
- if (this.canBurn(world.getBlockState(pos.relative(enumdirection)))) {
|
||||||
|
+ if (this.canBurn(world.getTypeIfLoaded(pos.relative(enumdirection)))) { // Paper - prevent chunk loads
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -326,7 +333,12 @@ public class FireBlock extends BaseFireBlock {
|
||||||
|
|
||||||
|
for (int k = 0; k < j; ++k) {
|
||||||
|
Direction enumdirection = aenumdirection[k];
|
||||||
|
- BlockState iblockdata = iworldreader.getBlockState(pos.relative(enumdirection));
|
||||||
|
+ // Paper start
|
||||||
|
+ BlockState iblockdata = iworldreader.getTypeIfLoaded(pos.relative(enumdirection));
|
||||||
|
+ if (iblockdata == null) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
i = Math.max(this.getFlameOdds(iblockdata), i);
|
||||||
|
}
|
||||||
|
@@ -337,7 +349,7 @@ public class FireBlock extends BaseFireBlock {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canBurn(BlockState state) {
|
||||||
|
- return this.getFlameOdds(state) > 0;
|
||||||
|
+ return state != null && this.getFlameOdds(state) > 0; // Paper - iblockdata can be nullable if chunk is unloaded now
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
|
@ -0,0 +1,48 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Isaac Moore <rmsy@me.com>
|
||||||
|
Date: Tue, 19 Apr 2016 14:09:31 -0500
|
||||||
|
Subject: [PATCH] Implement PlayerLocaleChangeEvent
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
index ffad931c72e52855a3f139354f5e85c460e2a80b..bd3d9182dfb2c0ae1d8c3b9aa360f94c33252592 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
@@ -1692,7 +1692,7 @@ public class ServerPlayer extends Player implements ContainerListener {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
- public String locale = "en_us"; // CraftBukkit - add, lowercase
|
||||||
|
+ public String locale = null; // CraftBukkit - add, lowercase // Paper - default to null
|
||||||
|
public java.util.Locale adventure$locale = java.util.Locale.US; // Paper
|
||||||
|
public void updateOptions(ServerboundClientInformationPacket packet) {
|
||||||
|
// CraftBukkit start
|
||||||
|
@@ -1700,9 +1700,10 @@ public class ServerPlayer extends Player implements ContainerListener {
|
||||||
|
PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(getBukkitEntity(), getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT);
|
||||||
|
this.server.server.getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
- if (!this.locale.equals(packet.language)) {
|
||||||
|
+ if (this.locale == null || !this.locale.equals(packet.language)) { // Paper - check for null
|
||||||
|
PlayerLocaleChangeEvent event = new PlayerLocaleChangeEvent(getBukkitEntity(), packet.language);
|
||||||
|
this.server.server.getPluginManager().callEvent(event);
|
||||||
|
+ new com.destroystokyo.paper.event.player.PlayerLocaleChangeEvent(this.getBukkitEntity(), this.locale, packet.language).callEvent(); // Paper
|
||||||
|
}
|
||||||
|
this.locale = packet.language;
|
||||||
|
// Paper start
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
index b264cbe5f91da9e31c5fd00ee285735a19aaad35..fc19b4cacd223b928fbdf922b828beaed630bf2e 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
@@ -1875,8 +1875,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLocale() {
|
||||||
|
- return getHandle().locale;
|
||||||
|
-
|
||||||
|
+ // Paper start - Locale change event
|
||||||
|
+ final String locale = getHandle().locale;
|
||||||
|
+ return locale != null ? locale : "en_us";
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paper start
|
|
@ -0,0 +1,42 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Fri, 22 Apr 2016 01:43:11 -0500
|
||||||
|
Subject: [PATCH] EntityRegainHealthEvent isFastRegen API
|
||||||
|
|
||||||
|
Don't even get me started
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
index a326e5b4ac055f2f8a95c6eaccd8d0a97762da1f..1131d86080b3100437aa18a00c6277fcea4b7ea8 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
@@ -1127,10 +1127,16 @@ public abstract class LivingEntity extends Entity {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason) {
|
||||||
|
+ // Paper start - Forward
|
||||||
|
+ heal(f, regainReason, false);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason, boolean isFastRegen) {
|
||||||
|
+ // Paper end
|
||||||
|
float f1 = this.getHealth();
|
||||||
|
|
||||||
|
if (f1 > 0.0F) {
|
||||||
|
- EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason);
|
||||||
|
+ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason, isFastRegen); // Paper
|
||||||
|
// Suppress during worldgen
|
||||||
|
if (this.valid) {
|
||||||
|
this.level.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/food/FoodData.java b/src/main/java/net/minecraft/world/food/FoodData.java
|
||||||
|
index 269392592f5271b1bb8c37661fbe685e76e32b74..d18b7d2c22312fc6ec3977ce38a1f04e0b5c8ad4 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/food/FoodData.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/food/FoodData.java
|
||||||
|
@@ -84,7 +84,7 @@ public class FoodData {
|
||||||
|
if (this.tickTimer >= this.saturatedRegenRate) { // CraftBukkit
|
||||||
|
float f = Math.min(this.saturationLevel, 6.0F);
|
||||||
|
|
||||||
|
- player.heal(f / 6.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED); // CraftBukkit - added RegainReason
|
||||||
|
+ player.heal(f / 6.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED, true); // CraftBukkit - added RegainReason // Paper - This is fast regen
|
||||||
|
// this.a(f); CraftBukkit - EntityExhaustionEvent
|
||||||
|
player.applyExhaustion(f, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.REGEN); // CraftBukkit - EntityExhaustionEvent
|
||||||
|
this.tickTimer = 0;
|
|
@ -0,0 +1,52 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: kashike <kashike@vq.lc>
|
||||||
|
Date: Thu, 21 Apr 2016 23:51:55 -0700
|
||||||
|
Subject: [PATCH] Add ability to configure frosted_ice properties
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 1942f5224aaebb18adb591d6f70a419cfc1a7bdd..5baccb8d50c135ab20c38ffd0690f585514ce5af 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -259,4 +259,14 @@ public class PaperWorldConfig {
|
||||||
|
private void useVanillaScoreboardColoring() {
|
||||||
|
useVanillaScoreboardColoring = getBoolean("use-vanilla-world-scoreboard-name-coloring", false);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean frostedIceEnabled = true;
|
||||||
|
+ public int frostedIceDelayMin = 20;
|
||||||
|
+ public int frostedIceDelayMax = 40;
|
||||||
|
+ private void frostedIce() {
|
||||||
|
+ this.frostedIceEnabled = this.getBoolean("frosted-ice.enabled", this.frostedIceEnabled);
|
||||||
|
+ this.frostedIceDelayMin = this.getInt("frosted-ice.delay.min", this.frostedIceDelayMin);
|
||||||
|
+ this.frostedIceDelayMax = this.getInt("frosted-ice.delay.max", this.frostedIceDelayMax);
|
||||||
|
+ log("Frosted Ice: " + (this.frostedIceEnabled ? "enabled" : "disabled") + " / delay: min=" + this.frostedIceDelayMin + ", max=" + this.frostedIceDelayMax);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java b/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
|
||||||
|
index 0727cc36c99cb5ca5019c71f4540de76b78c7a80..ae2f5acd008d5d7163b56cb4a2d29354299959ca 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
|
||||||
|
@@ -30,6 +30,7 @@ public class FrostedIceBlock extends IceBlock {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||||
|
+ if (!world.paperConfig.frostedIceEnabled) return; // Paper - add ability to disable frosted ice
|
||||||
|
if ((random.nextInt(3) == 0 || this.fewerNeigboursThan(world, pos, 4)) && world.getMaxLocalRawBrightness(pos) > 11 - (Integer) state.getValue(FrostedIceBlock.AGE) - state.getLightBlock((BlockGetter) world, pos) && this.slightlyMelt(state, (Level) world, pos)) {
|
||||||
|
BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
|
||||||
|
Direction[] aenumdirection = Direction.values();
|
||||||
|
@@ -42,12 +43,12 @@ public class FrostedIceBlock extends IceBlock {
|
||||||
|
BlockState iblockdata1 = world.getBlockState(blockposition_mutableblockposition);
|
||||||
|
|
||||||
|
if (iblockdata1.is((Block) this) && !this.slightlyMelt(iblockdata1, (Level) world, blockposition_mutableblockposition)) {
|
||||||
|
- world.getBlockTicks().scheduleTick(blockposition_mutableblockposition, this, Mth.nextInt(random, 20, 40));
|
||||||
|
+ world.getBlockTicks().scheduleTick(blockposition_mutableblockposition, this, Mth.nextInt(random, world.paperConfig.frostedIceDelayMin, world.paperConfig.frostedIceDelayMax)); // Paper - use configurable min/max delay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
- world.getBlockTicks().scheduleTick(pos, this, Mth.nextInt(random, 20, 40));
|
||||||
|
+ world.getBlockTicks().scheduleTick(pos, this, Mth.nextInt(random, world.paperConfig.frostedIceDelayMin, world.paperConfig.frostedIceDelayMax)); // Paper - use configurable min/max delay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Thu, 28 Apr 2016 00:57:27 -0400
|
||||||
|
Subject: [PATCH] remove null possibility for getServer singleton
|
||||||
|
|
||||||
|
to stop IDE complaining about potential NPE
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index d639ead95c36985fa0f5a9c51898c4237e373f0e..4e468cb7ccf683b8fc9e04a48cfc25779775e25f 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -178,6 +178,7 @@ import org.spigotmc.SlackActivityAccountant; // Spigot
|
||||||
|
|
||||||
|
public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements SnooperPopulator, CommandSource, AutoCloseable {
|
||||||
|
|
||||||
|
+ private static MinecraftServer SERVER; // Paper
|
||||||
|
public static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
public static final File USERID_CACHE_FILE = new File("usercache.json");
|
||||||
|
public static final LevelSettings DEMO_SETTINGS = new LevelSettings("Demo World", GameType.SURVIVAL, false, Difficulty.NORMAL, false, new GameRules(), DataPackConfig.DEFAULT);
|
||||||
|
@@ -284,6 +285,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
|
||||||
|
public MinecraftServer(OptionSet options, DataPackConfig datapackconfiguration, Thread thread, RegistryAccess.RegistryHolder iregistrycustom_dimension, LevelStorageSource.LevelStorageAccess convertable_conversionsession, WorldData savedata, PackRepository resourcepackrepository, Proxy proxy, DataFixer datafixer, ServerResources datapackresources, MinecraftSessionService minecraftsessionservice, GameProfileRepository gameprofilerepository, GameProfileCache usercache, ChunkProgressListenerFactory worldloadlistenerfactory) {
|
||||||
|
super("Server");
|
||||||
|
+ SERVER = this; // Paper - better singleton
|
||||||
|
this.continousProfiler = new ContinuousProfiler(Util.timeSource, this::getTickCount);
|
||||||
|
this.profiler = InactiveProfiler.INSTANCE;
|
||||||
|
this.status = new ServerStatus();
|
||||||
|
@@ -2161,7 +2163,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public static MinecraftServer getServer() {
|
||||||
|
- return (Bukkit.getServer() instanceof CraftServer) ? ((CraftServer) Bukkit.getServer()).getServer() : null;
|
||||||
|
+ return SERVER; // Paper
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Fri, 29 Apr 2016 20:02:00 -0400
|
||||||
|
Subject: [PATCH] Improve Maps (in item frames) performance and bug fixes
|
||||||
|
|
||||||
|
Maps used a modified version of rendering to support plugin controlled
|
||||||
|
imaging on maps. The Craft Map Renderer is much slower than Vanilla,
|
||||||
|
causing maps in item frames to cause a noticeable hit on server performance.
|
||||||
|
|
||||||
|
This updates the map system to not use the Craft system if we detect that no
|
||||||
|
custom renderers are in use, defaulting to the much simpler Vanilla system.
|
||||||
|
|
||||||
|
Additionally, numerous issues to player position tracking on maps has been fixed.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index bb99d9fe5e274318d8480a6de2c45b0a57351f77..0a613f94d1c796267636e1a343aeee65a49ffed5 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -1164,6 +1164,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||||
|
{
|
||||||
|
if ( iter.next().player == entity )
|
||||||
|
{
|
||||||
|
+ map.decorations.remove(entity.getName().getString()); // Paper
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 3b451e75a7f49ea6b543aee9f0a51c0be3c4dfba..c11d5aa115d10e3c12863cf9d42c60194d63b690 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||||
|
@@ -85,6 +85,7 @@ import net.minecraft.world.item.ElytraItem;
|
||||||
|
import net.minecraft.world.item.ItemCooldowns;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
+import net.minecraft.world.item.MapItem;
|
||||||
|
import net.minecraft.world.item.ProjectileWeaponItem;
|
||||||
|
import net.minecraft.world.item.SwordItem;
|
||||||
|
import net.minecraft.world.item.crafting.Recipe;
|
||||||
|
@@ -104,6 +105,7 @@ import net.minecraft.world.level.block.entity.SignBlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.StructureBlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.pattern.BlockInWorld;
|
||||||
|
+import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.scores.PlayerTeam;
|
||||||
|
@@ -686,6 +688,12 @@ public abstract class Player extends LivingEntity {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
+ // Paper start - remove player from map on drop
|
||||||
|
+ if (stack.getItem() == Items.FILLED_MAP) {
|
||||||
|
+ MapItemSavedData worldmap = MapItem.getOrCreateSavedData(stack, this.level);
|
||||||
|
+ worldmap.updateSeenPlayers(this, stack);
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
return entityitem;
|
||||||
|
}
|
||||||
|
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 d44505b3ee2a35422568e9bce0d868191e348fc0..7582c7cd4235d212a0cf66a4c59ce0cedaa360ad 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
|
||||||
|
@@ -57,6 +57,7 @@ public class MapItemSavedData extends SavedData {
|
||||||
|
private final Map<String, MapBanner> bannerMarkers = Maps.newHashMap();
|
||||||
|
public final Map<String, MapDecoration> decorations = Maps.newLinkedHashMap();
|
||||||
|
private final Map<String, MapFrame> frameMarkers = Maps.newHashMap();
|
||||||
|
+ private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
public final CraftMapView mapView;
|
||||||
|
@@ -69,6 +70,7 @@ public class MapItemSavedData extends SavedData {
|
||||||
|
// CraftBukkit start
|
||||||
|
mapView = new CraftMapView(this);
|
||||||
|
server = (CraftServer) org.bukkit.Bukkit.getServer();
|
||||||
|
+ vanillaRender.buffer = colors; // Paper
|
||||||
|
// CraftBukkit end
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -136,6 +138,7 @@ public class MapItemSavedData extends SavedData {
|
||||||
|
this.bannerMarkers.put(mapiconbanner.getId(), mapiconbanner);
|
||||||
|
this.addDecoration(mapiconbanner.getDecoration(), (LevelAccessor) null, mapiconbanner.getId(), (double) mapiconbanner.getPos().getX(), (double) mapiconbanner.getPos().getZ(), 180.0D, mapiconbanner.getName());
|
||||||
|
}
|
||||||
|
+ this.vanillaRender.buffer = colors; // Paper
|
||||||
|
|
||||||
|
ListTag nbttaglist1 = tag.getList("frames", 10);
|
||||||
|
|
||||||
|
@@ -216,6 +219,7 @@ public class MapItemSavedData extends SavedData {
|
||||||
|
this.setDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public void updateSeenPlayers(Player entityhuman, ItemStack itemstack) { this.tickCarriedBy(entityhuman, itemstack); } // Paper - OBFHELPER
|
||||||
|
public void tickCarriedBy(Player player, ItemStack stack) {
|
||||||
|
if (!this.carriedByPlayers.containsKey(player)) {
|
||||||
|
MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = new MapItemSavedData.HoldingPlayer(player);
|
||||||
|
@@ -451,6 +455,21 @@ public class MapItemSavedData extends SavedData {
|
||||||
|
|
||||||
|
public class HoldingPlayer {
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ private void addSeenPlayers(java.util.Collection<MapDecoration> icons) {
|
||||||
|
+ org.bukkit.entity.Player player = (org.bukkit.entity.Player) player.getBukkitEntity();
|
||||||
|
+ MapItemSavedData.this.decorations.forEach((name, mapIcon) -> {
|
||||||
|
+ // If this cursor is for a player check visibility with vanish system
|
||||||
|
+ org.bukkit.entity.Player other = org.bukkit.Bukkit.getPlayerExact(name); // Spigot
|
||||||
|
+ if (other == null || player.canSee(other)) {
|
||||||
|
+ icons.add(mapIcon);
|
||||||
|
+ }
|
||||||
|
+ });
|
||||||
|
+ }
|
||||||
|
+ private boolean shouldUseVanillaMap() {
|
||||||
|
+ return mapView.getRenderers().size() == 1 && mapView.getRenderers().get(0).getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
public final Player player;
|
||||||
|
private boolean dirtyData = true;
|
||||||
|
private int minDirtyX;
|
||||||
|
@@ -467,9 +486,12 @@ public class MapItemSavedData extends SavedData {
|
||||||
|
@Nullable
|
||||||
|
public Packet<?> nextUpdatePacket(ItemStack stack) {
|
||||||
|
// CraftBukkit start
|
||||||
|
- org.bukkit.craftbukkit.map.RenderData render = MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()); // CraftBukkit
|
||||||
|
+ if (!this.dirtyData && this.tick % 5 != 0) { this.tick++; return null; } // Paper - this won't end up sending, so don't render it!
|
||||||
|
+ boolean vanillaMaps = shouldUseVanillaMap(); // Paper
|
||||||
|
+ org.bukkit.craftbukkit.map.RenderData render = !vanillaMaps ? MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()) : MapItemSavedData.this.vanillaRender; // CraftBukkit // Paper
|
||||||
|
|
||||||
|
java.util.Collection<MapDecoration> icons = new java.util.ArrayList<MapDecoration>();
|
||||||
|
+ if (vanillaMaps) addSeenPlayers(icons); // Paper
|
||||||
|
|
||||||
|
for ( org.bukkit.map.MapCursor cursor : render.cursors) {
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/map/RenderData.java b/src/main/java/org/bukkit/craftbukkit/map/RenderData.java
|
||||||
|
index 256a131781721c86dd6cdbc329335964570cbe8c..5768cd512ec166f1e8d1f4a28792015347297c3f 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/map/RenderData.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/map/RenderData.java
|
||||||
|
@@ -5,7 +5,7 @@ import org.bukkit.map.MapCursor;
|
||||||
|
|
||||||
|
public class RenderData {
|
||||||
|
|
||||||
|
- public final byte[] buffer;
|
||||||
|
+ public byte[] buffer; // Paper
|
||||||
|
public final ArrayList<MapCursor> cursors;
|
||||||
|
|
||||||
|
public RenderData() {
|
|
@ -0,0 +1,739 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Sun, 1 May 2016 21:19:14 -0400
|
||||||
|
Subject: [PATCH] LootTable API & Replenishable Lootables Feature
|
||||||
|
|
||||||
|
Provides an API to control the loot table for an object.
|
||||||
|
Also provides a feature that any Lootable Inventory (Chests in Structures)
|
||||||
|
can automatically replenish after a given time.
|
||||||
|
|
||||||
|
This feature is good for long term worlds so that newer players
|
||||||
|
do not suffer with "Every chest has been looted"
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
index 5baccb8d50c135ab20c38ffd0690f585514ce5af..eb04fdb172a50ec1f5b7fe78fa0e7655246abd60 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||||
|
@@ -269,4 +269,26 @@ public class PaperWorldConfig {
|
||||||
|
this.frostedIceDelayMax = this.getInt("frosted-ice.delay.max", this.frostedIceDelayMax);
|
||||||
|
log("Frosted Ice: " + (this.frostedIceEnabled ? "enabled" : "disabled") + " / delay: min=" + this.frostedIceDelayMin + ", max=" + this.frostedIceDelayMax);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean autoReplenishLootables;
|
||||||
|
+ public boolean restrictPlayerReloot;
|
||||||
|
+ public boolean changeLootTableSeedOnFill;
|
||||||
|
+ public int maxLootableRefills;
|
||||||
|
+ public int lootableRegenMin;
|
||||||
|
+ public int lootableRegenMax;
|
||||||
|
+ private void enhancedLootables() {
|
||||||
|
+ autoReplenishLootables = getBoolean("lootables.auto-replenish", false);
|
||||||
|
+ restrictPlayerReloot = getBoolean("lootables.restrict-player-reloot", true);
|
||||||
|
+ changeLootTableSeedOnFill = getBoolean("lootables.reset-seed-on-fill", true);
|
||||||
|
+ maxLootableRefills = getInt("lootables.max-refills", -1);
|
||||||
|
+ lootableRegenMin = PaperConfig.getSeconds(getString("lootables.refresh-min", "12h"));
|
||||||
|
+ lootableRegenMax = PaperConfig.getSeconds(getString("lootables.refresh-max", "2d"));
|
||||||
|
+ if (autoReplenishLootables) {
|
||||||
|
+ log("Lootables: Replenishing every " +
|
||||||
|
+ PaperConfig.timeSummary(lootableRegenMin) + " to " +
|
||||||
|
+ PaperConfig.timeSummary(lootableRegenMax) +
|
||||||
|
+ (restrictPlayerReloot ? " (restricting reloot)" : "")
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..fda64b8860cb696e209eedcfb200e7193d216732
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java
|
||||||
|
@@ -0,0 +1,34 @@
|
||||||
|
+package com.destroystokyo.paper.loottable;
|
||||||
|
+
|
||||||
|
+import LootableInventory;
|
||||||
|
+import net.minecraft.core.BlockPos;
|
||||||
|
+import net.minecraft.world.level.Level;
|
||||||
|
+import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
|
||||||
|
+import org.bukkit.Chunk;
|
||||||
|
+import org.bukkit.block.Block;
|
||||||
|
+
|
||||||
|
+public interface PaperLootableBlockInventory extends LootableBlockInventory, PaperLootableInventory {
|
||||||
|
+
|
||||||
|
+ RandomizableContainerBlockEntity getTileEntity();
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default LootableInventory getAPILootableInventory() {
|
||||||
|
+ return this;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default Level getNMSWorld() {
|
||||||
|
+ return getTileEntity().getLevel();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ default Block getBlock() {
|
||||||
|
+ final BlockPos position = getTileEntity().getBlockPos();
|
||||||
|
+ final Chunk bukkitChunk = getTileEntity().getLevel().getChunkAt(position).bukkitChunk;
|
||||||
|
+ return bukkitChunk.getBlock(position.getX(), position.getY(), position.getZ());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default PaperLootableInventoryData getLootableData() {
|
||||||
|
+ return getTileEntity().lootableData;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..292d5ef8a1c428893af729b298eecd32b4c4659a
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java
|
||||||
|
@@ -0,0 +1,29 @@
|
||||||
|
+package com.destroystokyo.paper.loottable;
|
||||||
|
+
|
||||||
|
+import LootableInventory;
|
||||||
|
+import net.minecraft.world.level.Level;
|
||||||
|
+import org.bukkit.entity.Entity;
|
||||||
|
+
|
||||||
|
+public interface PaperLootableEntityInventory extends LootableEntityInventory, PaperLootableInventory {
|
||||||
|
+
|
||||||
|
+ net.minecraft.world.entity.Entity getHandle();
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default LootableInventory getAPILootableInventory() {
|
||||||
|
+ return this;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ default Entity getEntity() {
|
||||||
|
+ return getHandle().getBukkitEntity();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default Level getNMSWorld() {
|
||||||
|
+ return getHandle().getCommandSenderWorld();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default PaperLootableInventoryData getLootableData() {
|
||||||
|
+ return getHandle().lootableData;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..b3def19a50081cfa758b6e25707b2fc6fed8d3ca
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java
|
||||||
|
@@ -0,0 +1,71 @@
|
||||||
|
+package com.destroystokyo.paper.loottable;
|
||||||
|
+
|
||||||
|
+import org.bukkit.loot.Lootable;
|
||||||
|
+import LootableInventory;
|
||||||
|
+import java.util.UUID;
|
||||||
|
+import net.minecraft.world.level.Level;
|
||||||
|
+
|
||||||
|
+public interface PaperLootableInventory extends LootableInventory, Lootable {
|
||||||
|
+
|
||||||
|
+ PaperLootableInventoryData getLootableData();
|
||||||
|
+ LootableInventory getAPILootableInventory();
|
||||||
|
+
|
||||||
|
+ Level getNMSWorld();
|
||||||
|
+
|
||||||
|
+ default org.bukkit.World getBukkitWorld() {
|
||||||
|
+ return getNMSWorld().getWorld();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default boolean isRefillEnabled() {
|
||||||
|
+ return getNMSWorld().paperConfig.autoReplenishLootables;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default boolean hasBeenFilled() {
|
||||||
|
+ return getLastFilled() != -1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default boolean hasPlayerLooted(UUID player) {
|
||||||
|
+ return getLootableData().hasPlayerLooted(player);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default Long getLastLooted(UUID player) {
|
||||||
|
+ return getLootableData().getLastLooted(player);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default boolean setHasPlayerLooted(UUID player, boolean looted) {
|
||||||
|
+ final boolean hasLooted = hasPlayerLooted(player);
|
||||||
|
+ if (hasLooted != looted) {
|
||||||
|
+ getLootableData().setPlayerLootedState(player, looted);
|
||||||
|
+ }
|
||||||
|
+ return hasLooted;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default boolean hasPendingRefill() {
|
||||||
|
+ long nextRefill = getLootableData().getNextRefill();
|
||||||
|
+ return nextRefill != -1 && nextRefill > getLootableData().getLastFill();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default long getLastFilled() {
|
||||||
|
+ return getLootableData().getLastFill();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default long getNextRefill() {
|
||||||
|
+ return getLootableData().getNextRefill();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ default long setNextRefill(long refillAt) {
|
||||||
|
+ if (refillAt < -1) {
|
||||||
|
+ refillAt = -1;
|
||||||
|
+ }
|
||||||
|
+ return getLootableData().setNextRefill(refillAt);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..88542462d34ba24e8590294bd896d7e73932ef9c
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
|
||||||
|
@@ -0,0 +1,180 @@
|
||||||
|
+package com.destroystokyo.paper.loottable;
|
||||||
|
+
|
||||||
|
+import com.destroystokyo.paper.PaperWorldConfig;
|
||||||
|
+import org.bukkit.entity.Player;
|
||||||
|
+import org.bukkit.loot.LootTable;
|
||||||
|
+
|
||||||
|
+import javax.annotation.Nullable;
|
||||||
|
+import net.minecraft.nbt.CompoundTag;
|
||||||
|
+import net.minecraft.nbt.ListTag;
|
||||||
|
+import java.util.HashMap;
|
||||||
|
+import java.util.Map;
|
||||||
|
+import java.util.Random;
|
||||||
|
+import java.util.UUID;
|
||||||
|
+
|
||||||
|
+public class PaperLootableInventoryData {
|
||||||
|
+
|
||||||
|
+ private static final Random RANDOM = new Random();
|
||||||
|
+
|
||||||
|
+ private long lastFill = -1;
|
||||||
|
+ private long nextRefill = -1;
|
||||||
|
+ private int numRefills = 0;
|
||||||
|
+ private Map<UUID, Long> lootedPlayers;
|
||||||
|
+ private final PaperLootableInventory lootable;
|
||||||
|
+
|
||||||
|
+ public PaperLootableInventoryData(PaperLootableInventory lootable) {
|
||||||
|
+ this.lootable = lootable;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ long getLastFill() {
|
||||||
|
+ return this.lastFill;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ long getNextRefill() {
|
||||||
|
+ return this.nextRefill;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ long setNextRefill(long nextRefill) {
|
||||||
|
+ long prev = this.nextRefill;
|
||||||
|
+ this.nextRefill = nextRefill;
|
||||||
|
+ return prev;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public boolean shouldReplenish(@Nullable net.minecraft.world.entity.player.Player player) {
|
||||||
|
+ LootTable table = this.lootable.getLootTable();
|
||||||
|
+
|
||||||
|
+ // No Loot Table associated
|
||||||
|
+ if (table == null) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // ALWAYS process the first fill or if the feature is disabled
|
||||||
|
+ if (this.lastFill == -1 || !this.lootable.getNMSWorld().paperConfig.autoReplenishLootables) {
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Only process refills when a player is set
|
||||||
|
+ if (player == null) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Chest is not scheduled for refill
|
||||||
|
+ if (this.nextRefill == -1) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final PaperWorldConfig paperConfig = this.lootable.getNMSWorld().paperConfig;
|
||||||
|
+
|
||||||
|
+ // Check if max refills has been hit
|
||||||
|
+ if (paperConfig.maxLootableRefills != -1 && this.numRefills >= paperConfig.maxLootableRefills) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Refill has not been reached
|
||||||
|
+ if (this.nextRefill > System.currentTimeMillis()) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ final Player bukkitPlayer = (Player) player.getBukkitEntity();
|
||||||
|
+ LootableInventoryReplenishEvent event = new LootableInventoryReplenishEvent(bukkitPlayer, lootable.getAPILootableInventory());
|
||||||
|
+ if (paperConfig.restrictPlayerReloot && hasPlayerLooted(player.getUUID())) {
|
||||||
|
+ event.setCancelled(true);
|
||||||
|
+ }
|
||||||
|
+ return event.callEvent();
|
||||||
|
+ }
|
||||||
|
+ public void processRefill(@Nullable net.minecraft.world.entity.player.Player player) {
|
||||||
|
+ this.lastFill = System.currentTimeMillis();
|
||||||
|
+ final PaperWorldConfig paperConfig = this.lootable.getNMSWorld().paperConfig;
|
||||||
|
+ if (paperConfig.autoReplenishLootables) {
|
||||||
|
+ int min = paperConfig.lootableRegenMin;
|
||||||
|
+ int max = paperConfig.lootableRegenMax;
|
||||||
|
+ this.nextRefill = this.lastFill + (min + RANDOM.nextInt(max - min + 1)) * 1000L;
|
||||||
|
+ this.numRefills++;
|
||||||
|
+ if (paperConfig.changeLootTableSeedOnFill) {
|
||||||
|
+ this.lootable.setSeed(0);
|
||||||
|
+ }
|
||||||
|
+ if (player != null) { // This means that numRefills can be incremented without a player being in the lootedPlayers list - Seems to be EntityMinecartChest specific
|
||||||
|
+ this.setPlayerLootedState(player.getUUID(), true);
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ this.lootable.clearLootTable();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ public void loadNbt(CompoundTag base) {
|
||||||
|
+ if (!base.contains("Paper.LootableData", 10)) { // 10 = compound
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ CompoundTag comp = base.getCompound("Paper.LootableData");
|
||||||
|
+ if (comp.contains("lastFill")) {
|
||||||
|
+ this.lastFill = comp.getLong("lastFill");
|
||||||
|
+ }
|
||||||
|
+ if (comp.contains("nextRefill")) {
|
||||||
|
+ this.nextRefill = comp.getLong("nextRefill");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (comp.contains("numRefills")) {
|
||||||
|
+ this.numRefills = comp.getInt("numRefills");
|
||||||
|
+ }
|
||||||
|
+ if (comp.contains("lootedPlayers", 9)) { // 9 = list
|
||||||
|
+ ListTag list = comp.getList("lootedPlayers", 10); // 10 = compound
|
||||||
|
+ final int size = list.size();
|
||||||
|
+ if (size > 0) {
|
||||||
|
+ this.lootedPlayers = new HashMap<>(list.size());
|
||||||
|
+ }
|
||||||
|
+ for (int i = 0; i < size; i++) {
|
||||||
|
+ final CompoundTag cmp = list.getCompound(i);
|
||||||
|
+ lootedPlayers.put(cmp.getUUID("UUID"), cmp.getLong("Time"));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ public void saveNbt(CompoundTag base) {
|
||||||
|
+ CompoundTag comp = new CompoundTag();
|
||||||
|
+ if (this.nextRefill != -1) {
|
||||||
|
+ comp.putLong("nextRefill", this.nextRefill);
|
||||||
|
+ }
|
||||||
|
+ if (this.lastFill != -1) {
|
||||||
|
+ comp.putLong("lastFill", this.lastFill);
|
||||||
|
+ }
|
||||||
|
+ if (this.numRefills != 0) {
|
||||||
|
+ comp.putInt("numRefills", this.numRefills);
|
||||||
|
+ }
|
||||||
|
+ if (this.lootedPlayers != null && !this.lootedPlayers.isEmpty()) {
|
||||||
|
+ ListTag list = new ListTag();
|
||||||
|
+ for (Map.Entry<UUID, Long> entry : this.lootedPlayers.entrySet()) {
|
||||||
|
+ CompoundTag cmp = new CompoundTag();
|
||||||
|
+ cmp.setUUID("UUID", entry.getKey());
|
||||||
|
+ cmp.putLong("Time", entry.getValue());
|
||||||
|
+ list.add(cmp);
|
||||||
|
+ }
|
||||||
|
+ comp.put("lootedPlayers", list);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!comp.isEmpty()) {
|
||||||
|
+ base.put("Paper.LootableData", comp);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ void setPlayerLootedState(UUID player, boolean looted) {
|
||||||
|
+ if (looted && this.lootedPlayers == null) {
|
||||||
|
+ this.lootedPlayers = new HashMap<>();
|
||||||
|
+ }
|
||||||
|
+ if (looted) {
|
||||||
|
+ if (!this.lootedPlayers.containsKey(player)) {
|
||||||
|
+ this.lootedPlayers.put(player, System.currentTimeMillis());
|
||||||
|
+ }
|
||||||
|
+ } else if (this.lootedPlayers != null) {
|
||||||
|
+ this.lootedPlayers.remove(player);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ boolean hasPlayerLooted(UUID player) {
|
||||||
|
+ return this.lootedPlayers != null && this.lootedPlayers.containsKey(player);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Long getLastLooted(UUID player) {
|
||||||
|
+ return lootedPlayers != null ? lootedPlayers.get(player) : null;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperMinecartLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperMinecartLootableInventory.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..d9b31c8a21fdffb33d1f75b1a16606f218145b39
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperMinecartLootableInventory.java
|
||||||
|
@@ -0,0 +1,63 @@
|
||||||
|
+package com.destroystokyo.paper.loottable;
|
||||||
|
+
|
||||||
|
+import LootableInventory;
|
||||||
|
+import net.minecraft.world.entity.Entity;
|
||||||
|
+import net.minecraft.world.entity.vehicle.AbstractMinecartContainer;
|
||||||
|
+import net.minecraft.world.level.Level;
|
||||||
|
+import org.bukkit.Bukkit;
|
||||||
|
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
||||||
|
+
|
||||||
|
+public class PaperMinecartLootableInventory implements PaperLootableEntityInventory {
|
||||||
|
+
|
||||||
|
+ private AbstractMinecartContainer entity;
|
||||||
|
+
|
||||||
|
+ public PaperMinecartLootableInventory(AbstractMinecartContainer entity) {
|
||||||
|
+ this.entity = entity;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public org.bukkit.loot.LootTable getLootTable() {
|
||||||
|
+ return entity.lootTable != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.lootTable)) : null;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setLootTable(org.bukkit.loot.LootTable table, long seed) {
|
||||||
|
+ setLootTable(table);
|
||||||
|
+ setSeed(seed);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setSeed(long seed) {
|
||||||
|
+ entity.lootTableSeed = seed;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public long getSeed() {
|
||||||
|
+ return entity.lootTableSeed;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setLootTable(org.bukkit.loot.LootTable table) {
|
||||||
|
+ entity.lootTable = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public PaperLootableInventoryData getLootableData() {
|
||||||
|
+ return entity.lootableData;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public Entity getHandle() {
|
||||||
|
+ return entity;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public LootableInventory getAPILootableInventory() {
|
||||||
|
+ return (LootableInventory) entity.getBukkitEntity();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public Level getNMSWorld() {
|
||||||
|
+ return entity.level;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..6bc899ec4dc03b09cc978bc7a763a9755a3d2dc4
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
|
||||||
|
@@ -0,0 +1,66 @@
|
||||||
|
+package com.destroystokyo.paper.loottable;
|
||||||
|
+
|
||||||
|
+import LootableInventory;
|
||||||
|
+import net.minecraft.server.MCUtil;
|
||||||
|
+import net.minecraft.world.level.Level;
|
||||||
|
+import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
|
||||||
|
+import org.bukkit.Bukkit;
|
||||||
|
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
||||||
|
+
|
||||||
|
+public class PaperTileEntityLootableInventory implements PaperLootableBlockInventory {
|
||||||
|
+ private RandomizableContainerBlockEntity tileEntityLootable;
|
||||||
|
+
|
||||||
|
+ public PaperTileEntityLootableInventory(RandomizableContainerBlockEntity tileEntityLootable) {
|
||||||
|
+ this.tileEntityLootable = tileEntityLootable;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public org.bukkit.loot.LootTable getLootTable() {
|
||||||
|
+ return tileEntityLootable.lootTable != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setLootTable(org.bukkit.loot.LootTable table, long seed) {
|
||||||
|
+ setLootTable(table);
|
||||||
|
+ setSeed(seed);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setLootTable(org.bukkit.loot.LootTable table) {
|
||||||
|
+ tileEntityLootable.lootTable = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setSeed(long seed) {
|
||||||
|
+ tileEntityLootable.lootTableSeed = seed;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public long getSeed() {
|
||||||
|
+ return tileEntityLootable.lootTableSeed;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public PaperLootableInventoryData getLootableData() {
|
||||||
|
+ return tileEntityLootable.lootableData;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public RandomizableContainerBlockEntity getTileEntity() {
|
||||||
|
+ return tileEntityLootable;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public LootableInventory getAPILootableInventory() {
|
||||||
|
+ Level world = tileEntityLootable.getLevel();
|
||||||
|
+ if (world == null) {
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ return (LootableInventory) getBukkitWorld().getBlockAt(MCUtil.toLocation(world, tileEntityLootable.getBlockPos())).getState();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public Level getNMSWorld() {
|
||||||
|
+ return tileEntityLootable.getLevel();
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 61048140cf0adca03bfb57193ada0adaee73b1bb..171697e88f5a4d8c0be2a47b67b865bbdc4dfe8c 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -157,6 +157,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
||||||
|
};
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper
|
||||||
|
private CraftEntity bukkitEntity;
|
||||||
|
|
||||||
|
public CraftEntity getBukkitEntity() {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
|
||||||
|
index f4758251e58fbb36526cea5c4825561d62c9665a..5b96b1e7428a43c8c5f4a96ea37d5189f0d84f56 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
|
||||||
|
@@ -45,6 +45,7 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
|
||||||
|
public long lootTableSeed;
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
+ { this.lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperMinecartLootableInventory(this)); } // Paper
|
||||||
|
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
||||||
|
private int maxStack = MAX_STACK;
|
||||||
|
|
||||||
|
@@ -202,12 +203,13 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
|
||||||
|
@Override
|
||||||
|
protected void addAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.addAdditionalSaveData(tag);
|
||||||
|
+ this.lootableData.saveNbt(tag); // Paper
|
||||||
|
if (this.lootTable != null) {
|
||||||
|
tag.putString("LootTable", this.lootTable.toString());
|
||||||
|
if (this.lootTableSeed != 0L) {
|
||||||
|
tag.putLong("LootTableSeed", this.lootTableSeed);
|
||||||
|
}
|
||||||
|
- } else {
|
||||||
|
+ } if (true) { // Paper - Always save the items, Table may stick around
|
||||||
|
ContainerHelper.saveAllItems(tag, this.itemStacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -216,11 +218,12 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
|
||||||
|
@Override
|
||||||
|
protected void readAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.readAdditionalSaveData(tag);
|
||||||
|
+ this.lootableData.loadNbt(tag); // Paper
|
||||||
|
this.itemStacks = NonNullList.a(this.getContainerSize(), ItemStack.EMPTY);
|
||||||
|
if (tag.contains("LootTable", 8)) {
|
||||||
|
this.lootTable = new ResourceLocation(tag.getString("LootTable"));
|
||||||
|
this.lootTableSeed = tag.getLong("LootTableSeed");
|
||||||
|
- } else {
|
||||||
|
+ } if (true) { // Paper - always load the items, table may still remain
|
||||||
|
ContainerHelper.loadAllItems(tag, this.itemStacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -251,14 +254,15 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unpackLootTable(@Nullable Player player) {
|
||||||
|
- if (this.lootTable != null && this.level.getServer() != null) {
|
||||||
|
+ if (this.lootableData.shouldReplenish(player) && this.level.getServer() != null) { // Paper
|
||||||
|
LootTable loottable = this.level.getServer().getLootTables().get(this.lootTable);
|
||||||
|
|
||||||
|
if (player instanceof ServerPlayer) {
|
||||||
|
CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer) player, this.lootTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
- this.lootTable = null;
|
||||||
|
+ //this.lootTable = null; // Paper
|
||||||
|
+ this.lootableData.processRefill(player); // Paper
|
||||||
|
LootContext.Builder loottableinfo_builder = (new LootContext.Builder((ServerLevel) this.level)).withParameter(LootContextParams.ORIGIN, this.position()).withOptionalRandomSeed(this.lootTableSeed);
|
||||||
|
|
||||||
|
if (player != null) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||||
|
index 9d33bc31c8088bfba66be1aecbf20e7ee86e4f83..5ad419941ff1113ef29b9a4593f44d8f35ba8424 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||||
|
@@ -27,6 +27,7 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
|
||||||
|
@Nullable
|
||||||
|
public ResourceLocation lootTable;
|
||||||
|
public long lootTableSeed;
|
||||||
|
+ public final com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperTileEntityLootableInventory(this)); // Paper
|
||||||
|
|
||||||
|
protected RandomizableContainerBlockEntity(BlockEntityType<?> type) {
|
||||||
|
super(type);
|
||||||
|
@@ -42,16 +43,19 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean tryLoadLootTable(CompoundTag nbttagcompound) {
|
||||||
|
+ this.lootableData.loadNbt(nbttagcompound); // Paper
|
||||||
|
if (nbttagcompound.contains("LootTable", 8)) {
|
||||||
|
this.lootTable = new ResourceLocation(nbttagcompound.getString("LootTable"));
|
||||||
|
+ try { org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.lootTable); } catch (IllegalArgumentException ex) { this.lootTable = null; } // Paper - validate
|
||||||
|
this.lootTableSeed = nbttagcompound.getLong("LootTableSeed");
|
||||||
|
- return true;
|
||||||
|
+ return false; // Paper - always load the items, table may still remain
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean trySaveLootTable(CompoundTag nbttagcompound) {
|
||||||
|
+ this.lootableData.saveNbt(nbttagcompound); // Paper
|
||||||
|
if (this.lootTable == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
@@ -60,19 +64,20 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
|
||||||
|
nbttagcompound.putLong("LootTableSeed", this.lootTableSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
- return true;
|
||||||
|
+ return false; // Paper - always save the items, table may still remain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unpackLootTable(@Nullable Player player) {
|
||||||
|
- if (this.lootTable != null && this.level.getServer() != null) {
|
||||||
|
+ if (this.lootableData.shouldReplenish(player) && this.level.getServer() != null) { // Paper
|
||||||
|
LootTable loottable = this.level.getServer().getLootTables().get(this.lootTable);
|
||||||
|
|
||||||
|
if (player instanceof ServerPlayer) {
|
||||||
|
CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer) player, this.lootTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
- this.lootTable = null;
|
||||||
|
+ //this.lootTable = null; // Paper
|
||||||
|
+ this.lootableData.processRefill(player); // Paper
|
||||||
|
LootContext.Builder loottableinfo_builder = (new LootContext.Builder((ServerLevel) this.level)).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf((Vec3i) this.worldPosition)).withOptionalRandomSeed(this.lootTableSeed);
|
||||||
|
|
||||||
|
if (player != null) {
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||||
|
index 1e2e94b0cd2ede8fb7ae5902dcd0b639bd8dcf52..e89a93082fe07fdb14df8ffef5beca5bd52d7866 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||||
|
@@ -64,7 +64,7 @@ public class CraftBlockEntityState<T extends BlockEntity> extends CraftBlockStat
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets the wrapped TileEntity
|
||||||
|
- protected T getTileEntity() {
|
||||||
|
+ public T getTileEntity() { // Paper - protected -> public
|
||||||
|
return tileEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
|
||||||
|
index 20d9a192ff102e04687a8aa3eff1ba36a69b6c03..a821df3e13e2ddc479dc5f55540671f43563cdac 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
|
||||||
|
@@ -12,8 +12,9 @@ import org.bukkit.craftbukkit.CraftWorld;
|
||||||
|
import org.bukkit.craftbukkit.inventory.CraftInventory;
|
||||||
|
import org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
+import com.destroystokyo.paper.loottable.PaperLootableBlockInventory; // Paper
|
||||||
|
|
||||||
|
-public class CraftChest extends CraftLootable<ChestBlockEntity> implements Chest {
|
||||||
|
+public class CraftChest extends CraftLootable<ChestBlockEntity> implements Chest, PaperLootableBlockInventory { // Paper
|
||||||
|
|
||||||
|
public CraftChest(final Block block) {
|
||||||
|
super(block, ChestBlockEntity.class);
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
|
||||||
|
index 309650aad43d8b6ce4bb13f8c172028f3feab299..5babbcfcacb89e62f00f8184af2ceea227f9ff69 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
|
||||||
|
@@ -10,7 +10,7 @@ import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
||||||
|
import org.bukkit.loot.LootTable;
|
||||||
|
import org.bukkit.loot.Lootable;
|
||||||
|
|
||||||
|
-public abstract class CraftLootable<T extends RandomizableContainerBlockEntity> extends CraftContainer<T> implements Nameable, Lootable {
|
||||||
|
+public abstract class CraftLootable<T extends RandomizableContainerBlockEntity> extends CraftContainer<T> implements Nameable, Lootable, com.destroystokyo.paper.loottable.PaperLootableBlockInventory { // Paper
|
||||||
|
|
||||||
|
public CraftLootable(Block block, Class<T> tileEntityClass) {
|
||||||
|
super(block, tileEntityClass);
|
||||||
|
@@ -54,7 +54,7 @@ public abstract class CraftLootable<T extends RandomizableContainerBlockEntity>
|
||||||
|
setLootTable(getLootTable(), seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
- private void setLootTable(LootTable table, long seed) {
|
||||||
|
+ public void setLootTable(LootTable table, long seed) { // Paper - public
|
||||||
|
ResourceLocation key = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
|
||||||
|
getSnapshot().setLootTable(key, seed);
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
|
||||||
|
index f0a30acb0199e396d6863a473db433cbe112d8a5..293b222565d8e0592f9f355a2ee8cdfbc868a08e 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
|
||||||
|
@@ -8,7 +8,7 @@ import org.bukkit.entity.minecart.StorageMinecart;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
-public class CraftMinecartChest extends CraftMinecartContainer implements StorageMinecart {
|
||||||
|
+public class CraftMinecartChest extends CraftMinecartContainer implements StorageMinecart, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
|
||||||
|
private final CraftInventory inventory;
|
||||||
|
|
||||||
|
public CraftMinecartChest(CraftServer server, MinecartChest entity) {
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartContainer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartContainer.java
|
||||||
|
index 12044062cb746bd5c77abacf8acddc67e08e78ce..ce14bc4791bd282d16af0ee91fc431acefa3b909 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartContainer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartContainer.java
|
||||||
|
@@ -47,7 +47,7 @@ public abstract class CraftMinecartContainer extends CraftMinecart implements Lo
|
||||||
|
return getHandle().lootTableSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
- private void setLootTable(LootTable table, long seed) {
|
||||||
|
+ public void setLootTable(LootTable table, long seed) { // Paper
|
||||||
|
ResourceLocation newKey = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
|
||||||
|
getHandle().setLootTable(newKey, seed);
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
|
||||||
|
index c1af739369715d8c628c466b269fdde99a2f6286..c8c5f60b6b32248696363d9b63bbbe43810743d3 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
|
||||||
|
@@ -7,7 +7,7 @@ import org.bukkit.entity.EntityType;
|
||||||
|
import org.bukkit.entity.minecart.HopperMinecart;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
|
||||||
|
-public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart {
|
||||||
|
+public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
|
||||||
|
private final CraftInventory inventory;
|
||||||
|
|
||||||
|
public CraftMinecartHopper(CraftServer server, MinecartHopper entity) {
|
|
@ -0,0 +1,32 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Sat, 7 May 2016 23:33:08 -0400
|
||||||
|
Subject: [PATCH] Don't save empty scoreboard teams to scoreboard.dat
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
index 504efea7b6f50a0d17f4f353781953dfb18bdeca..1b8e5671c9dc8c15ce33d351c1bb20f28919b9a2 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||||
|
@@ -237,4 +237,9 @@ public class PaperConfig {
|
||||||
|
private static void enablePlayerCollisions() {
|
||||||
|
enablePlayerCollisions = getBoolean("settings.enable-player-collisions", true);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public static boolean saveEmptyScoreboardTeams = false;
|
||||||
|
+ private static void saveEmptyScoreboardTeams() {
|
||||||
|
+ saveEmptyScoreboardTeams = getBoolean("settings.save-empty-scoreboard-teams", false);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java b/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java
|
||||||
|
index 36a922029687b9fa3ca3a986ae42a373ced87a0e..b9e14d1c54b690f0b975bda5733c4cb4f6449f77 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java
|
||||||
|
@@ -182,6 +182,7 @@ public class ScoreboardSaveData extends SavedData {
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
PlayerTeam scoreboardteam = (PlayerTeam) iterator.next();
|
||||||
|
+ if (!com.destroystokyo.paper.PaperConfig.saveEmptyScoreboardTeams && scoreboardteam.getPlayers().isEmpty()) continue; // Paper
|
||||||
|
CompoundTag nbttagcompound = new CompoundTag();
|
||||||
|
|
||||||
|
nbttagcompound.putString("Name", scoreboardteam.getName());
|
|
@ -0,0 +1,19 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||||
|
Date: Thu, 12 May 2016 23:02:58 -0500
|
||||||
|
Subject: [PATCH] System property for disabling watchdoge
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
index 0ed95268364ea7f6a92a39b726a1e03bc815be07..ee0cca25ef458f2f0f7e450a2edea2b2adb7e846 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
@@ -61,7 +61,7 @@ public class WatchdogThread extends Thread
|
||||||
|
while ( !stopping )
|
||||||
|
{
|
||||||
|
//
|
||||||
|
- if ( lastTick != 0 && timeoutTime > 0 && monotonicMillis() > lastTick + timeoutTime )
|
||||||
|
+ if ( lastTick != 0 && timeoutTime > 0 && monotonicMillis() > lastTick + timeoutTime && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
|
||||||
|
{
|
||||||
|
Logger log = Bukkit.getServer().getLogger();
|
||||||
|
log.log( Level.SEVERE, "------------------------------" );
|
|
@ -0,0 +1,117 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Mon, 16 May 2016 20:47:41 -0400
|
||||||
|
Subject: [PATCH] Optimize UserCache / Thread Safe
|
||||||
|
|
||||||
|
Because Techable keeps complaining about how this isn't thread safe,
|
||||||
|
easier to do this than replace the entire thing.
|
||||||
|
|
||||||
|
Additionally, move Saving of the User cache to be done async, incase
|
||||||
|
the user never changed the default setting for Spigot's save on stop only.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index 4e468cb7ccf683b8fc9e04a48cfc25779775e25f..211251fe7cd08074c040df2f4642f37d5f90d856 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -905,7 +905,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
} catch (java.lang.InterruptedException ignored) {} // Paper
|
||||||
|
if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) {
|
||||||
|
LOGGER.info("Saving usercache.json");
|
||||||
|
- this.getProfileCache().save();
|
||||||
|
+ this.getProfileCache().b(false); // Paper
|
||||||
|
}
|
||||||
|
// Spigot end
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
index c7655883262f122b373ac30a33ddb4c06cd9aebe..77616b5dd3d79221d3460b1db4d90ad37c0f85aa 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
@@ -248,7 +248,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.convertOldUsers()) {
|
||||||
|
- this.getProfileCache().save();
|
||||||
|
+ this.getProfileCache().b(false); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!OldUsersConverter.serverReadyAfterUserconversion(this)) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java
|
||||||
|
index 6f37f718015000a3df7e5aa2d7b89bdc283a807b..9342fa6b28e805743b8e3a13007605934244d6cd 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java
|
||||||
|
@@ -36,6 +36,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
+import net.minecraft.server.MCUtil;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
@@ -108,7 +109,7 @@ public class GameProfileCache {
|
||||||
|
return GameProfileCache.usesAuthentication;
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void add(GameProfile gameprofile) {
|
||||||
|
+ public synchronized void add(GameProfile gameprofile) { // Paper - synchronize
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
|
||||||
|
calendar.setTime(new Date());
|
||||||
|
@@ -117,7 +118,7 @@ public class GameProfileCache {
|
||||||
|
GameProfileCache.GameProfileInfo usercache_usercacheentry = new GameProfileCache.GameProfileInfo(gameprofile, date);
|
||||||
|
|
||||||
|
this.safeAdd(usercache_usercacheentry);
|
||||||
|
- if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.save(); // Spigot - skip saving if disabled
|
||||||
|
+ if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.b(true); // Spigot - skip saving if disabled // Paper - async
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getNextOperation() {
|
||||||
|
@@ -125,7 +126,7 @@ public class GameProfileCache {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
- public GameProfile get(String s) {
|
||||||
|
+ public synchronized GameProfile get(String s) { // Paper - synchronize
|
||||||
|
String s1 = s.toLowerCase(Locale.ROOT);
|
||||||
|
GameProfileCache.GameProfileInfo usercache_usercacheentry = (GameProfileCache.GameProfileInfo) this.profilesByName.get(s1);
|
||||||
|
boolean flag = false;
|
||||||
|
@@ -151,7 +152,7 @@ public class GameProfileCache {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flag && !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { // Spigot - skip saving if disabled
|
||||||
|
- this.save();
|
||||||
|
+ this.b(true); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
return gameprofile;
|
||||||
|
@@ -233,7 +234,7 @@ public class GameProfileCache {
|
||||||
|
return arraylist;
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void save() {
|
||||||
|
+ public void b(boolean asyncSave) { // Paper
|
||||||
|
JsonArray jsonarray = new JsonArray();
|
||||||
|
DateFormat dateformat = createDateFormat();
|
||||||
|
|
||||||
|
@@ -241,6 +242,7 @@ public class GameProfileCache {
|
||||||
|
jsonarray.add(writeGameProfile(usercache_usercacheentry, dateformat));
|
||||||
|
});
|
||||||
|
String s = this.gson.toJson(jsonarray);
|
||||||
|
+ Runnable save = () -> { // Paper
|
||||||
|
|
||||||
|
try {
|
||||||
|
BufferedWriter bufferedwriter = Files.newWriter(this.file, StandardCharsets.UTF_8);
|
||||||
|
@@ -268,6 +270,14 @@ public class GameProfileCache {
|
||||||
|
} catch (IOException ioexception) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
+ // Paper start
|
||||||
|
+ };
|
||||||
|
+ if (asyncSave) {
|
||||||
|
+ MCUtil.scheduleAsyncTask(save);
|
||||||
|
+ } else {
|
||||||
|
+ save.run();
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Mon, 16 May 2016 23:19:16 -0400
|
||||||
|
Subject: [PATCH] Avoid blocking on Network Manager creation
|
||||||
|
|
||||||
|
Per Paper issue 294
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||||
|
index 9680b0b3879c72776d6225a6a5a89fdfa3520598..6cb51a4fe3c11f53fbb556ce6b0d64b735254d51 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||||
|
@@ -52,6 +52,15 @@ public class ServerConnectionListener {
|
||||||
|
public volatile boolean running;
|
||||||
|
private final List<ChannelFuture> channels = Collections.synchronizedList(Lists.newArrayList());
|
||||||
|
private final List<Connection> connections = Collections.synchronizedList(Lists.newArrayList());
|
||||||
|
+ // Paper start - prevent blocking on adding a new network manager while the server is ticking
|
||||||
|
+ private final java.util.Queue<Connection> pending = new java.util.concurrent.ConcurrentLinkedQueue<>();
|
||||||
|
+ private void addPending() {
|
||||||
|
+ Connection manager = null;
|
||||||
|
+ while ((manager = pending.poll()) != null) {
|
||||||
|
+ connections.add(manager);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
public ServerConnectionListener(MinecraftServer server) {
|
||||||
|
this.server = server;
|
||||||
|
@@ -87,7 +96,8 @@ public class ServerConnectionListener {
|
||||||
|
int j = ServerConnectionListener.this.server.getRateLimitPacketsPerSecond();
|
||||||
|
Object object = j > 0 ? new RateKickingConnection(j) : new Connection(PacketFlow.SERVERBOUND);
|
||||||
|
|
||||||
|
- ServerConnectionListener.this.connections.add((Connection) object); // CraftBukkit - decompile error
|
||||||
|
+ //ServerConnection.this.connectedChannels.add((NetworkManager) object); // CraftBukkit - decompile error
|
||||||
|
+ pending.add((Connection) object); // Paper
|
||||||
|
channel.pipeline().addLast("packet_handler", (ChannelHandler) object);
|
||||||
|
((Connection) object).setListener(new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, (Connection) object));
|
||||||
|
}
|
||||||
|
@@ -126,6 +136,7 @@ public class ServerConnectionListener {
|
||||||
|
|
||||||
|
synchronized (this.connections) {
|
||||||
|
// Spigot Start
|
||||||
|
+ this.addPending(); // Paper
|
||||||
|
// This prevents players from 'gaming' the server, and strategically relogging to increase their position in the tick order
|
||||||
|
if ( org.spigotmc.SpigotConfig.playerShuffle > 0 && MinecraftServer.currentTick % org.spigotmc.SpigotConfig.playerShuffle == 0 )
|
||||||
|
{
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue