More patches

This commit is contained in:
Nassim Jahnke 2023-03-14 19:05:23 +01:00
parent 2cd29ddbb5
commit 2b6be6f1b3
No known key found for this signature in database
GPG key ID: 6BE3B555EBC5982B
34 changed files with 569 additions and 573 deletions

View file

@ -1,172 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kyle Wood <kyle@denwav.dev>
Date: Fri, 11 Jun 2021 05:25:03 -0500
Subject: [PATCH] Remap fixes
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
index 954cf20fb9fbf331fe6314590a3edbe73118ceca..d4c46f44f7a998121482c2fc56d7986881d489d8 100644
--- a/src/main/java/net/minecraft/core/BlockPos.java
+++ b/src/main/java/net/minecraft/core/BlockPos.java
@@ -274,9 +274,11 @@ public class BlockPos extends Vec3i {
public static Iterable<BlockPos> withinManhattan(BlockPos center, int rangeX, int rangeY, int rangeZ) {
int i = rangeX + rangeY + rangeZ;
- int j = center.getX();
- int k = center.getY();
- int l = center.getZ();
+ // Paper start - rename variables to fix conflict with anonymous class (remap fix)
+ int centerX = center.getX();
+ int centerY = center.getY();
+ int centerZ = center.getZ();
+ // Paper end
return () -> {
return new AbstractIterator<BlockPos>() {
private final BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
@@ -291,7 +293,7 @@ public class BlockPos extends Vec3i {
protected BlockPos computeNext() {
if (this.zMirror) {
this.zMirror = false;
- this.cursor.setZ(l - (this.cursor.getZ() - l));
+ this.cursor.setZ(centerZ - (this.cursor.getZ() - centerZ)); // Paper - remap fix
return this.cursor;
} else {
BlockPos blockPos;
@@ -317,7 +319,7 @@ public class BlockPos extends Vec3i {
int k = this.currentDepth - Math.abs(i) - Math.abs(j);
if (k <= rangeZ) {
this.zMirror = k != 0;
- blockPos = this.cursor.set(j + i, k + j, l + k);
+ blockPos = this.cursor.set(centerX + i, centerY + j, centerZ + k); // Paper - remap fix
}
}
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index b1ecaf47486eaa876e2286eae894b47ecf3a0849..01438ee9ad7a64ac4fd124d97029f87b49c25d5d 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1419,9 +1419,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
LevelChunk chunk1;
if (chunk instanceof LevelChunk) {
- LevelChunk chunk1 = (LevelChunk) chunk;
-
- chunk1 = chunk1;
+ chunk1 = (LevelChunk) chunk; // Paper - remap fix
} else {
chunk1 = this.level.getChunk(chunkcoordintpair.x, chunkcoordintpair.z);
}
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java
index 8f0a2f8d3a34c6b97bc7a933272ccf2689576c76..b9fcff8862e624644fdb73afcb3ef2106b0a76fc 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java
@@ -173,11 +173,11 @@ public class BehaviorUtils {
return optional.map((uuid) -> {
return ((ServerLevel) entity.level).getEntity(uuid);
- }).map((entity) -> {
+ }).map((entity1) -> { // Paper - remap fix
LivingEntity entityliving1;
- if (entity instanceof LivingEntity) {
- LivingEntity entityliving2 = (LivingEntity) entity;
+ if (entity1 instanceof LivingEntity) { // Paper - remap fix
+ LivingEntity entityliving2 = (LivingEntity) entity1; // Paper - remap fix
entityliving1 = entityliving2;
} else {
diff --git a/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java b/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java
index 0b76584d85194f0b60ed51f577353bfead0489f5..d025df087e7b87fbc89a722226f2f2263c54ac47 100644
--- a/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java
+++ b/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java
@@ -192,7 +192,7 @@ public class RecipeManager extends SimpleJsonResourceReloadListener {
Builder<ResourceLocation, Recipe<?>> builder = ImmutableMap.builder();
recipes.forEach((irecipe) -> {
- Map<ResourceLocation, Recipe<?>> map1 = (Map) map.computeIfAbsent(irecipe.getType(), (recipes) -> {
+ Map<ResourceLocation, Recipe<?>> map1 = (Map) map.computeIfAbsent(irecipe.getType(), (recipes_) -> { // Paper - remap fix
return new Object2ObjectLinkedOpenHashMap<>(); // CraftBukkit
});
ResourceLocation minecraftkey = irecipe.getId();
diff --git a/src/test/java/org/bukkit/DyeColorsTest.java b/src/test/java/org/bukkit/DyeColorsTest.java
index ad52c3fc6210939a39ef77a382c640a24ee44838..6b7dd01778f0a5d3a96d2d04af4b525d17efbfba 100644
--- a/src/test/java/org/bukkit/DyeColorsTest.java
+++ b/src/test/java/org/bukkit/DyeColorsTest.java
@@ -4,7 +4,6 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
-import net.minecraft.world.item.DyeColor;
import org.bukkit.support.AbstractTestingBase;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -29,7 +28,7 @@ public class DyeColorsTest extends AbstractTestingBase {
@Test
public void checkColor() {
Color color = this.dye.getColor();
- float[] nmsColorArray = DyeColor.byId(this.dye.getWoolData()).getTextureDiffuseColors();
+ float[] nmsColorArray = net.minecraft.world.item.DyeColor.byId(this.dye.getWoolData()).getTextureDiffuseColors(); // Paper - remap fix
Color nmsColor = Color.fromRGB((int) (nmsColorArray[0] * 255), (int) (nmsColorArray[1] * 255), (int) (nmsColorArray[2] * 255));
assertThat(color, is(nmsColor));
}
@@ -37,7 +36,7 @@ public class DyeColorsTest extends AbstractTestingBase {
@Test
public void checkFireworkColor() {
Color color = this.dye.getFireworkColor();
- int nmsColor = DyeColor.byId(this.dye.getWoolData()).getFireworkColor();
+ int nmsColor = net.minecraft.world.item.DyeColor.byId(this.dye.getWoolData()).getFireworkColor(); // Paper - remap fix
assertThat(color, is(Color.fromRGB(nmsColor)));
}
}
diff --git a/src/test/java/org/bukkit/entity/EntityTypesTest.java b/src/test/java/org/bukkit/entity/EntityTypesTest.java
index b1de312e902c83a2f95d80040abb9255e64431a9..aafa6f472c82f851fe7f5ae3111488bb732d0bcc 100644
--- a/src/test/java/org/bukkit/entity/EntityTypesTest.java
+++ b/src/test/java/org/bukkit/entity/EntityTypesTest.java
@@ -5,7 +5,6 @@ import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
-import net.minecraft.world.entity.EntityType;
import org.bukkit.support.AbstractTestingBase;
import org.junit.Assert;
import org.junit.Test;
@@ -16,8 +15,8 @@ public class EntityTypesTest extends AbstractTestingBase {
public void testMaps() {
Set<EntityType> allBukkit = Arrays.stream(EntityType.values()).filter((b) -> b.getName() != null).collect(Collectors.toSet());
- for (EntityType<?> nms : BuiltInRegistries.ENTITY_TYPE) {
- ResourceLocation key = EntityType.getKey(nms);
+ for (net.minecraft.world.entity.EntityType<?> nms : BuiltInRegistries.ENTITY_TYPE) { // Paper - remap fix
+ ResourceLocation key = net.minecraft.world.entity.EntityType.getKey(nms); // Paper - remap fix
org.bukkit.entity.EntityType bukkit = org.bukkit.entity.EntityType.fromName(key.getPath());
Assert.assertNotNull("Missing nms->bukkit " + key, bukkit);
diff --git a/src/test/java/org/bukkit/entity/PandaGeneTest.java b/src/test/java/org/bukkit/entity/PandaGeneTest.java
index 76e2ad676ae68846bdff3c3ef711751445fb0f3c..feee17192bca55a9cf1b2fc5b9609b888db77763 100644
--- a/src/test/java/org/bukkit/entity/PandaGeneTest.java
+++ b/src/test/java/org/bukkit/entity/PandaGeneTest.java
@@ -1,6 +1,5 @@
package org.bukkit.entity;
-import net.minecraft.world.entity.animal.Panda;
import org.bukkit.craftbukkit.entity.CraftPanda;
import org.junit.Assert;
import org.junit.Test;
@@ -10,7 +9,7 @@ public class PandaGeneTest {
@Test
public void testBukkit() {
for (Panda.Gene gene : Panda.Gene.values()) {
- Panda.Gene nms = CraftPanda.toNms(gene);
+ net.minecraft.world.entity.animal.Panda.Gene nms = CraftPanda.toNms(gene); // Paper - remap fix
Assert.assertNotNull("NMS gene null for " + gene, nms);
Assert.assertEquals("Recessive status did not match " + gene, gene.isRecessive(), nms.isRecessive());
@@ -20,7 +19,7 @@ public class PandaGeneTest {
@Test
public void testNMS() {
- for (Panda.Gene gene : Panda.Gene.values()) {
+ for (net.minecraft.world.entity.animal.Panda.Gene gene : net.minecraft.world.entity.animal.Panda.Gene.values()) { // Paper - remap fix
org.bukkit.entity.Panda.Gene bukkit = CraftPanda.fromNms(gene);
Assert.assertNotNull("Bukkit gene null for " + gene, bukkit);

View file

@ -1,94 +0,0 @@
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] Build system changes
diff --git a/build.gradle.kts b/build.gradle.kts
index c9950851db38df64fd82a3a549072d240e37d64d..ce176ef04e211b82020fa082b9cb1bdc4769a526 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -9,10 +9,9 @@ plugins {
dependencies {
implementation(project(":paper-api"))
implementation("jline:jline:2.12.1")
- implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") {
- exclude(group = "org.apache.logging.log4j", module = "log4j-api")
- }
+ implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion
implementation("org.ow2.asm:asm:9.4")
+ implementation("org.ow2.asm:asm-commons:9.4") // Paper - ASM event executor generation
implementation("commons-lang:commons-lang:2.6")
runtimeOnly("org.xerial:sqlite-jdbc:3.36.0.3")
runtimeOnly("mysql:mysql-connector-java:8.0.29")
@@ -23,6 +22,8 @@ dependencies {
testImplementation("junit:junit:4.13.2")
testImplementation("org.hamcrest:hamcrest-library:1.3")
+
+ implementation("io.netty:netty-all:4.1.87.Final"); // Paper - Bump netty
}
val craftbukkitPackageVersion = "1_19_R2" // Paper
@@ -34,6 +35,7 @@ tasks.jar {
val gitHash = git("rev-parse", "--short=7", "HEAD").getText().trim()
val implementationVersion = System.getenv("BUILD_NUMBER") ?: "\"$gitHash\""
val date = git("show", "-s", "--format=%ci", gitHash).getText().trim() // Paper
+ val gitBranch = git("rev-parse", "--abbrev-ref", "HEAD").getText().trim() // Paper
attributes(
"Main-Class" to "org.bukkit.craftbukkit.Main",
"Implementation-Title" to "CraftBukkit",
@@ -42,6 +44,9 @@ tasks.jar {
"Specification-Title" to "Bukkit",
"Specification-Version" to project.version,
"Specification-Vendor" to "Bukkit Team",
+ "Git-Branch" to gitBranch, // Paper
+ "Git-Commit" to gitHash, // Paper
+ "CraftBukkit-Package-Version" to craftbukkitPackageVersion, // Paper
)
for (tld in setOf("net", "com", "org")) {
attributes("$tld/bukkit", "Sealed" to true)
@@ -75,6 +80,17 @@ tasks.shadowJar {
}
}
+// Paper start
+val scanJar = tasks.register("scanJarForBadCalls", io.papermc.paperweight.tasks.ScanJarForBadCalls::class) {
+ badAnnotations.add("Lio/papermc/paper/annotation/DoNotUse;")
+ jarToScan.set(tasks.shadowJar.flatMap { it.archiveFile })
+ classpath.from(configurations.compileClasspath)
+}
+tasks.check {
+ dependsOn(scanJar)
+}
+// Paper end
+
tasks.test {
exclude("org/bukkit/craftbukkit/inventory/ItemStack*Test.class")
}
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index 2e216027fc38fabf3e3e49dbc310ecb648ab63d6..2ae4dbd8cc49efb93ecceeb9a7a08e1a8af1d84a 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -192,7 +192,7 @@ public class Main {
}
if (Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) {
- Date buildDate = new Date(Integer.parseInt(Main.class.getPackage().getImplementationVendor()) * 1000L);
+ Date buildDate = new java.text.SimpleDateFormat("yyyy-MM-dd 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..774556a62eb240da42e84db4502e2ed43495be17 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/io.papermc.paper/paper-api/pom.properties");
Properties properties = new Properties();
if (stream != null) {

View file

@ -1,281 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 13 Feb 2023 14:14:56 -0800
Subject: [PATCH] Test changes
diff --git a/build.gradle.kts b/build.gradle.kts
index ce176ef04e211b82020fa082b9cb1bdc4769a526..15456e54d8a392e702a30dfb3d06a3f74156dce7 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -12,6 +12,7 @@ dependencies {
implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion
implementation("org.ow2.asm:asm:9.4")
implementation("org.ow2.asm:asm-commons:9.4") // Paper - ASM event executor generation
+ testImplementation("org.mockito:mockito-core:4.9.0") // Paper - switch to mockito
implementation("commons-lang:commons-lang:2.6")
runtimeOnly("org.xerial:sqlite-jdbc:3.36.0.3")
runtimeOnly("mysql:mysql-connector-java:8.0.29")
diff --git a/src/test/java/io/papermc/paper/testing/DummyServer.java b/src/test/java/io/papermc/paper/testing/DummyServer.java
new file mode 100644
index 0000000000000000000000000000000000000000..c6503ff76f56bab5f383f0ca17d137155e9be447
--- /dev/null
+++ b/src/test/java/io/papermc/paper/testing/DummyServer.java
@@ -0,0 +1,67 @@
+package io.papermc.paper.testing;
+
+import java.util.logging.Logger;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
+import org.bukkit.Server;
+import org.bukkit.command.SimpleCommandMap;
+import org.bukkit.craftbukkit.CraftRegistry;
+import org.bukkit.craftbukkit.block.data.CraftBlockData;
+import org.bukkit.craftbukkit.inventory.CraftItemFactory;
+import org.bukkit.craftbukkit.util.CraftMagicNumbers;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+import org.bukkit.plugin.PluginManager;
+import org.bukkit.plugin.SimplePluginManager;
+import org.bukkit.support.AbstractTestingBase;
+import org.mockito.Mockito;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public final class DummyServer {
+
+ @SuppressWarnings({"deprecation", "removal"})
+ public static void setup() {
+ //noinspection ConstantValue
+ if (Bukkit.getServer() != null) {
+ return;
+ }
+
+ final Server dummyServer = mock(Server.class, Mockito.withSettings().stubOnly());
+
+ final Logger logger = Logger.getLogger(DummyServer.class.getCanonicalName());
+ when(dummyServer.getLogger()).thenReturn(logger);
+ when(dummyServer.getName()).thenReturn(DummyServer.class.getSimpleName());
+ when(dummyServer.getVersion()).thenReturn("Version_" + DummyServer.class.getPackage().getImplementationVersion());
+ when(dummyServer.getBukkitVersion()).thenReturn("BukkitVersion_" + DummyServer.class.getPackage().getImplementationVersion());
+
+ final Thread currentThread = Thread.currentThread();
+ when(dummyServer.isPrimaryThread()).thenAnswer(ignored -> Thread.currentThread().equals(currentThread));
+
+ when(dummyServer.getItemFactory()).thenReturn(CraftItemFactory.instance());
+
+ when(dummyServer.getUnsafe()).thenAnswer(ignored -> CraftMagicNumbers.INSTANCE); // lambda for lazy load
+
+ when(dummyServer.createBlockData(any(Material.class))).thenAnswer(invocation -> {
+ return CraftBlockData.newData(invocation.getArgument(0, Material.class), null);
+ });
+
+ when(dummyServer.getLootTable(any(NamespacedKey.class))).thenAnswer(invocation -> {
+ final NamespacedKey key = invocation.getArgument(0, NamespacedKey.class);
+ return new org.bukkit.craftbukkit.CraftLootTable(key, AbstractTestingBase.DATA_PACK.getLootTables().get(CraftNamespacedKey.toMinecraft(key)));
+ });
+
+ when(dummyServer.getRegistry(any())).thenAnswer(invocation -> {
+ // LazyRegistry because the vanilla data hasn't been bootstrapped yet.
+ return new LazyRegistry(() -> CraftRegistry.createRegistry(invocation.getArgument(0, Class.class), AbstractTestingBase.REGISTRY_CUSTOM));
+ });
+
+ final PluginManager pluginManager = new SimplePluginManager(dummyServer, new SimpleCommandMap(dummyServer));
+ when(dummyServer.getPluginManager()).thenReturn(pluginManager);
+
+ Bukkit.setServer(dummyServer);
+
+ }
+}
diff --git a/src/test/java/io/papermc/paper/testing/LazyRegistry.java b/src/test/java/io/papermc/paper/testing/LazyRegistry.java
new file mode 100644
index 0000000000000000000000000000000000000000..8dd0df8c2cc25d37a2590a07872682230a9335f2
--- /dev/null
+++ b/src/test/java/io/papermc/paper/testing/LazyRegistry.java
@@ -0,0 +1,23 @@
+package io.papermc.paper.testing;
+
+import java.util.Iterator;
+import java.util.function.Supplier;
+import org.bukkit.Keyed;
+import org.bukkit.NamespacedKey;
+import org.bukkit.Registry;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public record LazyRegistry(Supplier<Registry<Keyed>> supplier) implements Registry<Keyed> {
+
+ @NotNull
+ @Override
+ public Iterator<Keyed> iterator() {
+ return this.supplier().get().iterator();
+ }
+
+ @Override
+ public @Nullable Keyed get(@NotNull final NamespacedKey key) {
+ return this.supplier().get().get(key);
+ }
+}
diff --git a/src/test/java/org/bukkit/support/AbstractTestingBase.java b/src/test/java/org/bukkit/support/AbstractTestingBase.java
index 492c1ec28a9f1facb117d05245b32231554385ad..8013cc99c063d2ca0c578c093e3112676f5361b7 100644
--- a/src/test/java/org/bukkit/support/AbstractTestingBase.java
+++ b/src/test/java/org/bukkit/support/AbstractTestingBase.java
@@ -2,7 +2,6 @@ package org.bukkit.support;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.MoreExecutors;
-import java.util.Collections;
import java.util.List;
import net.minecraft.SharedConstants;
import net.minecraft.commands.Commands;
@@ -49,6 +48,7 @@ public abstract class AbstractTestingBase {
LayeredRegistryAccess<RegistryLayer> layers = RegistryLayer.createRegistryAccess();
layers = WorldLoader.loadAndReplaceLayer(resourceManager, layers, RegistryLayer.WORLDGEN, RegistryDataLoader.WORLDGEN_REGISTRIES);
REGISTRY_CUSTOM = layers.compositeAccess().freeze();
+ io.papermc.paper.testing.DummyServer.setup(); // Paper
// Register vanilla pack
DATA_PACK = ReloadableServerResources.loadResources(resourceManager, REGISTRY_CUSTOM, FeatureFlags.REGISTRY.allFlags(), Commands.CommandSelection.DEDICATED, 0, MoreExecutors.directExecutor(), MoreExecutors.directExecutor()).join();
// Bind tags
@@ -56,7 +56,6 @@ public abstract class AbstractTestingBase {
// Biome shortcut
BIOMES = REGISTRY_CUSTOM.registryOrThrow(Registries.BIOME);
- DummyServer.setup();
DummyEnchantments.setup();
ImmutableList.Builder<Material> builder = ImmutableList.builder();
diff --git a/src/test/java/org/bukkit/support/DummyServer.java b/src/test/java/org/bukkit/support/DummyServer.java
deleted file mode 100644
index 946497353a64421592d2bae012c9a3cb874dd5b8..0000000000000000000000000000000000000000
--- a/src/test/java/org/bukkit/support/DummyServer.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package org.bukkit.support;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.HashMap;
-import java.util.logging.Logger;
-import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.NamespacedKey;
-import org.bukkit.Server;
-import org.bukkit.craftbukkit.CraftLootTable;
-import org.bukkit.craftbukkit.CraftRegistry;
-import org.bukkit.craftbukkit.block.data.CraftBlockData;
-import org.bukkit.craftbukkit.inventory.CraftItemFactory;
-import org.bukkit.craftbukkit.util.CraftMagicNumbers;
-import org.bukkit.craftbukkit.util.CraftNamespacedKey;
-import org.bukkit.craftbukkit.util.Versioning;
-
-public final class DummyServer implements InvocationHandler {
- private static interface MethodHandler {
- Object handle(DummyServer server, Object[] args);
- }
- private static final HashMap<Method, MethodHandler> methods = new HashMap<Method, MethodHandler>();
- static {
- try {
- methods.put(
- Server.class.getMethod("getItemFactory"),
- new MethodHandler() {
- @Override
- public Object handle(DummyServer server, Object[] args) {
- return CraftItemFactory.instance();
- }
- }
- );
- methods.put(
- Server.class.getMethod("getName"),
- new MethodHandler() {
- @Override
- public Object handle(DummyServer server, Object[] args) {
- return DummyServer.class.getName();
- }
- }
- );
- methods.put(
- Server.class.getMethod("getVersion"),
- new MethodHandler() {
- @Override
- public Object handle(DummyServer server, Object[] args) {
- return DummyServer.class.getPackage().getImplementationVersion();
- }
- }
- );
- methods.put(
- Server.class.getMethod("getBukkitVersion"),
- new MethodHandler() {
- @Override
- public Object handle(DummyServer server, Object[] args) {
- return Versioning.getBukkitVersion();
- }
- }
- );
- methods.put(
- Server.class.getMethod("getLogger"),
- new MethodHandler() {
- final Logger logger = Logger.getLogger(DummyServer.class.getCanonicalName());
- @Override
- public Object handle(DummyServer server, Object[] args) {
- return logger;
- }
- }
- );
- methods.put(
- Server.class.getMethod("getUnsafe"),
- new MethodHandler() {
- @Override
- public Object handle(DummyServer server, Object[] args) {
- return CraftMagicNumbers.INSTANCE;
- }
- }
- );
- methods.put(
- Server.class.getMethod("createBlockData", Material.class),
- new MethodHandler() {
- final Logger logger = Logger.getLogger(DummyServer.class.getCanonicalName());
- @Override
- public Object handle(DummyServer server, Object[] args) {
- return CraftBlockData.newData((Material) args[0], null);
- }
- }
- );
- methods.put(Server.class.getMethod("getLootTable", NamespacedKey.class),
- new MethodHandler() {
- @Override
- public Object handle(DummyServer server, Object[] args) {
- NamespacedKey key = (NamespacedKey) args[0];
- return new CraftLootTable(key, AbstractTestingBase.DATA_PACK.getLootTables().get(CraftNamespacedKey.toMinecraft(key)));
- }
- }
- );
- methods.put(Server.class.getMethod("getRegistry", Class.class),
- new MethodHandler() {
- @Override
- public Object handle(DummyServer server, Object[] args) {
- return CraftRegistry.createRegistry((Class) args[0], AbstractTestingBase.REGISTRY_CUSTOM);
- }
- }
- );
- Bukkit.setServer(Proxy.getProxyClass(Server.class.getClassLoader(), Server.class).asSubclass(Server.class).getConstructor(InvocationHandler.class).newInstance(new DummyServer()));
- } catch (Throwable t) {
- throw new Error(t);
- }
- }
-
- public static void setup() {}
-
- private DummyServer() {};
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) {
- MethodHandler handler = DummyServer.methods.get(method);
- if (handler != null) {
- return handler.handle(this, args);
- }
- throw new UnsupportedOperationException(String.valueOf(method));
- }
-}

File diff suppressed because it is too large Load diff

View file

@ -1,224 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 30 Mar 2016 19:36:20 -0400
Subject: [PATCH] MC Dev fixes
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
index d33cce0265a85a23d726742e7752331b63449144..dc7a805d3058244ba13c2268666f274e7ec069dc 100644
--- a/src/main/java/net/minecraft/Util.java
+++ b/src/main/java/net/minecraft/Util.java
@@ -370,7 +370,7 @@ public class Util {
}
public static <K> Hash.Strategy<K> identityStrategy() {
- return Util.IdentityStrategy.INSTANCE;
+ return (Hash.Strategy<K>) Util.IdentityStrategy.INSTANCE; // Paper - decompile fix
}
public static <V> CompletableFuture<List<V>> sequence(List<? extends CompletableFuture<V>> futures) {
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
index d4c46f44f7a998121482c2fc56d7986881d489d8..6801a3aa5f2f1e9a7a72ff81c09b4944ecb8349d 100644
--- a/src/main/java/net/minecraft/core/BlockPos.java
+++ b/src/main/java/net/minecraft/core/BlockPos.java
@@ -379,12 +379,12 @@ public class BlockPos extends Vec3i {
if (this.index == l) {
return this.endOfData();
} else {
- int i = this.index % i;
- int j = this.index / i;
- int k = j % j;
- int l = j / j;
+ int offsetX = this.index % i; // Paper - decomp fix
+ int u = this.index / i; // Paper - decomp fix
+ int offsetY = u % j; // Paper - decomp fix
+ int offsetZ = u / j; // Paper - decomp fix
++this.index;
- return this.cursor.set(startX + i, startY + k, startZ + l);
+ return this.cursor.set(startX + offsetX, startY + offsetY, startZ + offsetZ); // Paper - decomp fix
}
}
};
diff --git a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java
index 3233f69345838af653b4259d2142169930533a69..5b8ecf5b0165ed2cd4397cdee958e97c2e8f18d5 100644
--- a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java
+++ b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java
@@ -305,7 +305,7 @@ public class BuiltInRegistries {
LOADERS.put(resourceLocation, () -> {
return initializer.run(registry);
});
- WRITABLE_REGISTRY.register(key, registry, lifecycle);
+ WRITABLE_REGISTRY.register((ResourceKey) key, registry, lifecycle); // Paper - decompile fix
return registry;
}
diff --git a/src/main/java/net/minecraft/nbt/NbtUtils.java b/src/main/java/net/minecraft/nbt/NbtUtils.java
index 24e864d1cd376e9f94cfa68fd06f96b239eed888..c0fe7c576f2361e599bc23003da7c49bb7cb62b2 100644
--- a/src/main/java/net/minecraft/nbt/NbtUtils.java
+++ b/src/main/java/net/minecraft/nbt/NbtUtils.java
@@ -505,7 +505,7 @@ public final class NbtUtils {
}
public static CompoundTag update(DataFixer fixer, DataFixTypes fixTypes, CompoundTag compound, int oldVersion, int targetVersion) {
- return fixer.update(fixTypes.getType(), new Dynamic<>(NbtOps.INSTANCE, compound), oldVersion, targetVersion).getValue();
+ return (CompoundTag) fixer.update(fixTypes.getType(), new Dynamic<>(NbtOps.INSTANCE, compound), oldVersion, targetVersion).getValue(); // Paper - decompile fix
}
public static Component toPrettyComponent(Tag element) {
diff --git a/src/main/java/net/minecraft/network/chat/ComponentUtils.java b/src/main/java/net/minecraft/network/chat/ComponentUtils.java
index 2df8fa1ae2dc58291add80fae0599ee4ff5066ee..ed7e1a6fc745df745d5bc79623948bb1015c9252 100644
--- a/src/main/java/net/minecraft/network/chat/ComponentUtils.java
+++ b/src/main/java/net/minecraft/network/chat/ComponentUtils.java
@@ -138,8 +138,7 @@ public class ComponentUtils {
ComponentContents string = text.getContents();
if (string instanceof TranslatableContents) {
TranslatableContents translatableContents = (TranslatableContents)string;
- String string = translatableContents.getKey();
- return Language.getInstance().has(string);
+ return Language.getInstance().has(translatableContents.getKey()); // Paper - decompile fix
}
}
diff --git a/src/main/java/net/minecraft/resources/RegistryDataLoader.java b/src/main/java/net/minecraft/resources/RegistryDataLoader.java
index bc7c6b40ec160d7d449546265b9808e15e587247..178215878c4bbf4ddb24002fcd6d1156a44494ff 100644
--- a/src/main/java/net/minecraft/resources/RegistryDataLoader.java
+++ b/src/main/java/net/minecraft/resources/RegistryDataLoader.java
@@ -87,7 +87,7 @@ public class RegistryDataLoader {
return new RegistryOps.RegistryInfoLookup() {
@Override
public <T> Optional<RegistryOps.RegistryInfo<T>> lookup(ResourceKey<? extends Registry<? extends T>> registryRef) {
- return Optional.ofNullable(map.get(registryRef));
+ return Optional.ofNullable((RegistryOps.RegistryInfo<T>) map.get(registryRef)); // Paper - decompile fix
}
};
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 870db0028becd6b76af76190fae908d0031ed94d..06b1da8b559f9d545f1593d81de7b25e0a12f176 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1747,7 +1747,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
PackRepository resourcepackrepository = this.packRepository;
Objects.requireNonNull(this.packRepository);
- return stream.map(resourcepackrepository::getPack).filter(Objects::nonNull).map(Pack::open).collect(ImmutableList.toImmutableList()); // CraftBukkit - decompile error
+ return stream.<Pack>map(resourcepackrepository::getPack).filter(Objects::nonNull).map(Pack::open).collect(ImmutableList.toImmutableList()); // CraftBukkit - decompile error // Paper - decompile error // todo: is this needed anymore?
}, this).thenCompose((immutablelist) -> {
MultiPackResourceManager resourcemanager = new MultiPackResourceManager(PackType.SERVER_DATA, immutablelist);
diff --git a/src/main/java/net/minecraft/server/level/Ticket.java b/src/main/java/net/minecraft/server/level/Ticket.java
index 2f66abf62d303342f5fe614fb3e35e7844497ffc..b346fa94b23d81da7da073f71dd12e672e0f079c 100644
--- a/src/main/java/net/minecraft/server/level/Ticket.java
+++ b/src/main/java/net/minecraft/server/level/Ticket.java
@@ -21,7 +21,7 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
return i;
} else {
int j = Integer.compare(System.identityHashCode(this.type), System.identityHashCode(ticket.type));
- return j != 0 ? j : this.type.getComparator().compare(this.key, ticket.key);
+ return j != 0 ? j : this.type.getComparator().compare(this.key, (T)ticket.key); // Paper - decompile fix
}
}
diff --git a/src/main/java/net/minecraft/util/SortedArraySet.java b/src/main/java/net/minecraft/util/SortedArraySet.java
index 2dc801061025888192c3bf2c4c38b928c16a0165..ca788f0dcec4a117b410fe8348969e056b138b1e 100644
--- a/src/main/java/net/minecraft/util/SortedArraySet.java
+++ b/src/main/java/net/minecraft/util/SortedArraySet.java
@@ -28,7 +28,7 @@ public class SortedArraySet<T> extends AbstractSet<T> {
}
public static <T extends Comparable<T>> SortedArraySet<T> create(int initialCapacity) {
- return new SortedArraySet<>(initialCapacity, Comparator.naturalOrder());
+ return new SortedArraySet<>(initialCapacity, Comparator.<T>naturalOrder()); // Paper - decompile fix
}
public static <T> SortedArraySet<T> create(Comparator<T> comparator) {
diff --git a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java
index 02c10fcdad18f7194e804d94449f291d636163a2..2222a8be261142dd7a42170ad3fe314eeea1deb5 100644
--- a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java
+++ b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java
@@ -147,7 +147,7 @@ public class Camel extends AbstractHorse implements PlayerRideableJumping, Rider
@Override
protected void customServerAiStep() {
this.level.getProfiler().push("camelBrain");
- Brain<?> brain = this.getBrain();
+ Brain<Camel> brain = (Brain<Camel>) this.getBrain(); // Paper - decompile fix
brain.tick((ServerLevel)this.level, this);
this.level.getProfiler().pop();
this.level.getProfiler().push("camelActivityUpdate");
diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java
index 471b9258320ba0002d741267144c80c149f5f34c..8852cc6253c8bc1a9f7591cd2b0beb95bb4f4d33 100644
--- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java
+++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java
@@ -106,7 +106,7 @@ public class Frog extends Animal implements VariantHolder<FrogVariant> {
@Override
public Brain<Frog> getBrain() {
- return super.getBrain();
+ return (Brain<Frog>) super.getBrain(); // Paper - decompile fix
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java
index 64314cf4dc53a1a0a5f676fa00503858e0120dfa..45741410a13cffe3419e34b5607b048bbcf1c3ff 100644
--- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java
+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java
@@ -123,7 +123,7 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
@Override
public Brain<Hoglin> getBrain() {
- return super.getBrain();
+ return (Brain<Hoglin>) super.getBrain(); // Paper - decompile fix
}
@Override
diff --git a/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java b/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java
index d025df087e7b87fbc89a722226f2f2263c54ac47..2f712bfc1f717ba410bf34669d7b0a919ca218cc 100644
--- a/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java
+++ b/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java
@@ -78,7 +78,7 @@ public class RecipeManager extends SimpleJsonResourceReloadListener {
}
this.recipes = (Map) map1.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry1) -> {
- return (entry1.getValue()); // CraftBukkit
+ return entry1.getValue(); // CraftBukkit // Paper - decompile fix - *shrugs internally* // todo: is this needed anymore?
}));
this.byName = Maps.newHashMap(builder.build()); // CraftBukkit
RecipeManager.LOGGER.info("Loaded {} recipes", map1.size());
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 7798cbbae6b72d64e6129cebf1f66696f21e15f9..240c19f4a7552a01b3c48f1f6413119e4cfc2b67 100644
--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
@@ -56,7 +56,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
}
private static <T, C extends PalettedContainerRO<T>> Codec<C> codec(IdMap<T> idList, Codec<T> entryCodec, PalettedContainer.Strategy provider, T defaultValue, PalettedContainerRO.Unpacker<T, C> reader) {
- return RecordCodecBuilder.<PalettedContainerRO.PackedData>create((instance) -> {
+ return RecordCodecBuilder.<PalettedContainerRO.PackedData<T>>create((instance) -> { // Paper - decompile fix
return instance.group(entryCodec.mapResult(ExtraCodecs.orElsePartial(defaultValue)).listOf().fieldOf("palette").forGetter(PalettedContainerRO.PackedData::paletteEntries), Codec.LONG_STREAM.optionalFieldOf("data").forGetter(PalettedContainerRO.PackedData::storage)).apply(instance, PalettedContainerRO.PackedData::new);
}).comapFlatMap((serialized) -> {
return reader.read(idList, provider, serialized);
diff --git a/src/main/java/net/minecraft/world/level/entity/EntityLookup.java b/src/main/java/net/minecraft/world/level/entity/EntityLookup.java
index 6b91771a4bf559881a4f3e6c98500e09b33d16e0..21a2800db22f287b9c6a8290326fdf3b94ae94b1 100644
--- a/src/main/java/net/minecraft/world/level/entity/EntityLookup.java
+++ b/src/main/java/net/minecraft/world/level/entity/EntityLookup.java
@@ -19,7 +19,7 @@ public class EntityLookup<T extends EntityAccess> {
public <U extends T> void getEntities(EntityTypeTest<T, U> filter, AbortableIterationConsumer<U> consumer) {
for(T entityAccess : this.byId.values()) {
U entityAccess2 = (U)((EntityAccess)filter.tryCast(entityAccess));
- if (entityAccess2 != null && consumer.accept((T)entityAccess2).shouldAbort()) {
+ if (entityAccess2 != null && consumer.accept(entityAccess2).shouldAbort()) { // Paper - decompile fix
return;
}
}
diff --git a/src/main/java/net/minecraft/world/level/entity/EntitySection.java b/src/main/java/net/minecraft/world/level/entity/EntitySection.java
index 69a19dbf58cde41680d086e78b9a12ffee602dbf..5dcb7f9cab097990148f5a7c4ccbe1556afdd514 100644
--- a/src/main/java/net/minecraft/world/level/entity/EntitySection.java
+++ b/src/main/java/net/minecraft/world/level/entity/EntitySection.java
@@ -44,7 +44,7 @@ public class EntitySection<T extends EntityAccess> {
} else {
for(T entityAccess : collection) {
U entityAccess2 = (U)((EntityAccess)type.tryCast(entityAccess));
- if (entityAccess2 != null && entityAccess.getBoundingBox().intersects(box) && consumer.accept((T)entityAccess2).shouldAbort()) {
+ if (entityAccess2 != null && entityAccess.getBoundingBox().intersects(box) && consumer.accept(entityAccess2).shouldAbort()) { // Paper - decompile fix
return AbortableIterationConsumer.Continuation.ABORT;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,116 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Fri, 25 Feb 2022 07:14:48 -0800
Subject: [PATCH] CB fixes
* Missing Level -> LevelStem generic in StructureCheck
Need to use the right for injectDatafixingContext (Spottedleaf)
* Removed incorrect parent perm for `minecraft.debugstick.always` (Machine_Maker)
* Fixed method signature of Marker#addPassenger (Machine_Maker)
* Removed unneeded UOE in CustomWorldChunkManager (extends BiomeSource) (Machine_Maker)
* Honor Server#getLootTable method contract (Machine_Maker)
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index ae219be37c5fcec3dd3f8b08819551003e66d351..8309eb14140ebcf62ae7be1dfa0177ac7fcf83d7 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -294,7 +294,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
long l = minecraftserver.getWorldData().worldGenOptions().seed();
- this.structureCheck = new StructureCheck(this.chunkSource.chunkScanner(), this.registryAccess(), minecraftserver.getStructureManager(), resourcekey, chunkgenerator, this.chunkSource.randomState(), this, chunkgenerator.getBiomeSource(), l, datafixer);
+ this.structureCheck = new StructureCheck(this.chunkSource.chunkScanner(), this.registryAccess(), minecraftserver.getStructureManager(), this.getTypeKey(), chunkgenerator, this.chunkSource.randomState(), this, chunkgenerator.getBiomeSource(), l, datafixer); // Paper - Fix missing CB diff
this.structureManager = new StructureManager(this, this.serverLevelData.worldGenOptions(), this.structureCheck); // CraftBukkit
if ((this.dimension() == Level.END && this.dimensionTypeRegistration().is(BuiltinDimensionTypes.END)) || env == org.bukkit.World.Environment.THE_END) { // CraftBukkit - Allow to create EnderDragonBattle in default and custom END
this.dragonFight = new EndDragonFight(this, this.serverLevelData.worldGenOptions().seed(), this.serverLevelData.endDragonFightData()); // CraftBukkit
diff --git a/src/main/java/net/minecraft/world/entity/Marker.java b/src/main/java/net/minecraft/world/entity/Marker.java
index d9f07a311ec5a253bdfb681414e1f8033a576a23..6f110ece5686d1fc73b93fb9e0a73f2c1bcf4586 100644
--- a/src/main/java/net/minecraft/world/entity/Marker.java
+++ b/src/main/java/net/minecraft/world/entity/Marker.java
@@ -39,8 +39,9 @@ public class Marker extends Entity {
}
@Override
- protected void addPassenger(Entity passenger) {
+ protected boolean addPassenger(Entity passenger) { // Paper - fix upstream
passenger.stopRiding();
+ return false; // Paper - fix upstream
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java
index 2222a8be261142dd7a42170ad3fe314eeea1deb5..136da73e372b59f37665743c70833e815cd0070b 100644
--- a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java
+++ b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java
@@ -421,9 +421,9 @@ public class Camel extends AbstractHorse implements PlayerRideableJumping, Rider
}
@Override
- protected void actuallyHurt(DamageSource source, float amount) {
+ protected boolean damageEntity0(DamageSource source, float amount) { // Paper - fix CB method rename issue
this.standUpPanic();
- super.actuallyHurt(source, amount);
+ return super.damageEntity0(source, amount); // Paper - fix CB method rename issue
}
@Override
diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java b/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java
index 99af167b02c1291f9f5fd1a195a3eb65de87002b..874f7ea643d27eec47d51a10ad472af7e8ec402e 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java
@@ -44,7 +44,7 @@ public class StructureCheck {
private final Registry<Biome> biomes;
private final Registry<Structure> structureConfigs;
private final StructureTemplateManager structureTemplateManager;
- private final ResourceKey<Level> dimension;
+ private final ResourceKey<net.minecraft.world.level.dimension.LevelStem> dimension; // Paper - fix missing CB diff
private final ChunkGenerator chunkGenerator;
private final RandomState randomState;
private final LevelHeightAccessor heightAccessor;
@@ -54,7 +54,7 @@ public class StructureCheck {
private final Long2ObjectMap<Object2IntMap<Structure>> loadedChunks = new Long2ObjectOpenHashMap<>();
private final Map<Structure, Long2BooleanMap> featureChecks = new HashMap<>();
- public StructureCheck(ChunkScanAccess chunkIoWorker, RegistryAccess registryManager, StructureTemplateManager structureTemplateManager, ResourceKey<Level> worldKey, ChunkGenerator chunkGenerator, RandomState noiseConfig, LevelHeightAccessor world, BiomeSource biomeSource, long seed, DataFixer dataFixer) {
+ public StructureCheck(ChunkScanAccess chunkIoWorker, RegistryAccess registryManager, StructureTemplateManager structureTemplateManager, ResourceKey<net.minecraft.world.level.dimension.LevelStem> worldKey, ChunkGenerator chunkGenerator, RandomState noiseConfig, LevelHeightAccessor world, BiomeSource biomeSource, long seed, DataFixer dataFixer) { // Paper - fix missing CB diff
this.storageAccess = chunkIoWorker;
this.registryAccess = registryManager;
this.structureTemplateManager = structureTemplateManager;
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 8873bf84c71c48297a360df9c99e511fa0af5b40..f29395b6bf9eebd4830bbcda7d96085fb8e3d8b0 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2305,7 +2305,13 @@ public final class CraftServer implements Server {
Validate.notNull(key, "NamespacedKey cannot be null");
LootTables registry = this.getServer().getLootTables();
- return new CraftLootTable(key, registry.get(CraftNamespacedKey.toMinecraft(key)));
+ // Paper start - honor method contract
+ final ResourceLocation lootTableKey = CraftNamespacedKey.toMinecraft(key);
+ if (!registry.getIds().contains(lootTableKey)) {
+ return null;
+ }
+ return new CraftLootTable(key, registry.get(lootTableKey));
+ // Paper end
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java
index c93eec7a81ed83dc9190417dd51acb2780d3b60d..70d3949616c63038ad3e9bd1069db5ea2fb3f3b8 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java
@@ -15,7 +15,7 @@ public final class CraftDefaultPermissions {
DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".nbt.place", "Gives the user the ability to place restricted blocks with NBT in creative", org.bukkit.permissions.PermissionDefault.OP, parent);
DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".nbt.copy", "Gives the user the ability to copy NBT in creative", org.bukkit.permissions.PermissionDefault.TRUE, parent);
DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick", "Gives the user the ability to use the debug stick in creative", org.bukkit.permissions.PermissionDefault.OP, parent);
- DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick.always", "Gives the user the ability to use the debug stick in all game modes", org.bukkit.permissions.PermissionDefault.FALSE, parent);
+ DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick.always", "Gives the user the ability to use the debug stick in all game modes", org.bukkit.permissions.PermissionDefault.FALSE/* , parent */); // Paper - should not have this parent, as it's not a "vanilla" utility
// Spigot end
parent.recalculatePermissibles();
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,620 +0,0 @@
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 command
diff --git a/src/main/java/io/papermc/paper/command/CommandUtil.java b/src/main/java/io/papermc/paper/command/CommandUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..953c30500892e5f0c55b8597bc708ea85bf56d6e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/CommandUtil.java
@@ -0,0 +1,69 @@
+package io.papermc.paper.command;
+
+import com.google.common.base.Functions;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import net.minecraft.resources.ResourceLocation;
+import org.bukkit.command.CommandSender;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+public final class CommandUtil {
+ private CommandUtil() {
+ }
+
+ // Code from Mojang - copyright them
+ public static List<String> getListMatchingLast(
+ final CommandSender sender,
+ final String[] args,
+ final String... matches
+ ) {
+ return getListMatchingLast(sender, args, Arrays.asList(matches));
+ }
+
+ public static boolean matches(final String s, final String s1) {
+ return s1.regionMatches(true, 0, s, 0, s.length());
+ }
+
+ public static List<String> getListMatchingLast(
+ final CommandSender sender,
+ final String[] strings,
+ final 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(PaperCommand.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
+}
diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3a58bf4b654e336826dc04da9e2f80ff8b9a9a7
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java
@@ -0,0 +1,145 @@
+package io.papermc.paper.command;
+
+import io.papermc.paper.command.subcommands.EntityCommand;
+import io.papermc.paper.command.subcommands.HeapDumpCommand;
+import io.papermc.paper.command.subcommands.ReloadCommand;
+import io.papermc.paper.command.subcommands.VersionCommand;
+import it.unimi.dsi.fastutil.Pair;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import net.minecraft.Util;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.permissions.Permission;
+import org.bukkit.permissions.PermissionDefault;
+import org.bukkit.plugin.PluginManager;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+import static net.kyori.adventure.text.Component.text;
+import static net.kyori.adventure.text.format.NamedTextColor.RED;
+
+@DefaultQualifier(NonNull.class)
+public final class PaperCommand extends Command {
+ static final String BASE_PERM = "bukkit.command.paper.";
+ // subcommand label -> subcommand
+ private static final Map<String, PaperSubcommand> SUBCOMMANDS = Util.make(() -> {
+ final Map<Set<String>, PaperSubcommand> commands = new HashMap<>();
+
+ commands.put(Set.of("heap"), new HeapDumpCommand());
+ commands.put(Set.of("entity"), new EntityCommand());
+ commands.put(Set.of("reload"), new ReloadCommand());
+ commands.put(Set.of("version"), new VersionCommand());
+
+ return commands.entrySet().stream()
+ .flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ });
+ // alias -> subcommand label
+ private static final Map<String, String> ALIASES = Util.make(() -> {
+ final Map<String, Set<String>> aliases = new HashMap<>();
+
+ aliases.put("version", Set.of("ver"));
+
+ return aliases.entrySet().stream()
+ .flatMap(entry -> entry.getValue().stream().map(s -> Map.entry(s, entry.getKey())))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ });
+
+ public PaperCommand(final String name) {
+ super(name);
+ this.description = "Paper related commands";
+ this.usageMessage = "/paper [" + String.join(" | ", SUBCOMMANDS.keySet()) + "]";
+ final List<String> permissions = new ArrayList<>();
+ permissions.add("bukkit.command.paper");
+ permissions.addAll(SUBCOMMANDS.keySet().stream().map(s -> BASE_PERM + s).toList());
+ this.setPermission(String.join(";", permissions));
+ final PluginManager pluginManager = Bukkit.getServer().getPluginManager();
+ for (final String perm : permissions) {
+ pluginManager.addPermission(new Permission(perm, PermissionDefault.OP));
+ }
+ }
+
+ private static boolean testPermission(final CommandSender sender, final String permission) {
+ if (sender.hasPermission(BASE_PERM + permission) || sender.hasPermission("bukkit.command.paper")) {
+ return true;
+ }
+ sender.sendMessage(text("I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error.", RED));
+ return false;
+ }
+
+ @Override
+ public List<String> tabComplete(
+ final CommandSender sender,
+ final String alias,
+ final String[] args,
+ final @Nullable Location location
+ ) throws IllegalArgumentException {
+ if (args.length <= 1) {
+ return CommandUtil.getListMatchingLast(sender, args, SUBCOMMANDS.keySet());
+ }
+
+ final @Nullable Pair<String, PaperSubcommand> subCommand = resolveCommand(args[0]);
+ if (subCommand != null) {
+ return subCommand.second().tabComplete(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length));
+ }
+
+ return Collections.emptyList();
+ }
+
+ @Override
+ public boolean execute(
+ final CommandSender sender,
+ final String commandLabel,
+ final String[] args
+ ) {
+ if (!testPermission(sender)) {
+ return true;
+ }
+
+ if (args.length == 0) {
+ sender.sendMessage(text("Usage: " + this.usageMessage, RED));
+ return false;
+ }
+ final @Nullable Pair<String, PaperSubcommand> subCommand = resolveCommand(args[0]);
+
+ if (subCommand == null) {
+ sender.sendMessage(text("Usage: " + this.usageMessage, RED));
+ return false;
+ }
+
+ if (!testPermission(sender, subCommand.first())) {
+ return true;
+ }
+ final String[] choppedArgs = Arrays.copyOfRange(args, 1, args.length);
+ return subCommand.second().execute(sender, subCommand.first(), choppedArgs);
+ }
+
+ private static @Nullable Pair<String, PaperSubcommand> resolveCommand(String label) {
+ label = label.toLowerCase(Locale.ENGLISH);
+ @Nullable PaperSubcommand subCommand = SUBCOMMANDS.get(label);
+ if (subCommand == null) {
+ final @Nullable String command = ALIASES.get(label);
+ if (command != null) {
+ label = command;
+ subCommand = SUBCOMMANDS.get(command);
+ }
+ }
+
+ if (subCommand != null) {
+ return Pair.of(label, subCommand);
+ }
+
+ return null;
+ }
+}
diff --git a/src/main/java/io/papermc/paper/command/PaperCommands.java b/src/main/java/io/papermc/paper/command/PaperCommands.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a00f3d38da8107825ab1d405f337fd077b09f72
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/PaperCommands.java
@@ -0,0 +1,27 @@
+package io.papermc.paper.command;
+
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.command.Command;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+public final class PaperCommands {
+
+ private PaperCommands() {
+ }
+
+ private static final Map<String, Command> COMMANDS = new HashMap<>();
+ static {
+ COMMANDS.put("paper", new PaperCommand("paper"));
+ }
+
+ public static void registerCommands(final MinecraftServer server) {
+ COMMANDS.forEach((s, command) -> {
+ server.server.getCommandMap().register(s, "Paper", command);
+ });
+ }
+}
diff --git a/src/main/java/io/papermc/paper/command/PaperSubcommand.java b/src/main/java/io/papermc/paper/command/PaperSubcommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..6ff5d42a866d2752c73a766815aa190b2b0dc36f
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/PaperSubcommand.java
@@ -0,0 +1,16 @@
+package io.papermc.paper.command;
+
+import java.util.Collections;
+import java.util.List;
+import org.bukkit.command.CommandSender;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+public interface PaperSubcommand {
+ boolean execute(CommandSender sender, String subCommand, String[] args);
+
+ default List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff99336e0b8131ae161cfa5c4fc83c6905e3dbc8
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java
@@ -0,0 +1,158 @@
+package io.papermc.paper.command.subcommands;
+
+import com.google.common.collect.Maps;
+import io.papermc.paper.command.CommandUtil;
+import io.papermc.paper.command.PaperSubcommand;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.event.ClickEvent;
+import net.kyori.adventure.text.event.HoverEvent;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerChunkCache;
+import net.minecraft.server.level.ServerLevel;
+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.HeightMap;
+import org.bukkit.World;
+import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.entity.Player;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+import static net.kyori.adventure.text.Component.text;
+import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
+import static net.kyori.adventure.text.format.NamedTextColor.RED;
+
+@DefaultQualifier(NonNull.class)
+public final class EntityCommand implements PaperSubcommand {
+ @Override
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
+ this.listEntities(sender, args);
+ return true;
+ }
+
+ @Override
+ public List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
+ if (args.length == 1) {
+ return CommandUtil.getListMatchingLast(sender, args, "help", "list");
+ } else if (args.length == 2) {
+ return CommandUtil.getListMatchingLast(sender, args, BuiltInRegistries.ENTITY_TYPE.keySet().stream().map(ResourceLocation::toString).sorted().toArray(String[]::new));
+ }
+ return Collections.emptyList();
+ }
+
+ /*
+ * Ported from MinecraftForge - author: LexManos <LexManos@gmail.com> - License: LGPLv2.1
+ */
+ private void listEntities(final CommandSender sender, final String[] args) {
+ // help
+ if (args.length < 1 || !args[0].toLowerCase(Locale.ENGLISH).equals("list")) {
+ sender.sendMessage(text("Use /paper entity [list] help for more information on a specific command", RED));
+ return;
+ }
+
+ if ("list".equals(args[0].toLowerCase(Locale.ENGLISH))) {
+ String filter = "*";
+ if (args.length > 1) {
+ if (args[1].toLowerCase(Locale.ENGLISH).equals("help")) {
+ sender.sendMessage(text("Use /paper entity list [filter] [worldName] to get entity info that matches the optional filter.", RED));
+ return;
+ }
+ filter = args[1];
+ }
+ final String cleanfilter = filter.replace("?", ".?").replace("*", ".*?");
+ Set<ResourceLocation> names = BuiltInRegistries.ENTITY_TYPE.keySet().stream()
+ .filter(n -> n.toString().matches(cleanfilter))
+ .collect(Collectors.toSet());
+ if (names.isEmpty()) {
+ sender.sendMessage(text("Invalid filter, does not match any entities. Use /paper entity list for a proper list", RED));
+ sender.sendMessage(text("Usage: /paper entity list [filter] [worldName]", RED));
+ return;
+ }
+ String worldName;
+ if (args.length > 2) {
+ worldName = args[2];
+ } else if (sender instanceof Player) {
+ worldName = ((Player) sender).getWorld().getName();
+ } else {
+ sender.sendMessage(text("Please specify the name of a world", RED));
+ sender.sendMessage(text("To do so without a filter, specify '*' as the filter", RED));
+ sender.sendMessage(text("Usage: /paper entity list [filter] [worldName]", RED));
+ return;
+ }
+ Map<ResourceLocation, MutablePair<Integer, Map<ChunkPos, Integer>>> list = Maps.newHashMap();
+ @Nullable World bukkitWorld = Bukkit.getWorld(worldName);
+ if (bukkitWorld == null) {
+ sender.sendMessage(text("Could not load world for " + worldName + ". Please select a valid world.", RED));
+ sender.sendMessage(text("Usage: /paper entity list [filter] [worldName]", RED));
+ return;
+ }
+ ServerLevel world = ((CraftWorld) bukkitWorld).getHandle();
+ Map<ResourceLocation, Integer> nonEntityTicking = Maps.newHashMap();
+ ServerChunkCache chunkProviderServer = world.getChunkSource();
+ world.getAllEntities().forEach(e -> {
+ ResourceLocation key = EntityType.getKey(e.getType());
+
+ MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap()));
+ ChunkPos chunk = e.chunkPosition();
+ info.left++;
+ info.right.put(chunk, info.right.getOrDefault(chunk, 0) + 1);
+ if (!chunkProviderServer.isPositionTicking(e)) {
+ nonEntityTicking.merge(key, 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, 0);
+ if (info == null) {
+ sender.sendMessage(text("No entities found.", RED));
+ 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 -> {
+ final int x = (e.getKey().x << 4) + 8;
+ final int z = (e.getKey().z << 4) + 8;
+ final Component message = text(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z + (chunkProviderServer.isPositionTicking(e.getKey().toLong()) ? " (Ticking)" : " (Non-Ticking)"))
+ .hoverEvent(HoverEvent.showText(text("Click to teleport to chunk", GREEN)))
+ .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/minecraft:execute as @s in " + world.getWorld().getKey() + " run tp " + x + " " + (world.getWorld().getHighestBlockYAt(x, z, HeightMap.MOTION_BLOCKING) + 1) + " " + z));
+ sender.sendMessage(message);
+ });
+ } 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()))
+ .toList();
+
+ if (info.isEmpty()) {
+ sender.sendMessage(text("No entities found.", RED));
+ 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(), 0);
+ sender.sendMessage(" " + (e.getValue() - nonTicking) + " (" + nonTicking + ") " + ": " + e.getKey());
+ });
+ sender.sendMessage("* First number is ticking entities, second number is non-ticking entities");
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java b/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd2e4d792e972b8bf1e07b8961594a670ae949cf
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java
@@ -0,0 +1,38 @@
+package io.papermc.paper.command.subcommands;
+
+import io.papermc.paper.command.PaperSubcommand;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.CraftServer;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+import static net.kyori.adventure.text.Component.text;
+import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
+import static net.kyori.adventure.text.format.NamedTextColor.RED;
+import static net.kyori.adventure.text.format.NamedTextColor.YELLOW;
+
+@DefaultQualifier(NonNull.class)
+public final class HeapDumpCommand implements PaperSubcommand {
+ @Override
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
+ this.dumpHeap(sender);
+ return true;
+ }
+
+ private void dumpHeap(final 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, text("Writing JVM heap data...", YELLOW));
+
+ java.nio.file.Path file = CraftServer.dumpHeap(dir, name);
+ if (file != null) {
+ Command.broadcastCommandMessage(sender, text("Heap dump saved to " + file, GREEN));
+ } else {
+ Command.broadcastCommandMessage(sender, text("Failed to write heap dump, see server log for details", RED));
+ }
+ }
+}
diff --git a/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java b/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd68139ae635f2ad7ec8e7a21e0056a139c4c62e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java
@@ -0,0 +1,33 @@
+package io.papermc.paper.command.subcommands;
+
+import io.papermc.paper.command.PaperSubcommand;
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.CraftServer;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+import static net.kyori.adventure.text.Component.text;
+import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
+import static net.kyori.adventure.text.format.NamedTextColor.RED;
+
+@DefaultQualifier(NonNull.class)
+public final class ReloadCommand implements PaperSubcommand {
+ @Override
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
+ this.doReload(sender);
+ return true;
+ }
+
+ private void doReload(final CommandSender sender) {
+ Command.broadcastCommandMessage(sender, text("Please note that this command is not supported and may cause issues.", RED));
+ Command.broadcastCommandMessage(sender, text("If you encounter any issues please use the /stop command to restart your server.", RED));
+
+ MinecraftServer server = ((CraftServer) sender.getServer()).getServer();
+ server.paperConfigurations.reloadConfigs(server);
+ server.server.reloadCount++;
+
+ Command.broadcastCommandMessage(sender, text("Paper config reload complete.", GREEN));
+ }
+}
diff --git a/src/main/java/io/papermc/paper/command/subcommands/VersionCommand.java b/src/main/java/io/papermc/paper/command/subcommands/VersionCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae60bd96b5284d54676d8e7e4dd5d170b526ec1e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/subcommands/VersionCommand.java
@@ -0,0 +1,21 @@
+package io.papermc.paper.command.subcommands;
+
+import io.papermc.paper.command.PaperSubcommand;
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+public final class VersionCommand implements PaperSubcommand {
+ @Override
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
+ final @Nullable Command ver = MinecraftServer.getServer().server.getCommandMap().getCommand("version");
+ if (ver != null) {
+ ver.execute(sender, "paper", new String[0]);
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 1fe07773cf9664164b29164caba22800e5a6bdae..cb6f192c11cda6230ec365e6cefb44a37416236d 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -186,6 +186,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
// Paper start
paperConfigurations.initializeGlobalConfiguration();
paperConfigurations.initializeWorldDefaultsConfiguration();
+ io.papermc.paper.command.PaperCommands.registerCommands(this);
// Paper end
this.setPvpAllowed(dedicatedserverproperties.pvp);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 877a104e3899debd387544b740896ffbe86bb581..26ca07b5e302cc4cc02e06f5d07f6d9eb541275e 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -909,6 +909,7 @@ public final class CraftServer implements Server {
this.commandMap.clearCommands();
this.reloadData();
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
+ io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper
this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*");
this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions");
@@ -2438,6 +2439,34 @@ public final class CraftServer implements Server {
// 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;
+ }
+ }
private Iterable<? extends net.kyori.adventure.audience.Audience> adventure$audiences;
@Override
public Iterable<? extends net.kyori.adventure.audience.Audience> audiences() {

View file

@ -1,731 +0,0 @@
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..6aaed8e8bf8c721fc834da5c76ac72a4c3e92458
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
@@ -0,0 +1,678 @@
+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;
+ }
+
+ }
+
+ public static class PaperMetrics {
+ public 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() ? "online" : "offline"));
+ final String paperVersion;
+ final String implVersion = org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion();
+ if (implVersion != null) {
+ final String buildOrHash = implVersion.substring(implVersion.lastIndexOf('-') + 1);
+ paperVersion = "git-Paper-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash);
+ } else {
+ paperVersion = "unknown";
+ }
+ metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> paperVersion));
+
+ metrics.addCustomChart(new Metrics.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/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index cb6f192c11cda6230ec365e6cefb44a37416236d..11006df8797334da69801cdb9aa34b0f941cf90d 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -187,6 +187,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
paperConfigurations.initializeGlobalConfiguration();
paperConfigurations.initializeWorldDefaultsConfiguration();
io.papermc.paper.command.PaperCommands.registerCommands(this);
+ com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics();
// Paper end
this.setPvpAllowed(dedicatedserverproperties.pvp);
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
index 83eabc34d952bbb13ec4b4bdcf34f647189c0b46..0a0aa6de31a94a701074cc5f43c94be7515a185c 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 ( SpigotConfig.metrics == null )
{
try
@@ -94,6 +95,7 @@ public class SpigotConfig
Bukkit.getServer().getLogger().log( Level.SEVERE, "Could not start metrics service", ex );
}
}
+ */ // Paper end
}
public static void readConfig(Class<?> clazz, Object instance) // Paper - package-private -> public

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -1,105 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sun, 3 Mar 2019 20:53:18 -0800
Subject: [PATCH] Add TickThread
Placeholder patch, to be used by chunksystem rewrite
diff --git a/src/main/java/io/papermc/paper/util/TickThread.java b/src/main/java/io/papermc/paper/util/TickThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..d59885ee9c8b29d5bac34dce0597e345e5358c77
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/TickThread.java
@@ -0,0 +1,79 @@
+package io.papermc.paper.util;
+
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.entity.Entity;
+import org.bukkit.Bukkit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public final class TickThread extends Thread {
+
+ public static final boolean STRICT_THREAD_CHECKS = Boolean.getBoolean("paper.strict-thread-checks");
+
+ static {
+ if (STRICT_THREAD_CHECKS) {
+ MinecraftServer.LOGGER.warn("Strict thread checks enabled - performance may suffer");
+ }
+ }
+
+ public static void softEnsureTickThread(final String reason) {
+ if (!STRICT_THREAD_CHECKS) {
+ return;
+ }
+ ensureTickThread(reason);
+ }
+
+ public static void ensureTickThread(final String reason) {
+ if (!isTickThread()) {
+ MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
+ throw new IllegalStateException(reason);
+ }
+ }
+
+ public static void ensureTickThread(final ServerLevel world, final int chunkX, final int chunkZ, final String reason) {
+ if (!isTickThreadFor(world, chunkX, chunkZ)) {
+ MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
+ throw new IllegalStateException(reason);
+ }
+ }
+
+ public static void ensureTickThread(final Entity entity, final String reason) {
+ if (!isTickThreadFor(entity)) {
+ MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
+ throw new IllegalStateException(reason);
+ }
+ }
+
+ public final int id; /* We don't override getId as the spec requires that it be unique (with respect to all other threads) */
+
+ private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
+
+ public TickThread(final String name) {
+ this(null, name);
+ }
+
+ public TickThread(final Runnable run, final String name) {
+ this(run, name, ID_GENERATOR.incrementAndGet());
+ }
+
+ private TickThread(final Runnable run, final String name, final int id) {
+ super(run, name);
+ this.id = id;
+ }
+
+ public static TickThread getCurrentTickThread() {
+ return (TickThread)Thread.currentThread();
+ }
+
+ public static boolean isTickThread() {
+ return Bukkit.isPrimaryThread();
+ }
+
+ public static boolean isTickThreadFor(final ServerLevel world, final int chunkX, final int chunkZ) {
+ return Bukkit.isPrimaryThread();
+ }
+
+ public static boolean isTickThreadFor(final Entity entity) {
+ return Bukkit.isPrimaryThread();
+ }
+}
diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java
index bbf0d9d9c44fe8d7add2f978994ec129420814c7..78669fa035b7537ff7e533cf32aaf2995625424f 100644
--- a/src/main/java/org/spigotmc/AsyncCatcher.java
+++ b/src/main/java/org/spigotmc/AsyncCatcher.java
@@ -9,7 +9,7 @@ public class AsyncCatcher
public static void catchOp(String reason)
{
- if ( AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread )
+ if ( (AsyncCatcher.enabled || io.papermc.paper.util.TickThread.STRICT_THREAD_CHECKS) && Thread.currentThread() != MinecraftServer.getServer().serverThread ) // Paper
{
throw new IllegalStateException( "Asynchronous " + reason + "!" );
}

File diff suppressed because it is too large Load diff

View file

@ -1,65 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Tue, 18 May 2021 14:39:44 -0700
Subject: [PATCH] Add command line option to load extra plugin jars not in the
plugins folder
ex: java -jar paperclip.jar nogui -add-plugin=/path/to/plugin.jar -add-plugin=/path/to/another/plugin_jar.jar
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index d6f858ee1245b313024c36ac2a0edd09b9307bca..d82e0dd38ef2b32d82e906d5bc71b46052eb0625 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -420,6 +420,35 @@ public final class CraftServer implements Server {
io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler.INSTANCE.enter(io.papermc.paper.plugin.entrypoint.Entrypoint.PLUGIN); // Paper - replace implementation
}
+ // Paper start
+ @Override
+ public File getPluginsFolder() {
+ return (File) this.console.options.valueOf("plugins");
+ }
+
+ private List<File> extraPluginJars() {
+ @SuppressWarnings("unchecked")
+ final List<File> jars = (List<File>) this.console.options.valuesOf("add-plugin");
+ final List<File> list = new ArrayList<>();
+ for (final File file : jars) {
+ if (!file.exists()) {
+ net.minecraft.server.MinecraftServer.LOGGER.warn("File '{}' specified through 'add-plugin' argument does not exist, cannot load a plugin from it!", file.getAbsolutePath());
+ continue;
+ }
+ if (!file.isFile()) {
+ net.minecraft.server.MinecraftServer.LOGGER.warn("File '{}' specified through 'add-plugin' argument is not a file, cannot load a plugin from it!", file.getAbsolutePath());
+ continue;
+ }
+ if (!file.getName().endsWith(".jar")) {
+ net.minecraft.server.MinecraftServer.LOGGER.warn("File '{}' specified through 'add-plugin' argument is not a jar file, cannot load a plugin from it!", file.getAbsolutePath());
+ continue;
+ }
+ list.add(file);
+ }
+ return list;
+ }
+ // Paper end
+
public void enablePlugins(PluginLoadOrder type) {
if (type == PluginLoadOrder.STARTUP) {
this.helpMap.clear();
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index 481c1f853bbe81da123cfb3f79ed4509cf127db8..985aae207e23584519b4c096f2aaaf0e80b6c163 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -149,6 +149,12 @@ public class Main {
.ofType(File.class)
.defaultsTo(new File("paper.yml"))
.describedAs("Yml file");
+
+ acceptsAll(asList("add-plugin", "add-extra-plugin-jar"), "Specify paths to extra plugin jars to be loaded in addition to those in the plugins folder. This argument can be specified multiple times, once for each extra plugin jar path.")
+ .withRequiredArg()
+ .ofType(File.class)
+ .defaultsTo(new File[] {})
+ .describedAs("Jar file");
// Paper end
}
};

View file

@ -1,92 +0,0 @@
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/net/minecraft/world/level/block/BambooStalkBlock.java b/src/main/java/net/minecraft/world/level/block/BambooStalkBlock.java
index 0d05ad9c0b5043e58d639041cfe3fb7a27f373a3..a5d391af2c6b733d653188f4aeeec2afffd96adf 100644
--- a/src/main/java/net/minecraft/world/level/block/BambooStalkBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/BambooStalkBlock.java
@@ -130,7 +130,7 @@ public class BambooStalkBlock extends Block implements BonemealableBlock {
if (random.nextFloat() < (world.spigotConfig.bambooModifier / (100.0f * 3)) && world.isEmptyBlock(pos.above()) && world.getRawBrightness(pos.above(), 0) >= 9) { // Spigot - SPIGOT-7159: Better modifier resolution
int i = this.getHeightBelowUpToMax(world, pos) + 1;
- if (i < 16) {
+ if (i < world.paperConfig().maxGrowthHeight.bamboo.max) { // Paper
this.growBamboo(state, world, pos, random, i);
}
}
@@ -161,7 +161,7 @@ public class BambooStalkBlock 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(BambooStalkBlock.STAGE) != 1;
+ return i + j + 1 < ((Level) world).paperConfig().maxGrowthHeight.bamboo.max && (Integer) world.getBlockState(pos.above(i)).getValue(BambooStalkBlock.STAGE) != 1; // Paper
}
@Override
@@ -180,7 +180,7 @@ public class BambooStalkBlock extends Block implements BonemealableBlock {
BlockPos blockposition1 = pos.above(i);
BlockState iblockdata1 = world.getBlockState(blockposition1);
- if (k >= 16 || !iblockdata1.is(Blocks.BAMBOO) || (Integer) iblockdata1.getValue(BambooStalkBlock.STAGE) == 1 || !world.isEmptyBlock(blockposition1.above())) { // CraftBukkit - If the BlockSpreadEvent was cancelled, we have no bamboo here
+ if (k >= world.paperConfig().maxGrowthHeight.bamboo.max || !iblockdata1.is(Blocks.BAMBOO) || (Integer) iblockdata1.getValue(BambooStalkBlock.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;
}
@@ -221,7 +221,7 @@ public class BambooStalkBlock extends Block implements BonemealableBlock {
}
int j = (Integer) state.getValue(BambooStalkBlock.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().maxGrowthHeight.bamboo.min || random.nextFloat() >= 0.25F) && height != (world.paperConfig().maxGrowthHeight.bamboo.max - 1) ? 0 : 1; // Paper
// CraftBukkit start
if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, pos.above(), (BlockState) ((BlockState) ((BlockState) this.defaultBlockState().setValue(BambooStalkBlock.AGE, j)).setValue(BambooStalkBlock.LEAVES, blockpropertybamboosize)).setValue(BambooStalkBlock.STAGE, k), 3)) {
@@ -236,7 +236,7 @@ public class BambooStalkBlock 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().maxGrowthHeight.bamboo.max && world.getBlockState(pos.above(i + 1)).is(Blocks.BAMBOO); ++i) { // Paper
;
}
@@ -246,7 +246,7 @@ public class BambooStalkBlock 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().maxGrowthHeight.bamboo.max && 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 ea052e4a5e5cb23609129fd08869bcd38f675cd0..7f137f43f725cd2866e10f0ade40d4906b64fac1 100644
--- a/src/main/java/net/minecraft/world/level/block/CactusBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CactusBlock.java
@@ -55,7 +55,7 @@ public class CactusBlock extends Block {
;
}
- if (i < 3) {
+ if (i < world.paperConfig().maxGrowthHeight.cactus) { // Paper - Configurable growth height
int j = (Integer) state.getValue(CactusBlock.AGE);
int modifier = world.spigotConfig.cactusModifier; // Spigot - SPIGOT-7159: Better modifier resolution
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 2aa81f93a2e1e94d0788b4d7b67f94494101c397..6b400a4759c8c8612a3b5c96ca0d87ef9dc71435 100644
--- a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
@@ -52,7 +52,7 @@ public class SugarCaneBlock extends Block {
;
}
- if (i < 3) {
+ if (i < world.paperConfig().maxGrowthHeight.reeds) { // Paper - Configurable growth height
int j = (Integer) state.getValue(SugarCaneBlock.AGE);
int modifier = world.spigotConfig.caneModifier; // Spigot - SPIGOT-7159: Better modifier resolution

View file

@ -1,30 +0,0 @@
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/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
index 251487682550af7492068bd461bf0c61760de0fa..8ea60d388fff4a6368652ff96f648e5880053a2b 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
@@ -77,6 +77,7 @@ 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 babyModifier = new net.minecraft.world.entity.ai.attributes.AttributeModifier(SPEED_MODIFIER_BABY.getId(), SPEED_MODIFIER_BABY.getName(), this.level.paperConfig().entities.behavior.babyZombieMovementModifier, SPEED_MODIFIER_BABY.getOperation()); // Paper - 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);
@@ -185,9 +186,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
}
}

View file

@ -1,30 +0,0 @@
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/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
index f0cb2fa768adf1ffe68a00457d39a7749899ac6b..9d0df8d64a2cfd2458295a214829f277798030f0 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
@@ -86,6 +86,10 @@ public class FishingHook extends Projectile {
this.noCulling = true;
this.luck = Math.max(0, luckOfTheSeaLevel);
this.lureSpeed = Math.max(0, lureLevel);
+ // Paper start
+ minWaitTime = world.paperConfig().fishingTimeRange.minimum;
+ maxWaitTime = world.paperConfig().fishingTimeRange.maximum;
+ // Paper end
}
public FishingHook(EntityType<? extends FishingHook> type, Level world) {
@@ -401,7 +405,7 @@ public class FishingHook extends Projectile {
} else {
// CraftBukkit start - logic to modify fishing wait time
this.timeUntilLured = Mth.nextInt(this.random, this.minWaitTime, this.maxWaitTime);
- this.timeUntilLured -= (this.applyLure) ? this.lureSpeed * 20 * 5 : 0;
+ this.timeUntilLured -= (this.applyLure) ? (this.lureSpeed * 20 * 5 >= this.maxWaitTime ? this.timeUntilLured - 1 : this.lureSpeed * 20 * 5) : 0; // Paper - Fix Lure infinite loop
// CraftBukkit end
}
}

View file

@ -1,49 +0,0 @@
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/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index 10949455cc92ed6cb537fd7f148714c7ade4e360..c4b28340d62a89d6f896357c93fd933fe6cd934b 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -110,6 +110,7 @@ public abstract class Mob extends LivingEntity {
private final BodyRotationControl bodyRotationControl;
protected PathNavigation navigation;
public GoalSelector goalSelector;
+ @Nullable public net.minecraft.world.entity.ai.goal.FloatGoal goalFloat; // Paper
public GoalSelector targetSelector;
@Nullable
private LivingEntity target;
@@ -836,7 +837,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.canUse()) goalFloat.tick();
+ this.getJumpControl().tick();
+ }
+ if (this.isSensitiveToWater() && isInWaterRainOrBubble()) {
+ 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/goal/FloatGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/FloatGoal.java
index 01950951ea06e43bedeeede489a112e577617829..7093c62be53fe99ed9880fc8ddaa07440fe4f715 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
@@ -9,6 +9,7 @@ public class FloatGoal extends Goal {
public FloatGoal(Mob mob) {
this.mob = mob;
+ if (mob.getCommandSenderWorld().paperConfig().entities.behavior.spawnerNerfedMobsShouldJump) mob.goalFloat = this; // Paper
this.setFlags(EnumSet.of(Goal.Flag.JUMP));
mob.getNavigation().setCanFloat(true);
}

View file

@ -1,27 +0,0 @@
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/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index c4b28340d62a89d6f896357c93fd933fe6cd934b..99218eac34374a4d13451cfec15006c3bf0d755f 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -812,14 +812,14 @@ public abstract class Mob extends LivingEntity {
if (entityhuman != null) {
double d0 = entityhuman.distanceToSqr((Entity) this);
- int i = this.getType().getCategory().getDespawnDistance();
+ int i = this.level.paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory()).hard(); // Paper - custom despawn distances
int j = i * i;
if (d0 > (double) j && this.removeWhenFarAway(d0)) {
this.discard();
}
- int k = this.getType().getCategory().getNoDespawnDistance();
+ int k = this.level.paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory()).soft(); // Paper - custom despawn distances
int l = k * k;
if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d0 > (double) l && this.removeWhenFarAway(d0)) {

View file

@ -1,18 +0,0 @@
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/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 5ed57b1156b1f358fb7d1d876becfc06f47ffe3b..4b2aadae3a7595a5aee2bc71216adc34fa0f2cf9 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -256,6 +256,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().spawn.keepSpawnLoaded; // Paper
this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
}

View file

@ -1,63 +0,0 @@
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
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
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 c186ea200e196ff97a9bbe78d4e550ccba2d40ac..c125564cfca5c4a616e11b334a9ec7929ebea496 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -139,6 +139,17 @@ public class FallingBlockEntity extends Entity {
}
this.move(MoverType.SELF, this.getDeltaMovement());
+
+ // Paper start - Configurable EntityFallingBlock height nerf
+ if (this.level.paperConfig().fixes.fallingBlockHeightNerf.test(v -> this.getY() > v)) {
+ if (this.dropItem && this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
+ this.spawnAtLocation(block);
+ }
+
+ this.discard();
+ return;
+ }
+ // Paper end
if (!this.level.isClientSide) {
BlockPos 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 dd3eee50509f5388e78e0908e83925c43ab20628..43ec4bc45a3e553fbbf47aaf613f6e0aad2319cf 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -65,6 +65,12 @@ public class PrimedTnt extends Entity {
}
this.move(MoverType.SELF, this.getDeltaMovement());
+ // Paper start - Configurable TNT entity height nerf
+ if (this.level.paperConfig().fixes.tntEntityHeightNerf.test(v -> this.getY() > v)) {
+ this.discard();
+ 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 db40c7a11dba6450ac9c1107b226aff5858867c9..3e2407e00e56b8648bc6b084ba016ddccf40a53b 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartTNT.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartTNT.java
@@ -52,6 +52,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().fixes.tntEntityHeightNerf.test(v -> this.getY() > v)) {
+ this.discard();
+ 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) {

View file

@ -1,104 +0,0 @@
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/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index e9f4ffec4b659f3300daa0138f6e955a8d97786d..e2e66fd4bd34e0ceaab350214a50ddbb1dc76184 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1433,7 +1433,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@DontObfuscate
public String getServerModName() {
- return "Spigot"; // Spigot - Spigot > // CraftBukkit - cb > vanilla!
+ return "Paper"; // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla!
}
public SystemReport fillSystemReport(SystemReport details) {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index d82e0dd38ef2b32d82e906d5bc71b46052eb0625..e5aa25abee4d4c5447920e64ad45acf9763dedf0 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -259,7 +259,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 985aae207e23584519b4c096f2aaaf0e80b6c163..49f6d20706e8fb94c41834f5addcd015d18acd7e 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -223,12 +223,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 f1194eb6fdfba60959e00080d0562f2820d13b27..11d7ede26b46d0bf9cced65e8c3bcc41c8b66dbf 100644
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
@@ -19,7 +19,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
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 final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
{
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 final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
}
//
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
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper // Paper - rewrite chunk system
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
log.log( Level.SEVERE, "------------------------------" );

View file

@ -1,157 +0,0 @@
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..351159bbdb0c8045f4983f54dee34430dbcc423e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
@@ -0,0 +1,129 @@
+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.event.ClickEvent;
+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 final String DOWNLOAD_PAGE = "https://papermc.io/downloads";
+ 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)
+ .append(Component.newline())
+ .append(Component.text("Download the new version at: ")
+ .append(Component.text(DOWNLOAD_PAGE, NamedTextColor.GOLD)
+ .hoverEvent(Component.text("Click to open", NamedTextColor.WHITE))
+ .clickEvent(ClickEvent.openUrl(DOWNLOAD_PAGE))));
+ }
+ }
+
+ private static int fetchDistanceFromSiteApi(int jenkinsBuild, @Nullable String siteApiVersion) {
+ if (siteApiVersion == null) { return -1; }
+ try {
+ try (BufferedReader reader = Resources.asCharSource(
+ new URL("https://api.papermc.io/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 d22210c6aaeed8ac6df296f47a699f2e5b67abf4..289276ae40409868c6293c5ab3bafe54c2ccf15c 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -455,6 +455,11 @@ public final class CraftMagicNumbers implements UnsafeValues {
public String getTimingsServerName() {
return io.papermc.paper.configuration.GlobalConfiguration.get().timings.serverName;
}
+
+ @Override
+ public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() {
+ return new com.destroystokyo.paper.PaperVersionFetcher();
+ }
// Paper end
/**

View file

@ -1,214 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kyle Wood <kyle@denwav.dev>
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 351159bbdb0c8045f4983f54dee34430dbcc423e..bf42969859545a8a520923ef1836ffa4a5cc24a0 100644
--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
@@ -7,6 +7,8 @@ import com.google.gson.*;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.TextDecoration;
+import net.kyori.adventure.text.TextComponent;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -30,7 +32,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() {
@@ -126,4 +131,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 8318af4db5fa7242b5cb2ae50fd08174017d6f7d..18f7d73fd8a780753e2249a9fec6bb335ebfdeed 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -189,6 +189,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
paperConfigurations.initializeWorldDefaultsConfiguration();
io.papermc.paper.command.PaperCommands.registerCommands(this);
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics();
+ com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now
// Paper end
this.setPvpAllowed(dedicatedserverproperties.pvp);

View file

@ -1,163 +0,0 @@
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/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java
index 5c3b11f738c1ea19981cc878aa6c2323497391a0..6fd874a83a248e6a7d427d18d11fc608544662c5 100644
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
@@ -29,6 +29,11 @@ public final class EntitySelector {
public static final Predicate<Entity> CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith);
private EntitySelector() {}
+ // Paper start
+ public static final Predicate<Entity> PLAYER_AFFECTS_SPAWNING = (entity) -> {
+ return !entity.isSpectator() && entity.isAlive() && entity instanceof Player player && player.affectsSpawning;
+ };
+ // Paper end
public static Predicate<Entity> withinDistance(double x, double y, double z, double max) {
double d4 = max * max;
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index 99218eac34374a4d13451cfec15006c3bf0d755f..bb7c459c126be789bb12d08a569fe344e08914b8 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -808,7 +808,7 @@ public abstract class Mob extends LivingEntity {
if (this.level.getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
this.discard();
} else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) {
- Player entityhuman = this.level.getNearestPlayer(this, -1.0D);
+ Player entityhuman = this.level.findNearbyPlayer(this, -1.0D, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper
if (entityhuman != null) {
double d0 = entityhuman.distanceToSqr((Entity) this);
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonTrapGoal.java b/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonTrapGoal.java
index e368478dba01a9b11adf23ed64bed61c73a78a28..17fda4857f74d2994525262472700e7788dec383 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonTrapGoal.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonTrapGoal.java
@@ -25,7 +25,7 @@ public class SkeletonTrapGoal extends Goal {
@Override
public boolean canUse() {
- return this.horse.level.hasNearbyAlivePlayer(this.horse.getX(), this.horse.getY(), this.horse.getZ(), 10.0D);
+ return this.horse.level.hasNearbyAlivePlayerThatAffectsSpawning(this.horse.getX(), this.horse.getY(), this.horse.getZ(), 10.0D); // Paper - Affects Spawning API
}
@Override
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 87f66fd33e404367d924137b2d8aac3b06937f43..2dcda3b03796655da443e1b3dd68c6f6bca20d21 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
@@ -127,7 +127,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/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
index 8ea60d388fff4a6368652ff96f648e5880053a2b..8ecbb64f9db9346757c5597404489496a0945508 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
@@ -325,7 +325,7 @@ public class Zombie extends Monster {
if (NaturalSpawner.isSpawnPositionOk(entitypositiontypes_surface, this.level, blockposition, entitytypes) && SpawnPlacements.checkSpawnRules(entitytypes, worldserver, MobSpawnType.REINFORCEMENT, blockposition, this.level.random)) {
entityzombie.setPos((double) i1, (double) j1, (double) k1);
- if (!this.level.hasNearbyAlivePlayer((double) i1, (double) j1, (double) k1, 7.0D) && this.level.isUnobstructed(entityzombie) && this.level.noCollision((Entity) entityzombie) && !this.level.containsAnyLiquid(entityzombie.getBoundingBox())) {
+ if (!this.level.hasNearbyAlivePlayerThatAffectsSpawning((double) i1, (double) j1, (double) k1, 7.0D) && this.level.isUnobstructed(entityzombie) && this.level.noCollision((Entity) entityzombie) && !this.level.containsAnyLiquid(entityzombie.getBoundingBox())) { // Paper - Affects Spawning API
entityzombie.setTarget(entityliving, EntityTargetEvent.TargetReason.REINFORCEMENT_TARGET, true); // CraftBukkit
entityzombie.finalizeSpawn(worldserver, this.level.getCurrentDifficultyAt(entityzombie.blockPosition()), MobSpawnType.REINFORCEMENT, (SpawnGroupData) null, (CompoundTag) null);
worldserver.addFreshEntityWithPassengers(entityzombie, CreatureSpawnEvent.SpawnReason.REINFORCEMENTS); // CraftBukkit
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 47b5ef810348f8c702acb09b280b41b6b7227b6f..60fb74537fdc96005cbf6aa1670e773c0faa2f26 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -179,6 +179,9 @@ public abstract class Player extends LivingEntity {
private Optional<GlobalPos> lastDeathLocation;
@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 f035206f2f59cb293d503c638ff06333a797a7a9..3e83bff81a0656d5e1d079ad9e63c7d27561c8e3 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -54,7 +54,7 @@ public abstract class BaseSpawner {
}
public boolean isNearPlayer(Level world, BlockPos pos) {
- return world.hasNearbyAlivePlayer((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange);
+ return world.hasNearbyAlivePlayerThatAffectsSpawning((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange); // Paper - Affects Spawning API
}
public void clientTick(Level world, BlockPos pos) {
diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java
index be6e3e21ad62da01e5e2dd78e300cbc8efdbeb42..ea98625fe7c00743b8df74a24e6d4b75df4189a5 100644
--- a/src/main/java/net/minecraft/world/level/EntityGetter.java
+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java
@@ -82,6 +82,11 @@ public interface EntityGetter {
}
}
+ // Paper start
+ default @Nullable Player findNearbyPlayer(Entity entity, double maxDistance, @Nullable Predicate<Entity> predicate) {
+ return this.getNearestPlayer(entity.getX(), entity.getY(), entity.getZ(), maxDistance, predicate);
+ }
+ // Paper end
@Nullable
default Player getNearestPlayer(double x, double y, double z, double maxDistance, @Nullable Predicate<Entity> targetPredicate) {
double d = -1.0D;
@@ -111,6 +116,20 @@ public interface EntityGetter {
return this.getNearestPlayer(x, y, z, maxDistance, predicate);
}
+ // Paper start
+ default boolean hasNearbyAlivePlayerThatAffectsSpawning(double x, double y, double z, double range) {
+ for (Player player : this.players()) {
+ if (EntitySelector.PLAYER_AFFECTS_SPAWNING.test(player)) { // combines NO_SPECTATORS and LIVING_ENTITY_STILL_ALIVE with an "affects spawning" check
+ double distanceSqr = player.distanceToSqr(x, y, z);
+ if (range < 0.0D || distanceSqr < range * range) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ // Paper end
+
default boolean hasNearbyAlivePlayer(double x, double y, double z, double range) {
for(Player player : this.players()) {
if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 92e5b781049122e3de3784ec4197557f2730b3b3..eecfbd4e835bfc3d98194365e360a827fb02bb38 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2113,8 +2113,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override
public String getLocale() {
return this.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 (this.getHandle().connection == null) return;

View file

@ -1,213 +0,0 @@
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 e2e66fd4bd34e0ceaab350214a50ddbb1dc76184..ac81428f19e2d445f315000d34173c2d650a9aeb 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -281,7 +281,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;
@@ -290,7 +290,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Spigot start
public static final int TPS = 20;
public static final int TICK_TIME = 1000000000 / MinecraftServer.TPS;
- private static final int SAMPLE_INTERVAL = 100;
+ private static final int SAMPLE_INTERVAL = 20; // Paper
public final double[] recentTps = new double[ 3 ];
// Spigot end
public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations;
@@ -953,6 +953,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
public static volatile RuntimeException chunkSystemCrash; // Paper - rewrite chunk system
@@ -971,7 +1022,8 @@ 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) {
// Paper start - rewrite chunk system
// guarantee that nothing can stop the server from halting if it can at least still tick
@@ -979,7 +1031,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
throw this.chunkSystemCrash;
}
// Paper end - rewrite chunk system
- 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;
@@ -991,12 +1043,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
++MinecraftServer.currentTickLong; // Paper
- if ( tickCount++ % MinecraftServer.SAMPLE_INTERVAL == 0 )
+ if ( ++MinecraftServer.currentTick % MinecraftServer.SAMPLE_INTERVAL == 0 )
{
- double currentTps = 1E3 / ( curTime - tickSection ) * MinecraftServer.SAMPLE_INTERVAL;
- this.recentTps[0] = MinecraftServer.calcTps( this.recentTps[0], 0.92, currentTps ); // 1/exp(5sec/1min)
- this.recentTps[1] = MinecraftServer.calcTps( this.recentTps[1], 0.9835, currentTps ); // 1/exp(5sec/5min)
- this.recentTps[2] = MinecraftServer.calcTps( this.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
+ this.recentTps[0] = tps1.getAverage();
+ this.recentTps[1] = tps5.getAverage();
+ this.recentTps[2] = tps15.getAverage();
+ // Paper end
tickSection = curTime;
}
// Spigot end
@@ -1006,7 +1064,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount);
}
- 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;
this.startMetricsRecordingTick();
this.profiler.push("tick");
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index e5aa25abee4d4c5447920e64ad45acf9763dedf0..babde3ac7af9b5659bcc7e0298d1d77e7b2d60e2 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2418,6 +2418,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 4ab81a99f906e3f28e026d0e50b5b943c1bdcfb5..9bede6a26c08ede063c7a38f1149c811df14b258 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( this.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] = TicksPerSecondCommand.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
}
}

View file

@ -1,25 +0,0 @@
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 eecfbd4e835bfc3d98194365e360a827fb02bb38..27f4387a3ac750114c99e41e855c8fb8081a507d 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1782,12 +1782,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override
public void setFlying(boolean value) {
+ boolean needsUpdate = getHandle().getAbilities().flying != value; // Paper - Only refresh abilities if needed
if (!this.getAllowFlight() && value) {
throw new IllegalArgumentException("Cannot make player fly if getAllowFlight() is false");
}
this.getHandle().getAbilities().flying = value;
- this.getHandle().onUpdateAbilities();
+ if (needsUpdate) this.getHandle().onUpdateAbilities(); // Paper - Only refresh abilities if needed
}
@Override

View file

@ -1,158 +0,0 @@
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/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 3fce997cc390136a16c941f0461b20d2bc046948..b1771e25c13b555d3316aca35f8a97ed4ce8f275 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -2215,6 +2215,15 @@ public class ServerLevel extends Level implements WorldGenLevel {
entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
entity.valid = true; // CraftBukkit
+ // Paper start - Set origin location when the entity is being added to the world
+ if (entity.getOriginVector() == null) {
+ entity.setOrigin(entity.getBukkitEntity().getLocation());
+ }
+ // Default to current world if unknown, gross assumption but entities rarely change world
+ if (entity.getOriginWorld() == null) {
+ entity.setOrigin(entity.getOriginVector().toLocation(getWorld()));
+ }
+ // Paper end
}
public void onTrackingEnd(Entity entity) {
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 0cd735648314872e98e310627247b9ad425ab64d..5cf04b209ae3fa6c52ad45e726343418d0de311f 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -304,7 +304,27 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
public long activatedTick = Integer.MIN_VALUE;
public void inactiveTick() { }
// Spigot end
+ // Paper start
+ @javax.annotation.Nullable
+ private org.bukkit.util.Vector origin;
+ @javax.annotation.Nullable
+ private UUID originWorld;
+
+ public void setOrigin(@javax.annotation.Nonnull Location location) {
+ this.origin = location.toVector();
+ this.originWorld = location.getWorld().getUID();
+ }
+ @javax.annotation.Nullable
+ public org.bukkit.util.Vector getOriginVector() {
+ return this.origin != null ? this.origin.clone() : null;
+ }
+
+ @javax.annotation.Nullable
+ public UUID getOriginWorld() {
+ return this.originWorld;
+ }
+ // Paper end
public float getBukkitYaw() {
return this.yRot;
}
@@ -1928,6 +1948,15 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
this.bukkitEntity.storeBukkitValues(nbt);
}
// CraftBukkit end
+ // Paper start - Save the entity's origin location
+ if (this.origin != null) {
+ UUID originWorld = this.originWorld != null ? this.originWorld : this.level != null ? this.level.getWorld().getUID() : null;
+ if (originWorld != null) {
+ nbt.putUUID("Paper.OriginWorld", originWorld);
+ }
+ nbt.put("Paper.Origin", this.newDoubleList(origin.getX(), origin.getY(), origin.getZ()));
+ }
+ // Paper end
return nbt;
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT");
@@ -2054,6 +2083,20 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
// CraftBukkit end
+ // Paper start - Restore the entity's origin location
+ ListTag originTag = nbt.getList("Paper.Origin", 6);
+ if (!originTag.isEmpty()) {
+ UUID originWorld = null;
+ if (nbt.contains("Paper.OriginWorld")) {
+ originWorld = nbt.getUUID("Paper.OriginWorld");
+ } else if (this.level != null) {
+ originWorld = this.level.getWorld().getUID();
+ }
+ this.originWorld = originWorld;
+ origin = new org.bukkit.util.Vector(originTag.getDouble(0), originTag.getDouble(1), originTag.getDouble(2));
+ }
+ // Paper end
+
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Loading entity NBT");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being loaded");
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 c125564cfca5c4a616e11b334a9ec7929ebea496..561b8d6fcf4d511fb026bcc2c02054e56589d0b7 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -339,6 +339,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 (nbt.contains("SourceLoc_x")) {
+ int srcX = nbt.getInt("SourceLoc_x");
+ int srcY = nbt.getInt("SourceLoc_y");
+ int srcZ = nbt.getInt("SourceLoc_z");
+ this.setOrigin(new org.bukkit.Location(level.getWorld(), srcX, srcY, srcZ));
+ }
+ // Paper end
}
public void setHurtsEntities(float fallHurtAmount, int fallHurtMax) {
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 43ec4bc45a3e553fbbf47aaf613f6e0aad2319cf..aa0dfd08aefbb9363ec96080432f0f75d71b0b95 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -117,6 +117,14 @@ public class PrimedTnt extends Entity {
@Override
protected void readAdditionalSaveData(CompoundTag nbt) {
this.setFuse(nbt.getShort("Fuse"));
+ // Paper start - Try and load origin location from the old NBT tags for backwards compatibility
+ if (nbt.contains("SourceLoc_x")) {
+ int srcX = nbt.getInt("SourceLoc_x");
+ int srcY = nbt.getInt("SourceLoc_y");
+ int srcZ = nbt.getInt("SourceLoc_z");
+ this.setOrigin(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 55bf95017d58bb61f9c6af27335c88421c74c4aa..62c2780b165a520e85f17fdf5c0d1c29b7579ebc 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1217,5 +1217,20 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return ret;
}
+
+ @Override
+ public Location getOrigin() {
+ Vector originVector = this.getHandle().getOriginVector();
+ if (originVector == null) {
+ return null;
+ }
+ World world = this.getWorld();
+ if (this.getHandle().getOriginWorld() != null) {
+ world = org.bukkit.Bukkit.getWorld(this.getHandle().getOriginWorld());
+ }
+
+ //noinspection ConstantConditions
+ return originVector.toLocation(world);
+ }
// Paper end
}