okaaay let's go
This commit is contained in:
parent
d348cb88a9
commit
2ef589c820
1191 changed files with 411 additions and 358 deletions
|
@ -175,7 +175,7 @@ index 71a22e50d5e543d41b0d285fabfa0965a393ab2e..00000000000000000000000000000000
|
|||
- <groupId>org.spigotmc</groupId>
|
||||
- <artifactId>spigot</artifactId>
|
||||
- <packaging>jar</packaging>
|
||||
- <version>1.21.1-R0.1-SNAPSHOT</version>
|
||||
- <version>1.21.2-R0.1-SNAPSHOT</version>
|
||||
- <name>Spigot</name>
|
||||
- <url>https://www.spigotmc.org/</url>
|
||||
-
|
||||
|
|
|
@ -1,211 +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 766006fe7ff965d6ca17df1df457ecc629b3be18..0ef1a7b2a17e81144d594f29f7b5e54d5038dcf4 100644
|
||||
--- a/src/main/java/net/minecraft/core/BlockPos.java
|
||||
+++ b/src/main/java/net/minecraft/core/BlockPos.java
|
||||
@@ -323,9 +323,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 () -> new AbstractIterator<BlockPos>() {
|
||||
private final BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
|
||||
private int currentDepth;
|
||||
@@ -339,7 +341,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;
|
||||
@@ -365,7 +367,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/world/entity/ai/behavior/BehaviorUtils.java b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java
|
||||
index 7344cff32fa6fe3dedb74ed98126072c55b0abd2..d98b28e9488a5a7736719cf656736bb026ec8c7e 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
|
||||
@@ -169,10 +169,10 @@ 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 entityliving2) {
|
||||
+ if (entity1 instanceof LivingEntity entityliving2) { // Paper - remap fix
|
||||
entityliving1 = entityliving2;
|
||||
} else {
|
||||
entityliving1 = null;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java
|
||||
index 9051f0186c09eeb8ecccf62b0116f6da1800a1df..b231f90317fe7df9133674b12d47873520b481cb 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java
|
||||
@@ -259,8 +259,8 @@ public class LootTable {
|
||||
|
||||
public static class Builder implements FunctionUserBuilder<LootTable.Builder> {
|
||||
|
||||
- private final Builder<LootPool> pools = ImmutableList.builder();
|
||||
- private final Builder<LootItemFunction> functions = ImmutableList.builder();
|
||||
+ private final ImmutableList.Builder<LootPool> pools = ImmutableList.builder();
|
||||
+ private final ImmutableList.Builder<LootItemFunction> functions = ImmutableList.builder();
|
||||
private LootContextParamSet paramSet;
|
||||
private Optional<ResourceLocation> randomSequence;
|
||||
|
||||
diff --git a/src/test/java/org/bukkit/DyeColorsTest.java b/src/test/java/org/bukkit/DyeColorsTest.java
|
||||
index e96d821da0698dd42651500fb97a0856a9e9ce02..fb7d40181abdaa5b2ce607db47c09d0d0a19c86d 100644
|
||||
--- a/src/test/java/org/bukkit/DyeColorsTest.java
|
||||
+++ b/src/test/java/org/bukkit/DyeColorsTest.java
|
||||
@@ -3,7 +3,6 @@ package org.bukkit;
|
||||
import static org.bukkit.support.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
-import net.minecraft.world.item.DyeColor;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
@@ -15,7 +14,7 @@ public class DyeColorsTest {
|
||||
@EnumSource(DyeColor.class)
|
||||
public void checkColor(DyeColor dye) {
|
||||
Color color = dye.getColor();
|
||||
- int nmsColorArray = DyeColor.byId(dye.getWoolData()).getTextureDiffuseColor();
|
||||
+ int nmsColorArray = net.minecraft.world.item.DyeColor.byId(dye.getWoolData()).getTextureDiffuseColor(); // Paper - remap fix
|
||||
Color nmsColor = Color.fromARGB(nmsColorArray);
|
||||
assertThat(color, is(nmsColor));
|
||||
}
|
||||
@@ -24,7 +23,7 @@ public class DyeColorsTest {
|
||||
@EnumSource(org.bukkit.DyeColor.class)
|
||||
public void checkFireworkColor(org.bukkit.DyeColor dye) {
|
||||
Color color = dye.getFireworkColor();
|
||||
- int nmsColor = DyeColor.byId(dye.getWoolData()).getFireworkColor();
|
||||
+ int nmsColor = net.minecraft.world.item.DyeColor.byId(dye.getWoolData()).getFireworkColor(); // Paper - remap fix
|
||||
assertThat(color, is(Color.fromRGB(nmsColor)));
|
||||
}
|
||||
}
|
||||
diff --git a/src/test/java/org/bukkit/ParticleTest.java b/src/test/java/org/bukkit/ParticleTest.java
|
||||
index 688c5bae8146f6fc8cddb2632e9cbf304f0745fb..1b0df6220682328b8f1d03416cb8df2f6662a1cf 100644
|
||||
--- a/src/test/java/org/bukkit/ParticleTest.java
|
||||
+++ b/src/test/java/org/bukkit/ParticleTest.java
|
||||
@@ -251,7 +251,7 @@ public class ParticleTest {
|
||||
Check in CraftParticle if the conversion is still correct.
|
||||
""", bukkit.getKey()));
|
||||
|
||||
- DataResult<Tag> encoded = assertDoesNotThrow(() -> minecraft.codec().codec().encodeStart(DynamicOpsNBT.INSTANCE, particleParam),
|
||||
+ DataResult<Tag> encoded = assertDoesNotThrow(() -> minecraft.codec().codec().encodeStart(NbtOps.INSTANCE, particleParam), // Paper - remap fix
|
||||
String.format("""
|
||||
Could not encoded particle param for particle %s.
|
||||
This can indicated, that the wrong particle param is created in CraftParticle.
|
||||
diff --git a/src/test/java/org/bukkit/entity/EntityTypesTest.java b/src/test/java/org/bukkit/entity/EntityTypesTest.java
|
||||
index 9df52ab0f04758dd04f45f6029fe120ac1a933af..d513d926ddabd61a03172adb846afb7674ed402e 100644
|
||||
--- a/src/test/java/org/bukkit/entity/EntityTypesTest.java
|
||||
+++ b/src/test/java/org/bukkit/entity/EntityTypesTest.java
|
||||
@@ -6,7 +6,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.environment.AllFeatures;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -17,8 +16,8 @@ public class EntityTypesTest {
|
||||
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());
|
||||
assertNotNull(bukkit, "Missing nms->bukkit " + key);
|
||||
diff --git a/src/test/java/org/bukkit/entity/PandaGeneTest.java b/src/test/java/org/bukkit/entity/PandaGeneTest.java
|
||||
index 4a3ac959f0dcc35f80371443383be1f8b42b6d95..e8520f541fda2d1cd9677f3fc7d7d295743f88b2 100644
|
||||
--- a/src/test/java/org/bukkit/entity/PandaGeneTest.java
|
||||
+++ b/src/test/java/org/bukkit/entity/PandaGeneTest.java
|
||||
@@ -2,7 +2,6 @@ package org.bukkit.entity;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
-import net.minecraft.world.entity.animal.Panda;
|
||||
import org.bukkit.craftbukkit.entity.CraftPanda;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -12,8 +11,8 @@ public class PandaGeneTest {
|
||||
|
||||
@Test
|
||||
public void testBukkit() {
|
||||
- for (Panda.Gene gene : Panda.Gene.values()) {
|
||||
- Panda.Gene nms = CraftPanda.toNms(gene);
|
||||
+ for (Panda.Gene gene : Panda.Gene.values()) { // Paper - remap fix
|
||||
+ net.minecraft.world.entity.animal.Panda.Gene nms = CraftPanda.toNms(gene); // Paper - remap fix
|
||||
|
||||
assertNotNull(nms, "NMS gene null for " + gene);
|
||||
assertEquals(gene.isRecessive(), nms.isRecessive(), "Recessive status did not match " + gene);
|
||||
@@ -23,7 +22,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);
|
||||
|
||||
assertNotNull(bukkit, "Bukkit gene null for " + gene);
|
||||
diff --git a/src/test/java/org/bukkit/registry/RegistryConstantsTest.java b/src/test/java/org/bukkit/registry/RegistryConstantsTest.java
|
||||
index a382ca7c6e0f96e5d8be37fa8139360db13f9c2f..8fb906c77070eedec8cde263154eaf4610ad3197 100644
|
||||
--- a/src/test/java/org/bukkit/registry/RegistryConstantsTest.java
|
||||
+++ b/src/test/java/org/bukkit/registry/RegistryConstantsTest.java
|
||||
@@ -31,17 +31,17 @@ public class RegistryConstantsTest {
|
||||
|
||||
@Test
|
||||
public void testTrimMaterial() {
|
||||
- this.testExcessConstants(TrimMaterial.class, Registry.TRIM_MATERIAL);
|
||||
+ this.testExcessConstants(TrimMaterial.class, org.bukkit.Registry.TRIM_MATERIAL); // Paper - remap fix
|
||||
this.testMissingConstants(TrimMaterial.class, Registries.TRIM_MATERIAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTrimPattern() {
|
||||
- this.testExcessConstants(TrimPattern.class, Registry.TRIM_PATTERN);
|
||||
+ this.testExcessConstants(TrimPattern.class, org.bukkit.Registry.TRIM_PATTERN); // Paper - remap fix
|
||||
this.testMissingConstants(TrimPattern.class, Registries.TRIM_PATTERN);
|
||||
}
|
||||
|
||||
- private <T extends Keyed> void testExcessConstants(Class<T> clazz, Registry<T> registry) {
|
||||
+ private <T extends Keyed> void testExcessConstants(Class<T> clazz, org.bukkit.Registry<T> registry) { // Paper - remap fix
|
||||
List<NamespacedKey> excessKeys = new ArrayList<>();
|
||||
|
||||
for (Field field : clazz.getFields()) {
|
||||
diff --git a/src/test/java/org/bukkit/registry/RegistryLoadOrderTest.java b/src/test/java/org/bukkit/registry/RegistryLoadOrderTest.java
|
||||
index 52f057a3b81ae798a8ff354a90e2cc64264c0398..0c704fb9e73229f5632f1f48e59fccc0daf9ec26 100644
|
||||
--- a/src/test/java/org/bukkit/registry/RegistryLoadOrderTest.java
|
||||
+++ b/src/test/java/org/bukkit/registry/RegistryLoadOrderTest.java
|
||||
@@ -25,7 +25,7 @@ public class RegistryLoadOrderTest {
|
||||
|
||||
private static boolean initInterface = false;
|
||||
private static boolean initAbstract = false;
|
||||
- private static Registry<Keyed> registry;
|
||||
+ private static org.bukkit.Registry<Keyed> registry; // Paper - remap fix
|
||||
|
||||
public static Stream<Arguments> data() {
|
||||
return Stream.of(
|
|
@ -1,185 +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
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.server.packs.VanillaPackResourcesBuilder safeGetPath(Ljava/net/URI;)Ljava/nio/file/Path;
|
||||
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index 82b298d454dee6a6d996aa7822dd745e70a8da74..ef88afa5fe914ae3fef9ffb1a971dabf568f75f3 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -8,9 +8,7 @@ plugins {
|
||||
dependencies {
|
||||
implementation(project(":paper-api"))
|
||||
implementation("jline:jline:2.12.1")
|
||||
- implementation("org.apache.logging.log4j:log4j-iostreams:2.22.1") {
|
||||
- exclude(group = "org.apache.logging.log4j", module = "log4j-api")
|
||||
- }
|
||||
+ implementation("org.apache.logging.log4j:log4j-iostreams:2.22.1") // Paper - remove exclusion
|
||||
implementation("org.ow2.asm:asm-commons:9.7.1")
|
||||
implementation("commons-lang:commons-lang:2.6")
|
||||
runtimeOnly("org.xerial:sqlite-jdbc:3.46.0.0")
|
||||
@@ -39,6 +37,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",
|
||||
@@ -47,6 +46,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 paperweight.craftBukkitPackageVersion.get(), // Paper
|
||||
)
|
||||
for (tld in setOf("net", "com", "org")) {
|
||||
attributes("$tld/bukkit", "Sealed" to true)
|
||||
@@ -59,6 +61,17 @@ publishing {
|
||||
}
|
||||
}
|
||||
|
||||
+// Paper start
|
||||
+val scanJar = tasks.register("scanJarForBadCalls", io.papermc.paperweight.tasks.ScanJarForBadCalls::class) {
|
||||
+ badAnnotations.add("Lio/papermc/paper/annotation/DoNotUse;")
|
||||
+ jarToScan.set(tasks.serverJar.flatMap { it.archiveFile })
|
||||
+ classpath.from(configurations.compileClasspath)
|
||||
+}
|
||||
+tasks.check {
|
||||
+ dependsOn(scanJar)
|
||||
+}
|
||||
+// Paper end
|
||||
+
|
||||
tasks.test {
|
||||
include("**/**TestSuite.class")
|
||||
workingDir = temporaryDir
|
||||
@@ -128,4 +141,5 @@ tasks.registerRunTask("runReobf") {
|
||||
tasks.registerRunTask("runDev") {
|
||||
description = "Spin up a non-relocated Mojang-mapped test server"
|
||||
classpath(sourceSets.main.map { it.runtimeClasspath })
|
||||
+ jvmArgs("-DPaper.pushPaperAssetsRoot=true")
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/resources/ResourceLocation.java b/src/main/java/net/minecraft/resources/ResourceLocation.java
|
||||
index bfc8f152fa91dff1dcd5fd07fc067e8e5e480002..262660d115a5d5cbecfbae995955a24283e666b0 100644
|
||||
--- a/src/main/java/net/minecraft/resources/ResourceLocation.java
|
||||
+++ b/src/main/java/net/minecraft/resources/ResourceLocation.java
|
||||
@@ -32,6 +32,7 @@ public final class ResourceLocation implements Comparable<ResourceLocation> {
|
||||
public static final char NAMESPACE_SEPARATOR = ':';
|
||||
public static final String DEFAULT_NAMESPACE = "minecraft";
|
||||
public static final String REALMS_NAMESPACE = "realms";
|
||||
+ public static final String PAPER_NAMESPACE = "paper"; // Paper
|
||||
private final String namespace;
|
||||
private final String path;
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/packs/VanillaPackResourcesBuilder.java b/src/main/java/net/minecraft/server/packs/VanillaPackResourcesBuilder.java
|
||||
index 14fc03563daea531314c7ceba56dbb47884010ee..fcf95958ef659c7aa8e28026961fa1d6a5f8b28c 100644
|
||||
--- a/src/main/java/net/minecraft/server/packs/VanillaPackResourcesBuilder.java
|
||||
+++ b/src/main/java/net/minecraft/server/packs/VanillaPackResourcesBuilder.java
|
||||
@@ -138,6 +138,15 @@ public class VanillaPackResourcesBuilder {
|
||||
|
||||
public VanillaPackResourcesBuilder applyDevelopmentConfig() {
|
||||
developmentConfig.accept(this);
|
||||
+ if (Boolean.getBoolean("Paper.pushPaperAssetsRoot")) {
|
||||
+ try {
|
||||
+ this.pushAssetPath(net.minecraft.server.packs.PackType.SERVER_DATA, net.minecraft.server.packs.VanillaPackResourcesBuilder.safeGetPath(java.util.Objects.requireNonNull(
|
||||
+ // Important that this is a patched class
|
||||
+ VanillaPackResourcesBuilder.class.getResource("/data/.paperassetsroot"), "Missing required .paperassetsroot file").toURI()).getParent());
|
||||
+ } catch (java.net.URISyntaxException | IOException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
+ }
|
||||
return this;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/packs/repository/ServerPacksSource.java b/src/main/java/net/minecraft/server/packs/repository/ServerPacksSource.java
|
||||
index feca36209fd2405fab70f564f63e627b8b78ac18..396ec10a76bdadbf5be2f0e15e88eed47619004d 100644
|
||||
--- a/src/main/java/net/minecraft/server/packs/repository/ServerPacksSource.java
|
||||
+++ b/src/main/java/net/minecraft/server/packs/repository/ServerPacksSource.java
|
||||
@@ -48,7 +48,7 @@ public class ServerPacksSource extends BuiltInPackSource {
|
||||
public static VanillaPackResources createVanillaPackSource() {
|
||||
return new VanillaPackResourcesBuilder()
|
||||
.setMetadata(BUILT_IN_METADATA)
|
||||
- .exposeNamespace("minecraft")
|
||||
+ .exposeNamespace("minecraft", ResourceLocation.PAPER_NAMESPACE) // Paper
|
||||
.applyDevelopmentConfig()
|
||||
.pushJarResources()
|
||||
.build(VANILLA_PACK_INFO);
|
||||
@@ -68,7 +68,18 @@ public class ServerPacksSource extends BuiltInPackSource {
|
||||
@Nullable
|
||||
@Override
|
||||
protected Pack createBuiltinPack(String fileName, Pack.ResourcesSupplier packFactory, Component displayName) {
|
||||
- return Pack.readMetaAndCreate(createBuiltInPackLocation(fileName, displayName), packFactory, PackType.SERVER_DATA, FEATURE_SELECTION_CONFIG);
|
||||
+ // Paper start - custom built-in pack
|
||||
+ final PackLocationInfo info;
|
||||
+ final PackSelectionConfig packConfig;
|
||||
+ if ("paper".equals(fileName)) {
|
||||
+ info = new PackLocationInfo(fileName, displayName, PackSource.BUILT_IN, Optional.empty());
|
||||
+ packConfig = new PackSelectionConfig(true, Pack.Position.TOP, true);
|
||||
+ } else {
|
||||
+ info = createBuiltInPackLocation(fileName, displayName);
|
||||
+ packConfig = FEATURE_SELECTION_CONFIG;
|
||||
+ }
|
||||
+ return Pack.readMetaAndCreate(info, packFactory, PackType.SERVER_DATA, packConfig);
|
||||
+ // Paper end - custom built-in pack
|
||||
}
|
||||
|
||||
public static PackRepository createPackRepository(Path dataPacksPath, DirectoryValidator symlinkFinder) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index dd64f5c16560d2ce6255c8319ddd0f5157237f0f..4566237fa1d49a559b2df806f9a318be46a6eade 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -199,7 +199,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) {
|
||||
diff --git a/src/main/resources/data/.paperassetsroot b/src/main/resources/data/.paperassetsroot
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
|
||||
diff --git a/src/main/resources/data/minecraft/datapacks/paper/pack.mcmeta b/src/main/resources/data/minecraft/datapacks/paper/pack.mcmeta
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..288fbe68c6053f40e72f0feedef0ae0fed10fa67
|
||||
--- /dev/null
|
||||
+++ b/src/main/resources/data/minecraft/datapacks/paper/pack.mcmeta
|
||||
@@ -0,0 +1,6 @@
|
||||
+{
|
||||
+ "pack": {
|
||||
+ "description": "Built-in Paper Datapack",
|
||||
+ "pack_format": 41
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/test/java/org/bukkit/support/RegistryHelper.java b/src/test/java/org/bukkit/support/RegistryHelper.java
|
||||
index e5dbcdcbd4187c724c3c6a3b8141a3796710c7a8..73645ea2e5c17e973ed3b888aab56f733f9c87a3 100644
|
||||
--- a/src/test/java/org/bukkit/support/RegistryHelper.java
|
||||
+++ b/src/test/java/org/bukkit/support/RegistryHelper.java
|
||||
@@ -58,6 +58,7 @@ public final class RegistryHelper {
|
||||
}
|
||||
|
||||
public static void setup(FeatureFlagSet featureFlagSet) {
|
||||
+ System.setProperty("Paper.pushPaperAssetsRoot", "true"); // Paper - build system changes - push asset root
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
|
|
@ -1,442 +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
|
||||
|
||||
Co-authored-by: yannnicklamprecht <yannicklamprecht@live.de>
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index ef88afa5fe914ae3fef9ffb1a971dabf568f75f3..3c1770864ab3e8708bab6cd50d6ffb5e19af5399 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -23,6 +23,7 @@ dependencies {
|
||||
testImplementation("org.hamcrest:hamcrest:2.2")
|
||||
testImplementation("org.mockito:mockito-core:5.14.1")
|
||||
testImplementation("org.ow2.asm:asm-tree:9.7.1")
|
||||
+ testImplementation("org.junit-pioneer:junit-pioneer:2.2.0") // Paper - CartesianTest
|
||||
}
|
||||
|
||||
paperweight {
|
||||
@@ -56,6 +57,12 @@ tasks.jar {
|
||||
}
|
||||
}
|
||||
|
||||
+// Paper start - compile tests with -parameters for better junit parameterized test names
|
||||
+tasks.compileTestJava {
|
||||
+ options.compilerArgs.add("-parameters")
|
||||
+}
|
||||
+// Paper end
|
||||
+
|
||||
publishing {
|
||||
publications.create<MavenPublication>("maven") {
|
||||
}
|
||||
diff --git a/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java b/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..fe52d229c31526cc32f6422328efe92edf75a7ff
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java
|
||||
@@ -0,0 +1,34 @@
|
||||
+package io.papermc.paper.registry;
|
||||
+
|
||||
+import java.util.Optional;
|
||||
+import java.util.stream.Stream;
|
||||
+import net.minecraft.core.Registry;
|
||||
+import net.minecraft.resources.ResourceKey;
|
||||
+import net.minecraft.resources.ResourceLocation;
|
||||
+import org.bukkit.support.AbstractTestingBase;
|
||||
+import org.junit.jupiter.api.BeforeAll;
|
||||
+import org.junit.jupiter.params.ParameterizedTest;
|
||||
+import org.junit.jupiter.params.provider.MethodSource;
|
||||
+
|
||||
+import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
+
|
||||
+@AllFeatures
|
||||
+class RegistryKeyTest {
|
||||
+
|
||||
+ @BeforeAll
|
||||
+ static void before() throws ClassNotFoundException {
|
||||
+ Class.forName(RegistryKey.class.getName()); // load all keys so they are found for the test
|
||||
+ }
|
||||
+
|
||||
+ static Stream<RegistryKey<?>> data() {
|
||||
+ return RegistryKeyImpl.REGISTRY_KEYS.stream();
|
||||
+ }
|
||||
+
|
||||
+ @ParameterizedTest
|
||||
+ @MethodSource("data")
|
||||
+ void testApiRegistryKeysExist(final RegistryKey<?> key) {
|
||||
+ final Optional<Registry<Object>> registry = RegistryHelper.getRegistry().registry(ResourceKey.createRegistryKey(ResourceLocation.parse(key.key().asString())));
|
||||
+ assertTrue(registry.isPresent(), "Missing vanilla registry for " + key.key().asString());
|
||||
+
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/test/java/io/papermc/paper/util/EmptyTag.java b/src/test/java/io/papermc/paper/util/EmptyTag.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6eb95a5e2534974c0e52e2b78b04e7c2b2f28525
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/io/papermc/paper/util/EmptyTag.java
|
||||
@@ -0,0 +1,31 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import java.util.Collections;
|
||||
+import java.util.Set;
|
||||
+import org.bukkit.Keyed;
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.Tag;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+
|
||||
+public record EmptyTag(NamespacedKey key) implements Tag<Keyed> {
|
||||
+
|
||||
+ @SuppressWarnings("deprecation")
|
||||
+ public EmptyTag() {
|
||||
+ this(NamespacedKey.randomKey());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NotNull NamespacedKey getKey() {
|
||||
+ return this.key;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isTagged(@NotNull final Keyed item) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NotNull Set<Keyed> getValues() {
|
||||
+ return Collections.emptySet();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/test/java/io/papermc/paper/util/MethodParameterProvider.java b/src/test/java/io/papermc/paper/util/MethodParameterProvider.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..3f58ef36df34cd15fcb72189eeff057654adf0c6
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/io/papermc/paper/util/MethodParameterProvider.java
|
||||
@@ -0,0 +1,206 @@
|
||||
+/*
|
||||
+ * Copyright 2015-2023 the original author or authors of https://github.com/junit-team/junit5/blob/6593317c15fb556febbde11914fa7afe00abf8cd/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java
|
||||
+ *
|
||||
+ * All rights reserved. This program and the accompanying materials are
|
||||
+ * made available under the terms of the Eclipse Public License v2.0 which
|
||||
+ * accompanies this distribution and is available at
|
||||
+ *
|
||||
+ * https://www.eclipse.org/legal/epl-v20.html
|
||||
+ */
|
||||
+
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import java.lang.reflect.Method;
|
||||
+import java.lang.reflect.Parameter;
|
||||
+import java.util.List;
|
||||
+import java.util.function.Predicate;
|
||||
+import java.util.stream.Stream;
|
||||
+import org.junit.jupiter.api.Test;
|
||||
+import org.junit.jupiter.api.TestFactory;
|
||||
+import org.junit.jupiter.api.TestTemplate;
|
||||
+import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
+import org.junit.jupiter.params.support.AnnotationConsumer;
|
||||
+import org.junit.platform.commons.JUnitException;
|
||||
+import org.junit.platform.commons.PreconditionViolationException;
|
||||
+import org.junit.platform.commons.util.ClassLoaderUtils;
|
||||
+import org.junit.platform.commons.util.CollectionUtils;
|
||||
+import org.junit.platform.commons.util.Preconditions;
|
||||
+import org.junit.platform.commons.util.ReflectionUtils;
|
||||
+import org.junit.platform.commons.util.StringUtils;
|
||||
+import org.junitpioneer.jupiter.cartesian.CartesianParameterArgumentsProvider;
|
||||
+
|
||||
+import static java.lang.String.format;
|
||||
+import static java.util.Arrays.stream;
|
||||
+import static java.util.stream.Collectors.toList;
|
||||
+import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated;
|
||||
+import static org.junit.platform.commons.util.CollectionUtils.isConvertibleToStream;
|
||||
+
|
||||
+public class MethodParameterProvider implements CartesianParameterArgumentsProvider<Object>, AnnotationConsumer<MethodParameterSource> {
|
||||
+ private MethodParameterSource source;
|
||||
+
|
||||
+ MethodParameterProvider() {
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void accept(final MethodParameterSource source) {
|
||||
+ this.source = source;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Stream<Object> provideArguments(ExtensionContext context, Parameter parameter) {
|
||||
+ return this.provideArguments(context, this.source);
|
||||
+ }
|
||||
+
|
||||
+ // Below is mostly copied from MethodArgumentsProvider
|
||||
+
|
||||
+ private static final Predicate<Method> isFactoryMethod = //
|
||||
+ method -> isConvertibleToStream(method.getReturnType()) && !isTestMethod(method);
|
||||
+
|
||||
+ protected Stream<Object> provideArguments(ExtensionContext context, MethodParameterSource methodSource) {
|
||||
+ Class<?> testClass = context.getRequiredTestClass();
|
||||
+ Method testMethod = context.getRequiredTestMethod();
|
||||
+ Object testInstance = context.getTestInstance().orElse(null);
|
||||
+ String[] methodNames = methodSource.value();
|
||||
+ // @formatter:off
|
||||
+ return stream(methodNames)
|
||||
+ .map(factoryMethodName -> findFactoryMethod(testClass, testMethod, factoryMethodName))
|
||||
+ .map(factoryMethod -> validateFactoryMethod(factoryMethod, testInstance))
|
||||
+ .map(factoryMethod -> context.getExecutableInvoker().invoke(factoryMethod, testInstance))
|
||||
+ .flatMap(CollectionUtils::toStream);
|
||||
+ // @formatter:on
|
||||
+ }
|
||||
+
|
||||
+ private static Method findFactoryMethod(Class<?> testClass, Method testMethod, String factoryMethodName) {
|
||||
+ String originalFactoryMethodName = factoryMethodName;
|
||||
+
|
||||
+ // If the user did not provide a factory method name, find a "default" local
|
||||
+ // factory method with the same name as the parameterized test method.
|
||||
+ if (StringUtils.isBlank(factoryMethodName)) {
|
||||
+ factoryMethodName = testMethod.getName();
|
||||
+ return findFactoryMethodBySimpleName(testClass, testMethod, factoryMethodName);
|
||||
+ }
|
||||
+
|
||||
+ // Convert local factory method name to fully-qualified method name.
|
||||
+ if (!looksLikeAFullyQualifiedMethodName(factoryMethodName)) {
|
||||
+ factoryMethodName = testClass.getName() + "#" + factoryMethodName;
|
||||
+ }
|
||||
+
|
||||
+ // Find factory method using fully-qualified name.
|
||||
+ Method factoryMethod = findFactoryMethodByFullyQualifiedName(testClass, testMethod, factoryMethodName);
|
||||
+
|
||||
+ // Ensure factory method has a valid return type and is not a test method.
|
||||
+ Preconditions.condition(isFactoryMethod.test(factoryMethod), () -> format(
|
||||
+ "Could not find valid factory method [%s] for test class [%s] but found the following invalid candidate: %s",
|
||||
+ originalFactoryMethodName, testClass.getName(), factoryMethod));
|
||||
+
|
||||
+ return factoryMethod;
|
||||
+ }
|
||||
+
|
||||
+ private static boolean looksLikeAFullyQualifiedMethodName(String factoryMethodName) {
|
||||
+ if (factoryMethodName.contains("#")) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ int indexOfFirstDot = factoryMethodName.indexOf('.');
|
||||
+ if (indexOfFirstDot == -1) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ int indexOfLastOpeningParenthesis = factoryMethodName.lastIndexOf('(');
|
||||
+ if (indexOfLastOpeningParenthesis > 0) {
|
||||
+ // Exclude simple/local method names with parameters
|
||||
+ return indexOfFirstDot < indexOfLastOpeningParenthesis;
|
||||
+ }
|
||||
+ // If we get this far, we conclude the supplied factory method name "looks"
|
||||
+ // like it was intended to be a fully-qualified method name, even if the
|
||||
+ // syntax is invalid. We do this in order to provide better diagnostics for
|
||||
+ // the user when a fully-qualified method name is in fact invalid.
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ // package-private for testing
|
||||
+ static Method findFactoryMethodByFullyQualifiedName(
|
||||
+ Class<?> testClass, Method testMethod,
|
||||
+ String fullyQualifiedMethodName
|
||||
+ ) {
|
||||
+ String[] methodParts = ReflectionUtils.parseFullyQualifiedMethodName(fullyQualifiedMethodName);
|
||||
+ String className = methodParts[0];
|
||||
+ String methodName = methodParts[1];
|
||||
+ String methodParameters = methodParts[2];
|
||||
+ ClassLoader classLoader = ClassLoaderUtils.getClassLoader(testClass);
|
||||
+ Class<?> clazz = loadRequiredClass(className, classLoader);
|
||||
+
|
||||
+ // Attempt to find an exact match first.
|
||||
+ Method factoryMethod = ReflectionUtils.findMethod(clazz, methodName, methodParameters).orElse(null);
|
||||
+ if (factoryMethod != null) {
|
||||
+ return factoryMethod;
|
||||
+ }
|
||||
+
|
||||
+ boolean explicitParameterListSpecified = //
|
||||
+ StringUtils.isNotBlank(methodParameters) || fullyQualifiedMethodName.endsWith("()");
|
||||
+
|
||||
+ // If we didn't find an exact match but an explicit parameter list was specified,
|
||||
+ // that's a user configuration error.
|
||||
+ Preconditions.condition(!explicitParameterListSpecified,
|
||||
+ () -> format("Could not find factory method [%s(%s)] in class [%s]", methodName, methodParameters,
|
||||
+ className));
|
||||
+
|
||||
+ // Otherwise, fall back to the same lenient search semantics that are used
|
||||
+ // to locate a "default" local factory method.
|
||||
+ return findFactoryMethodBySimpleName(clazz, testMethod, methodName);
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Find the factory method by searching for all methods in the given {@code clazz}
|
||||
+ * with the desired {@code factoryMethodName} which have return types that can be
|
||||
+ * converted to a {@link Stream}, ignoring the {@code testMethod} itself as well
|
||||
+ * as any {@code @Test}, {@code @TestTemplate}, or {@code @TestFactory} methods
|
||||
+ * with the same name.
|
||||
+ *
|
||||
+ * @return the single factory method matching the search criteria
|
||||
+ * @throws PreconditionViolationException if the factory method was not found or
|
||||
+ * multiple competing factory methods with the same name were found
|
||||
+ */
|
||||
+ private static Method findFactoryMethodBySimpleName(Class<?> clazz, Method testMethod, String factoryMethodName) {
|
||||
+ Predicate<Method> isCandidate = candidate -> factoryMethodName.equals(candidate.getName())
|
||||
+ && !testMethod.equals(candidate);
|
||||
+ List<Method> candidates = ReflectionUtils.findMethods(clazz, isCandidate);
|
||||
+
|
||||
+ List<Method> factoryMethods = candidates.stream().filter(isFactoryMethod).collect(toList());
|
||||
+
|
||||
+ Preconditions.condition(factoryMethods.size() > 0, () -> {
|
||||
+ // If we didn't find the factory method using the isFactoryMethod Predicate, perhaps
|
||||
+ // the specified factory method has an invalid return type or is a test method.
|
||||
+ // In that case, we report the invalid candidates that were found.
|
||||
+ if (candidates.size() > 0) {
|
||||
+ return format(
|
||||
+ "Could not find valid factory method [%s] in class [%s] but found the following invalid candidates: %s",
|
||||
+ factoryMethodName, clazz.getName(), candidates);
|
||||
+ }
|
||||
+ // Otherwise, report that we didn't find anything.
|
||||
+ return format("Could not find factory method [%s] in class [%s]", factoryMethodName, clazz.getName());
|
||||
+ });
|
||||
+ Preconditions.condition(factoryMethods.size() == 1,
|
||||
+ () -> format("%d factory methods named [%s] were found in class [%s]: %s", factoryMethods.size(),
|
||||
+ factoryMethodName, clazz.getName(), factoryMethods));
|
||||
+ return factoryMethods.get(0);
|
||||
+ }
|
||||
+
|
||||
+ private static boolean isTestMethod(Method candidate) {
|
||||
+ return isAnnotated(candidate, Test.class) || isAnnotated(candidate, TestTemplate.class)
|
||||
+ || isAnnotated(candidate, TestFactory.class);
|
||||
+ }
|
||||
+
|
||||
+ private static Class<?> loadRequiredClass(String className, ClassLoader classLoader) {
|
||||
+ return ReflectionUtils.tryToLoadClass(className, classLoader).getOrThrow(
|
||||
+ cause -> new JUnitException(format("Could not load class [%s]", className), cause));
|
||||
+ }
|
||||
+
|
||||
+ private static Method validateFactoryMethod(Method factoryMethod, Object testInstance) {
|
||||
+ Preconditions.condition(
|
||||
+ factoryMethod.getDeclaringClass().isInstance(testInstance) || ReflectionUtils.isStatic(factoryMethod),
|
||||
+ () -> format("Method '%s' must be static: local factory methods must be static "
|
||||
+ + "unless the PER_CLASS @TestInstance lifecycle mode is used; "
|
||||
+ + "external factory methods must always be static.",
|
||||
+ factoryMethod.toGenericString()));
|
||||
+ return factoryMethod;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/test/java/io/papermc/paper/util/MethodParameterSource.java b/src/test/java/io/papermc/paper/util/MethodParameterSource.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6cbf11c898439834cffb99ef84e5df1494356809
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/io/papermc/paper/util/MethodParameterSource.java
|
||||
@@ -0,0 +1,14 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import java.lang.annotation.ElementType;
|
||||
+import java.lang.annotation.Retention;
|
||||
+import java.lang.annotation.RetentionPolicy;
|
||||
+import java.lang.annotation.Target;
|
||||
+import org.junitpioneer.jupiter.cartesian.CartesianArgumentsSource;
|
||||
+
|
||||
+@Retention(RetentionPolicy.RUNTIME)
|
||||
+@Target({ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
|
||||
+@CartesianArgumentsSource(MethodParameterProvider.class)
|
||||
+public @interface MethodParameterSource {
|
||||
+ String[] value() default {};
|
||||
+}
|
||||
diff --git a/src/test/java/org/bukkit/ExplosionResultTest.java b/src/test/java/org/bukkit/ExplosionResultTest.java
|
||||
index ee5ab15bb0bfeb0ff6fa0d720eeff086d92cb459..7419ea2f68607aad27929a608c402bd4c222f95d 100644
|
||||
--- a/src/test/java/org/bukkit/ExplosionResultTest.java
|
||||
+++ b/src/test/java/org/bukkit/ExplosionResultTest.java
|
||||
@@ -5,6 +5,7 @@ import net.minecraft.world.level.Explosion;
|
||||
import org.bukkit.craftbukkit.CraftExplosionResult;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
+@org.bukkit.support.environment.Normal // Paper - test changes - missing test suite annotation
|
||||
public class ExplosionResultTest {
|
||||
|
||||
@Test
|
||||
diff --git a/src/test/java/org/bukkit/registry/RegistryClassTest.java b/src/test/java/org/bukkit/registry/RegistryClassTest.java
|
||||
index 740073ddd99b5e6aba056b99d5ed3e2a94a13b6c..575a06125e0b60b5bb8b6f85131f7d6cf86f5083 100644
|
||||
--- a/src/test/java/org/bukkit/registry/RegistryClassTest.java
|
||||
+++ b/src/test/java/org/bukkit/registry/RegistryClassTest.java
|
||||
@@ -57,6 +57,7 @@ import org.objectweb.asm.Type;
|
||||
* Note: This test class assumes that feature flags only enable more features and do not disable vanilla ones.
|
||||
*/
|
||||
@AllFeatures
|
||||
+@org.junit.jupiter.api.Disabled // Paper - disabled for now as it constructs a second root registry, which is not supported on paper
|
||||
public class RegistryClassTest {
|
||||
|
||||
private static final Map<Class<? extends Keyed>, Data> INIT_DATA = new HashMap<>();
|
||||
diff --git a/src/test/java/org/bukkit/registry/RegistryConstantsTest.java b/src/test/java/org/bukkit/registry/RegistryConstantsTest.java
|
||||
index 8fb906c77070eedec8cde263154eaf4610ad3197..8705ee2a28d5dba7bb579eae1436451502e1e3c2 100644
|
||||
--- a/src/test/java/org/bukkit/registry/RegistryConstantsTest.java
|
||||
+++ b/src/test/java/org/bukkit/registry/RegistryConstantsTest.java
|
||||
@@ -26,7 +26,7 @@ public class RegistryConstantsTest {
|
||||
@Test
|
||||
public void testDamageType() {
|
||||
this.testExcessConstants(DamageType.class, Registry.DAMAGE_TYPE);
|
||||
- // this.testMissingConstants(DamageType.class, Registries.DAMAGE_TYPE); // WIND_CHARGE not registered
|
||||
+ this.testMissingConstants(DamageType.class, Registries.DAMAGE_TYPE); // Paper - re-enable this one
|
||||
}
|
||||
|
||||
@Test
|
||||
diff --git a/src/test/java/org/bukkit/support/DummyServerHelper.java b/src/test/java/org/bukkit/support/DummyServerHelper.java
|
||||
index 6ecafd167d4d8c79f2cbc43ea9da98a5d61d8751..f81f86cf05a8c6816d356185af6d0d84a0474dd2 100644
|
||||
--- a/src/test/java/org/bukkit/support/DummyServerHelper.java
|
||||
+++ b/src/test/java/org/bukkit/support/DummyServerHelper.java
|
||||
@@ -47,7 +47,7 @@ public final class DummyServerHelper {
|
||||
when(instance.getTag(any(), any(), any())).then(mock -> {
|
||||
String registry = mock.getArgument(0);
|
||||
Class<?> clazz = mock.getArgument(2);
|
||||
- MinecraftKey key = CraftNamespacedKey.toMinecraft(mock.getArgument(1));
|
||||
+ net.minecraft.resources.ResourceLocation key = CraftNamespacedKey.toMinecraft(mock.getArgument(1)); // Paper - address remapping issues
|
||||
|
||||
switch (registry) {
|
||||
case org.bukkit.Tag.REGISTRY_BLOCKS -> {
|
||||
@@ -66,24 +66,31 @@ public final class DummyServerHelper {
|
||||
}
|
||||
case org.bukkit.Tag.REGISTRY_FLUIDS -> {
|
||||
Preconditions.checkArgument(clazz == org.bukkit.Fluid.class, "Fluid namespace must have fluid type");
|
||||
- TagKey<FluidType> fluidTagKey = TagKey.create(Registries.FLUID, key);
|
||||
+ TagKey<net.minecraft.world.level.material.Fluid> fluidTagKey = TagKey.create(Registries.FLUID, key); // Paper - address remapping issues
|
||||
if (BuiltInRegistries.FLUID.getTag(fluidTagKey).isPresent()) {
|
||||
return new CraftFluidTag(BuiltInRegistries.FLUID, fluidTagKey);
|
||||
}
|
||||
}
|
||||
case org.bukkit.Tag.REGISTRY_ENTITY_TYPES -> {
|
||||
Preconditions.checkArgument(clazz == org.bukkit.entity.EntityType.class, "Entity type namespace must have entity type");
|
||||
- TagKey<EntityTypes<?>> entityTagKey = TagKey.create(Registries.ENTITY_TYPE, key);
|
||||
+ TagKey<net.minecraft.world.entity.EntityType<?>> entityTagKey = TagKey.create(Registries.ENTITY_TYPE, key); // Paper - address remapping issues
|
||||
if (BuiltInRegistries.ENTITY_TYPE.getTag(entityTagKey).isPresent()) {
|
||||
return new CraftEntityTag(BuiltInRegistries.ENTITY_TYPE, entityTagKey);
|
||||
}
|
||||
}
|
||||
- default -> throw new IllegalArgumentException();
|
||||
+ default -> new io.papermc.paper.util.EmptyTag(); // Paper - testing additions
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
+ // Paper start - testing additions
|
||||
+ final Thread currentThread = Thread.currentThread();
|
||||
+ when(instance.isPrimaryThread()).thenAnswer(ignored -> Thread.currentThread().equals(currentThread));
|
||||
+ final org.bukkit.plugin.PluginManager pluginManager = new org.bukkit.plugin.SimplePluginManager(instance, new org.bukkit.command.SimpleCommandMap(instance));
|
||||
+ when(instance.getPluginManager()).thenReturn(pluginManager);
|
||||
+ // Paper end - testing additions
|
||||
+
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
diff --git a/src/test/java/org/bukkit/support/RegistryHelper.java b/src/test/java/org/bukkit/support/RegistryHelper.java
|
||||
index 73645ea2e5c17e973ed3b888aab56f733f9c87a3..4d169ff3541044d447de519d2b0973da98b0bd53 100644
|
||||
--- a/src/test/java/org/bukkit/support/RegistryHelper.java
|
||||
+++ b/src/test/java/org/bukkit/support/RegistryHelper.java
|
||||
@@ -98,6 +98,11 @@ public final class RegistryHelper {
|
||||
private static LayeredRegistryAccess<RegistryLayer> createLayers(MultiPackResourceManager resourceManager) {
|
||||
// add tags and loot tables for unit tests
|
||||
LayeredRegistryAccess<RegistryLayer> layers = RegistryLayer.createRegistryAccess();
|
||||
+ // Paper start - load registry here to ensure bukkit object registry are correctly delayed if needed
|
||||
+ try {
|
||||
+ Class.forName("org.bukkit.Registry");
|
||||
+ } catch (final ClassNotFoundException ignored) {}
|
||||
+ // Paper end - load registry here to ensure bukkit object registry are correctly delayed if needed
|
||||
layers = WorldLoader.loadAndReplaceLayer(resourceManager, layers, RegistryLayer.WORLDGEN, RegistryDataLoader.WORLDGEN_REGISTRIES);
|
||||
|
||||
return layers;
|
File diff suppressed because it is too large
Load diff
|
@ -1,124 +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/commands/arguments/item/ItemInput.java b/src/main/java/net/minecraft/commands/arguments/item/ItemInput.java
|
||||
index 643bb8860962ad691b11073f6dbf406bf7ec5fb1..9b8ec1fd158f6e51779be263fd56b9119d0d9bbb 100644
|
||||
--- a/src/main/java/net/minecraft/commands/arguments/item/ItemInput.java
|
||||
+++ b/src/main/java/net/minecraft/commands/arguments/item/ItemInput.java
|
||||
@@ -78,6 +78,6 @@ public class ItemInput {
|
||||
}
|
||||
|
||||
private String getItemName() {
|
||||
- return this.item.unwrapKey().map(ResourceKey::location).orElseGet(() -> "unknown[" + this.item + "]").toString();
|
||||
+ return this.item.unwrapKey().<Object>map(ResourceKey::location).orElseGet(() -> "unknown[" + this.item + "]").toString(); // Paper - decompile fix
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
|
||||
index 0ef1a7b2a17e81144d594f29f7b5e54d5038dcf4..8994a381b05dcdd1163d2e7a0b63a8875b6063ed 100644
|
||||
--- a/src/main/java/net/minecraft/core/BlockPos.java
|
||||
+++ b/src/main/java/net/minecraft/core/BlockPos.java
|
||||
@@ -439,12 +439,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 a467eb6b3b74cdb5378ff5f3043efbe6f4a6f06e..34b3b3251da21bce616870d312fd42fd58ba7881 100644
|
||||
--- a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java
|
||||
+++ b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java
|
||||
@@ -317,7 +317,7 @@ public class BuiltInRegistries {
|
||||
Bootstrap.checkBootstrapCalled(() -> "registry " + key);
|
||||
ResourceLocation resourceLocation = key.location();
|
||||
LOADERS.put(resourceLocation, () -> initializer.run(registry));
|
||||
- WRITABLE_REGISTRY.register((ResourceKey<WritableRegistry<?>>)key, registry, RegistrationInfo.BUILT_IN);
|
||||
+ WRITABLE_REGISTRY.register((ResourceKey)key, registry, RegistrationInfo.BUILT_IN); // Paper - decompile fix
|
||||
return registry;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/nbt/TagParser.java b/src/main/java/net/minecraft/nbt/TagParser.java
|
||||
index a614e960fcd5958ad17b679eee8a8e6926f58e62..da101bca71f4710812621b98f0a0d8cab180346a 100644
|
||||
--- a/src/main/java/net/minecraft/nbt/TagParser.java
|
||||
+++ b/src/main/java/net/minecraft/nbt/TagParser.java
|
||||
@@ -253,11 +253,11 @@ public class TagParser {
|
||||
}
|
||||
|
||||
if (typeReader == ByteTag.TYPE) {
|
||||
- list.add((T)((NumericTag)tag).getAsByte());
|
||||
+ list.add((T)(Byte)((NumericTag)tag).getAsByte()); // Paper - decompile fix
|
||||
} else if (typeReader == LongTag.TYPE) {
|
||||
- list.add((T)((NumericTag)tag).getAsLong());
|
||||
+ list.add((T)(Long)((NumericTag)tag).getAsLong()); // Paper - decompile fix
|
||||
} else {
|
||||
- list.add((T)((NumericTag)tag).getAsInt());
|
||||
+ list.add((T)(Integer)((NumericTag)tag).getAsInt()); // Paper - decompile fix
|
||||
}
|
||||
|
||||
if (!this.hasElementSeparator()) {
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 299afe72a2fc2affca196f2fdfbf27e5533c51a6..40adb6117b9e0d5f70103113202a07715e403e2a 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1952,7 +1952,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/util/SortedArraySet.java b/src/main/java/net/minecraft/util/SortedArraySet.java
|
||||
index 661a6274a800ca9b91bdb809d026972d23c3b263..ea72dcb064a35bc6245bc5c94d592efedd8faf41 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/monster/Pillager.java b/src/main/java/net/minecraft/world/entity/monster/Pillager.java
|
||||
index 8eb1aca72df0bca292473e90ecb74159db4fe034..4b4dcee6abe7a6db43638d04665125eec560496e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Pillager.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Pillager.java
|
||||
@@ -66,7 +66,7 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve
|
||||
protected void registerGoals() {
|
||||
super.registerGoals();
|
||||
this.goalSelector.addGoal(0, new FloatGoal(this));
|
||||
- this.goalSelector.addGoal(2, new Raider.HoldGroundAttackGoal(this, this, 10.0F));
|
||||
+ this.goalSelector.addGoal(2, new Raider.HoldGroundAttackGoal(this, 10.0F)); // Paper - decomp fix
|
||||
this.goalSelector.addGoal(3, new RangedCrossbowAttackGoal<>(this, 1.0D, 8.0F));
|
||||
this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D));
|
||||
this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 15.0F, 1.0F));
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java
|
||||
index e2b72817857a7a203aae4c9de4e01ba1396dc95b..82fc5133325a127890984d51c1381883759eb444 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java
|
||||
@@ -153,7 +153,7 @@ public class ChunkStatusTasks {
|
||||
if (protochunk instanceof ImposterProtoChunk) {
|
||||
chunk1 = ((ImposterProtoChunk) protochunk).getWrapped();
|
||||
} else {
|
||||
- chunk1 = new LevelChunk(worldserver, protochunk, (chunk1) -> {
|
||||
+ chunk1 = new LevelChunk(worldserver, protochunk, ($) -> { // Paper - decompile fix
|
||||
ChunkStatusTasks.postLoadProtoChunk(worldserver, protochunk.getEntities());
|
||||
});
|
||||
generationchunkholder.replaceProtoChunk(new ImposterProtoChunk(chunk1, false));
|
File diff suppressed because it is too large
Load diff
|
@ -1,142 +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)
|
||||
|
||||
* Fix summon_entity effect attempting to add incorrect entity (granny)
|
||||
|
||||
* 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 a696a0d168987aaa4e59c471a23eeb48d683c1b2..9d11fcb3df12182ae00ce73f7e30091fd199a341 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -303,7 +303,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/item/enchantment/effects/SummonEntityEffect.java b/src/main/java/net/minecraft/world/item/enchantment/effects/SummonEntityEffect.java
|
||||
index d927357d541cf206bb3019b2fda3473a77b44ec4..4601c7069ba82ccfe87e9dc304b6f3262f7bbfbf 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/enchantment/effects/SummonEntityEffect.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/enchantment/effects/SummonEntityEffect.java
|
||||
@@ -54,7 +54,7 @@ public record SummonEntityEffect(HolderSet<EntityType<?>> entityTypes, boolean j
|
||||
// CraftBukkit start
|
||||
world.strikeLightning(entity1, (context.itemStack().getItem() == Items.TRIDENT) ? LightningStrikeEvent.Cause.TRIDENT : LightningStrikeEvent.Cause.ENCHANTMENT);
|
||||
} else {
|
||||
- world.addFreshEntityWithPassengers(user, CreatureSpawnEvent.SpawnReason.ENCHANTMENT);
|
||||
+ world.addFreshEntityWithPassengers(entity1, CreatureSpawnEvent.SpawnReason.ENCHANTMENT); // Paper - Fix typo when adding summoned entity
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
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 0dc7f88877020bddd5a84db51d349f52b673048e..aae73586265593ee7830fb8dd5c2e3d7560057f0 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
|
||||
@@ -40,7 +40,7 @@ public class StructureCheck {
|
||||
private final ChunkScanAccess storageAccess;
|
||||
private final RegistryAccess registryAccess;
|
||||
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 {
|
||||
ChunkScanAccess chunkIoWorker,
|
||||
RegistryAccess registryManager,
|
||||
StructureTemplateManager structureTemplateManager,
|
||||
- ResourceKey<Level> worldKey,
|
||||
+ ResourceKey<net.minecraft.world.level.dimension.LevelStem> worldKey, // Paper - fix missing CB diff
|
||||
ChunkGenerator chunkGenerator,
|
||||
RandomState noiseConfig,
|
||||
LevelHeightAccessor world,
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java b/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java
|
||||
index 85c7f3027978b1d7d6c31b7ad21b3377cdda5925..e34deaf398dc6722c3128bdd6b9bc16da2d33bf7 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java
|
||||
@@ -187,4 +187,11 @@ public class CraftLootTable implements org.bukkit.loot.LootTable {
|
||||
org.bukkit.loot.LootTable table = (org.bukkit.loot.LootTable) obj;
|
||||
return table.getKey().equals(this.getKey());
|
||||
}
|
||||
+
|
||||
+ // Paper start - satisfy equals/hashCode contract
|
||||
+ @Override
|
||||
+ public int hashCode() {
|
||||
+ return java.util.Objects.hash(key);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index 0ea2d13ab80559472513c6df362583b8371a9532..13c37384defda4475de584f33d1860a2d53ce05e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -123,6 +123,7 @@ public class Main {
|
||||
this.acceptsAll(Main.asList("forceUpgrade"), "Whether to force a world upgrade");
|
||||
this.acceptsAll(Main.asList("eraseCache"), "Whether to force cache erase during world upgrade");
|
||||
this.acceptsAll(Main.asList("recreateRegionFiles"), "Whether to recreate region files during world upgrade");
|
||||
+ this.accepts("safeMode", "Loads level with vanilla datapack only"); // Paper
|
||||
this.acceptsAll(Main.asList("nogui"), "Disables the graphical console");
|
||||
|
||||
this.acceptsAll(Main.asList("nojline"), "Disables jline and emulates the vanilla console");
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
index 905adf97c0d1f0d1c774a6835a5dffcfea884e58..c017ce2ca1bc535795c958a2e509af2adf88efa9 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
@@ -26,6 +26,7 @@ import org.bukkit.scheduler.BukkitWorker;
|
||||
|
||||
/**
|
||||
* The fundamental concepts for this implementation:
|
||||
+ * <ul>
|
||||
* <li>Main thread owns {@link #head} and {@link #currentTick}, but it may be read from any thread</li>
|
||||
* <li>Main thread exclusively controls {@link #temp} and {@link #pending}.
|
||||
* They are never to be accessed outside of the main thread; alternatives exist to prevent locking.</li>
|
||||
@@ -41,6 +42,7 @@ import org.bukkit.scheduler.BukkitWorker;
|
||||
* <li>Sync tasks are only to be removed from runners on the main thread when coupled with a removal from pending and temp.</li>
|
||||
* <li>Most of the design in this scheduler relies on queuing special tasks to perform any data changes on the main thread.
|
||||
* When executed from inside a synchronous method, the scheduler will be updated before next execution by virtue of the frequent {@link #parsePending()} calls.</li>
|
||||
+ * </ul>
|
||||
*/
|
||||
public class CraftScheduler implements BukkitScheduler {
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index a0f228ee83fd3a913666f88381c946f8a6340644..60dc550431fa4641f8c6d964329b0e2698d1fdd6 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -246,7 +246,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
try {
|
||||
nmsStack.applyComponents(new ItemParser(Commands.createValidationContext(MinecraftServer.getDefaultRegistryAccess())).parse(new StringReader(arguments)).components());
|
||||
} catch (CommandSyntaxException ex) {
|
||||
- Logger.getLogger(CraftMagicNumbers.class.getName()).log(Level.SEVERE, null, ex);
|
||||
+ com.mojang.logging.LogUtils.getClassLogger().error("Exception modifying ItemStack", new Throwable(ex)); // Paper - show stack trace
|
||||
}
|
||||
|
||||
stack.setItemMeta(CraftItemStack.getItemMeta(nmsStack));
|
||||
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 5ac25dab93fd4c9e9533c80d1ca3d93446d7a365..245ad120a36b6defca7e6889faae1ca5fc33d0c7 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
|
@ -1,700 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Minecrell <minecrell@minecrell.net>
|
||||
Date: Fri, 9 Jun 2017 19:03:43 +0200
|
||||
Subject: [PATCH] Use TerminalConsoleAppender for console improvements
|
||||
|
||||
Rewrite console improvements (console colors, tab completion,
|
||||
persistent input line, ...) using JLine 3.x and TerminalConsoleAppender.
|
||||
|
||||
Also uses the new ANSIComponentSerializer to serialize components when
|
||||
logging them via the ComponentLogger, or when sending messages to the
|
||||
console, for hex color support.
|
||||
|
||||
New features:
|
||||
- Support console colors for Vanilla commands
|
||||
- Add console colors for warnings and errors
|
||||
- Server can now be turned off safely using CTRL + C. JLine catches
|
||||
the signal and the implementation shuts down the server cleanly.
|
||||
- Support console colors and persistent input line when running in
|
||||
IntelliJ IDEA
|
||||
|
||||
Other changes:
|
||||
- Server starts 1-2 seconds faster thanks to optimizations in Log4j
|
||||
configuration
|
||||
|
||||
Co-Authored-By: Emilia Kond <emilia@rymiel.space>
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index c4572c0a6d9695088613d158838f236fe64efb48..83daf789efc4ce90ff54420e040b783569eb5cab 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -5,9 +5,29 @@ plugins {
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
+val log4jPlugins = sourceSets.create("log4jPlugins")
|
||||
+configurations.named(log4jPlugins.compileClasspathConfigurationName) {
|
||||
+ extendsFrom(configurations.compileClasspath.get())
|
||||
+}
|
||||
+val alsoShade: Configuration by configurations.creating
|
||||
+
|
||||
dependencies {
|
||||
implementation(project(":paper-api"))
|
||||
- implementation("jline:jline:2.12.1")
|
||||
+ // Paper start
|
||||
+ implementation("org.jline:jline-terminal-jansi:3.21.0")
|
||||
+ implementation("net.minecrell:terminalconsoleappender:1.3.0")
|
||||
+ implementation("net.kyori:adventure-text-serializer-ansi:4.17.0") // Keep in sync with adventureVersion from Paper-API build file
|
||||
+ /*
|
||||
+ Required to add the missing Log4j2Plugins.dat file from log4j-core
|
||||
+ which has been removed by Mojang. Without it, log4j has to classload
|
||||
+ all its classes to check if they are plugins.
|
||||
+ Scanning takes about 1-2 seconds so adding this speeds up the server start.
|
||||
+ */
|
||||
+ runtimeOnly("org.apache.logging.log4j:log4j-core:2.19.0")
|
||||
+ log4jPlugins.annotationProcessorConfigurationName("org.apache.logging.log4j:log4j-core:2.19.0") // Paper - Needed to generate meta for our Log4j plugins
|
||||
+ runtimeOnly(log4jPlugins.output)
|
||||
+ alsoShade(log4jPlugins.output)
|
||||
+ // Paper end
|
||||
implementation("org.apache.logging.log4j:log4j-iostreams:2.22.1") // Paper - remove exclusion
|
||||
implementation("org.ow2.asm:asm-commons:9.7.1")
|
||||
implementation("org.spongepowered:configurate-yaml:4.2.0-SNAPSHOT") // Paper - config files
|
||||
@@ -79,6 +99,19 @@ tasks.check {
|
||||
dependsOn(scanJar)
|
||||
}
|
||||
// Paper end
|
||||
+// Paper start - use TCA for console improvements
|
||||
+tasks.serverJar {
|
||||
+ from(alsoShade.elements.map {
|
||||
+ it.map { f ->
|
||||
+ if (f.asFile.isFile) {
|
||||
+ zipTree(f.asFile)
|
||||
+ } else {
|
||||
+ f.asFile
|
||||
+ }
|
||||
+ }
|
||||
+ })
|
||||
+}
|
||||
+// Paper end - use TCA for console improvements
|
||||
|
||||
tasks.test {
|
||||
include("**/**TestSuite.class")
|
||||
diff --git a/src/log4jPlugins/java/io/papermc/paper/console/StripANSIConverter.java b/src/log4jPlugins/java/io/papermc/paper/console/StripANSIConverter.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..91547f6e6fe90006713beb2818da634304bdd236
|
||||
--- /dev/null
|
||||
+++ b/src/log4jPlugins/java/io/papermc/paper/console/StripANSIConverter.java
|
||||
@@ -0,0 +1,51 @@
|
||||
+package io.papermc.paper.console;
|
||||
+
|
||||
+import org.apache.logging.log4j.core.LogEvent;
|
||||
+import org.apache.logging.log4j.core.config.Configuration;
|
||||
+import org.apache.logging.log4j.core.config.plugins.Plugin;
|
||||
+import org.apache.logging.log4j.core.layout.PatternLayout;
|
||||
+import org.apache.logging.log4j.core.pattern.ConverterKeys;
|
||||
+import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
|
||||
+import org.apache.logging.log4j.core.pattern.PatternConverter;
|
||||
+import org.apache.logging.log4j.core.pattern.PatternFormatter;
|
||||
+import org.apache.logging.log4j.core.pattern.PatternParser;
|
||||
+
|
||||
+import java.util.List;
|
||||
+import java.util.regex.Pattern;
|
||||
+
|
||||
+@Plugin(name = "stripAnsi", category = PatternConverter.CATEGORY)
|
||||
+@ConverterKeys({"stripAnsi"})
|
||||
+public final class StripANSIConverter extends LogEventPatternConverter {
|
||||
+ final private Pattern ANSI_PATTERN = Pattern.compile("\\e\\[[\\d;]*[^\\d;]");
|
||||
+
|
||||
+ private final List<PatternFormatter> formatters;
|
||||
+
|
||||
+ private StripANSIConverter(List<PatternFormatter> formatters) {
|
||||
+ super("stripAnsi", null);
|
||||
+ this.formatters = formatters;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void format(LogEvent event, StringBuilder toAppendTo) {
|
||||
+ int start = toAppendTo.length();
|
||||
+ for (PatternFormatter formatter : formatters) {
|
||||
+ formatter.format(event, toAppendTo);
|
||||
+ }
|
||||
+ String content = toAppendTo.substring(start);
|
||||
+ content = ANSI_PATTERN.matcher(content).replaceAll("");
|
||||
+
|
||||
+ toAppendTo.setLength(start);
|
||||
+ toAppendTo.append(content);
|
||||
+ }
|
||||
+
|
||||
+ public static StripANSIConverter newInstance(Configuration config, String[] options) {
|
||||
+ if (options.length != 1) {
|
||||
+ LOGGER.error("Incorrect number of options on stripAnsi. Expected exactly 1, received " + options.length);
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ PatternParser parser = PatternLayout.createPatternParser(config);
|
||||
+ List<PatternFormatter> formatters = parser.parse(options[0]);
|
||||
+ return new StripANSIConverter(formatters);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..a4070b59e261f0f1ac4beec47b11492f4724bf27
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
|
||||
@@ -0,0 +1,41 @@
|
||||
+package com.destroystokyo.paper.console;
|
||||
+
|
||||
+import net.minecraft.server.dedicated.DedicatedServer;
|
||||
+import net.minecrell.terminalconsole.SimpleTerminalConsole;
|
||||
+import org.bukkit.craftbukkit.command.ConsoleCommandCompleter;
|
||||
+import org.jline.reader.LineReader;
|
||||
+import org.jline.reader.LineReaderBuilder;
|
||||
+
|
||||
+public final class PaperConsole extends SimpleTerminalConsole {
|
||||
+
|
||||
+ private final DedicatedServer server;
|
||||
+
|
||||
+ public PaperConsole(DedicatedServer server) {
|
||||
+ this.server = server;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected LineReader buildReader(LineReaderBuilder builder) {
|
||||
+ return super.buildReader(builder
|
||||
+ .appName("Paper")
|
||||
+ .variable(LineReader.HISTORY_FILE, java.nio.file.Paths.get(".console_history"))
|
||||
+ .completer(new ConsoleCommandCompleter(this.server))
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected boolean isRunning() {
|
||||
+ return !this.server.isStopped() && this.server.isRunning();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void runCommand(String command) {
|
||||
+ this.server.handleConsoleInput(command, this.server.createCommandSourceStack());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void shutdown() {
|
||||
+ this.server.halt(false);
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java b/src/main/java/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..8f07539a82f449ad217e316a7513a1708781fb63
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java
|
||||
@@ -0,0 +1,26 @@
|
||||
+package com.destroystokyo.paper.console;
|
||||
+
|
||||
+import net.kyori.adventure.audience.MessageType;
|
||||
+import net.kyori.adventure.identity.Identity;
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
||||
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
+import org.apache.logging.log4j.LogManager;
|
||||
+import org.bukkit.craftbukkit.command.CraftConsoleCommandSender;
|
||||
+
|
||||
+public class TerminalConsoleCommandSender extends CraftConsoleCommandSender {
|
||||
+
|
||||
+ private static final ComponentLogger LOGGER = ComponentLogger.logger(LogManager.getRootLogger().getName());
|
||||
+
|
||||
+ @Override
|
||||
+ public void sendRawMessage(String message) {
|
||||
+ final Component msg = LegacyComponentSerializer.legacySection().deserialize(message);
|
||||
+ this.sendMessage(Identity.nil(), msg, MessageType.SYSTEM);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void sendMessage(Identity identity, Component message, MessageType type) {
|
||||
+ LOGGER.info(message);
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/adventure/PaperAdventure.java b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java
|
||||
index dc4837c577676115f0653acc35f55962a432e425..22fe529890f34f66534c01248f654dc911b44c3b 100644
|
||||
--- a/src/main/java/io/papermc/paper/adventure/PaperAdventure.java
|
||||
+++ b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java
|
||||
@@ -32,6 +32,7 @@ import net.kyori.adventure.text.flattener.ComponentFlattener;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.serializer.ComponentSerializer;
|
||||
+import net.kyori.adventure.text.serializer.ansi.ANSIComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
@@ -129,6 +130,7 @@ public final class PaperAdventure {
|
||||
public static final AttributeKey<Locale> LOCALE_ATTRIBUTE = AttributeKey.valueOf("adventure:locale"); // init after FLATTENER because classloading triggered here might create a logger
|
||||
@Deprecated
|
||||
public static final PlainComponentSerializer PLAIN = PlainComponentSerializer.builder().flattener(FLATTENER).build();
|
||||
+ public static final ANSIComponentSerializer ANSI_SERIALIZER = ANSIComponentSerializer.builder().flattener(FLATTENER).build();
|
||||
public static final Codec<Tag, String, CommandSyntaxException, RuntimeException> NBT_CODEC = new Codec<>() {
|
||||
@Override
|
||||
public @NotNull Tag decode(final @NotNull String encoded) throws CommandSyntaxException {
|
||||
diff --git a/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java b/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java
|
||||
index 8323f135d6bf2e1f12525e05094ffa3f2420e7e1..a143ea1e58464a3122fbd8ccafe417bdb3c31c78 100644
|
||||
--- a/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java
|
||||
+++ b/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java
|
||||
@@ -1,9 +1,11 @@
|
||||
package io.papermc.paper.adventure.providers;
|
||||
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
+import java.util.Locale;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
||||
import net.kyori.adventure.text.logger.slf4j.ComponentLoggerProvider;
|
||||
+import net.kyori.adventure.translation.GlobalTranslator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -15,6 +17,6 @@ public class ComponentLoggerProviderImpl implements ComponentLoggerProvider {
|
||||
}
|
||||
|
||||
private String serialize(final Component message) {
|
||||
- return PaperAdventure.asPlain(message, null);
|
||||
+ return PaperAdventure.ANSI_SERIALIZER.serialize(GlobalTranslator.render(message, Locale.getDefault()));
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 387552877ac82baa3af0da723dbb7c331fad6cf4..b334cfc9b98d96f9bfba1d5b14c03c336d30ff23 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -154,7 +154,7 @@ import com.mojang.serialization.Dynamic;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import java.io.File;
|
||||
import java.util.Random;
|
||||
-import jline.console.ConsoleReader;
|
||||
+// import jline.console.ConsoleReader; // Paper
|
||||
import joptsimple.OptionSet;
|
||||
import net.minecraft.nbt.NbtException;
|
||||
import net.minecraft.nbt.ReportedNbtException;
|
||||
@@ -296,7 +296,6 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public org.bukkit.craftbukkit.CraftServer server;
|
||||
public OptionSet options;
|
||||
public org.bukkit.command.ConsoleCommandSender console;
|
||||
- public ConsoleReader reader;
|
||||
public static int currentTick = (int) (System.currentTimeMillis() / 50);
|
||||
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
|
||||
public int autosavePeriod;
|
||||
@@ -383,7 +382,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.options = options;
|
||||
this.worldLoader = worldLoader;
|
||||
this.vanillaCommandDispatcher = worldstem.dataPackResources().commands; // CraftBukkit
|
||||
+ // Paper start - Handled by TerminalConsoleAppender
|
||||
// Try to see if we're actually running in a terminal, disable jline if not
|
||||
+ /*
|
||||
if (System.console() == null && System.getProperty("jline.terminal") == null) {
|
||||
System.setProperty("jline.terminal", "jline.UnsupportedTerminal");
|
||||
Main.useJline = false;
|
||||
@@ -404,6 +405,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
MinecraftServer.LOGGER.warn((String) null, ex);
|
||||
}
|
||||
}
|
||||
+ */
|
||||
+ // Paper end
|
||||
Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this));
|
||||
// CraftBukkit end
|
||||
this.paperConfigurations = services.paperConfigurations(); // Paper - add paper configuration files
|
||||
@@ -1118,7 +1121,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
org.spigotmc.WatchdogThread.doStop(); // Spigot
|
||||
// CraftBukkit start - Restore terminal to original settings
|
||||
try {
|
||||
- this.reader.getTerminal().restore();
|
||||
+ net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
// CraftBukkit end
|
||||
@@ -1656,7 +1659,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
@Override
|
||||
public void sendSystemMessage(Component message) {
|
||||
- MinecraftServer.LOGGER.info(message.getString());
|
||||
+ MinecraftServer.LOGGER.info(io.papermc.paper.adventure.PaperAdventure.ANSI_SERIALIZER.serialize(io.papermc.paper.adventure.PaperAdventure.asAdventure(message))); // Paper - Log message with colors
|
||||
}
|
||||
|
||||
public KeyPair getKeyPair() {
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index cd26616aba6abd44abc5eb8b01cc96f29248aecd..b41eb920b5665b7a1b7cd9f38955c31eeb350847 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -112,6 +112,9 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
if (!org.bukkit.craftbukkit.Main.useConsole) {
|
||||
return;
|
||||
}
|
||||
+ // Paper start - Use TerminalConsoleAppender
|
||||
+ new com.destroystokyo.paper.console.PaperConsole(DedicatedServer.this).start();
|
||||
+ /*
|
||||
jline.console.ConsoleReader bufferedreader = DedicatedServer.this.reader;
|
||||
|
||||
// MC-33041, SPIGOT-5538: if System.in is not valid due to javaw, then return
|
||||
@@ -143,7 +146,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
continue;
|
||||
}
|
||||
if (s.trim().length() > 0) { // Trim to filter lines which are just spaces
|
||||
- DedicatedServer.this.handleConsoleInput(s, DedicatedServer.this.createCommandSourceStack());
|
||||
+ DedicatedServer.this.issueCommand(s, DedicatedServer.this.getServerCommandListener());
|
||||
}
|
||||
// CraftBukkit end
|
||||
}
|
||||
@@ -151,6 +154,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
DedicatedServer.LOGGER.error("Exception handling console input", ioexception);
|
||||
}
|
||||
|
||||
+ */
|
||||
+ // Paper end
|
||||
}
|
||||
};
|
||||
|
||||
@@ -162,6 +167,9 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
}
|
||||
global.addHandler(new org.bukkit.craftbukkit.util.ForwardLogHandler());
|
||||
|
||||
+ // Paper start - Not needed with TerminalConsoleAppender
|
||||
+ final org.apache.logging.log4j.Logger logger = LogManager.getRootLogger();
|
||||
+ /*
|
||||
final org.apache.logging.log4j.core.Logger logger = ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger());
|
||||
for (org.apache.logging.log4j.core.Appender appender : logger.getAppenders().values()) {
|
||||
if (appender instanceof org.apache.logging.log4j.core.appender.ConsoleAppender) {
|
||||
@@ -172,6 +180,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
TerminalConsoleWriterThread writerThread = new TerminalConsoleWriterThread(System.out, this.reader);
|
||||
this.reader.setCompletionHandler(new TerminalCompletionHandler(writerThread, this.reader.getCompletionHandler()));
|
||||
writerThread.start();
|
||||
+ */
|
||||
+ // Paper end - Not needed with TerminalConsoleAppender
|
||||
|
||||
System.setOut(IoBuilder.forLogger(logger).setLevel(Level.INFO).buildPrintStream());
|
||||
System.setErr(IoBuilder.forLogger(logger).setLevel(Level.WARN).buildPrintStream());
|
||||
diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
||||
index 3d92c61f7781221cfdc0324d11bd0088954e4a68..84a2c6c397604279ba821286f5c3c855e6041400 100644
|
||||
--- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
||||
+++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
||||
@@ -166,7 +166,7 @@ public class MinecraftServerGui extends JComponent {
|
||||
this.finalizers.forEach(Runnable::run);
|
||||
}
|
||||
|
||||
- private static final java.util.regex.Pattern ANSI = java.util.regex.Pattern.compile("\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})*)?[m|K]"); // CraftBukkit
|
||||
+ private static final java.util.regex.Pattern ANSI = java.util.regex.Pattern.compile("\\e\\[[\\d;]*[^\\d;]"); // CraftBukkit // Paper
|
||||
public void print(JTextArea textArea, JScrollPane scrollPane, String message) {
|
||||
if (!SwingUtilities.isEventDispatchThread()) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index e9109526880159e2341cc97b53939ba2bcfaeaf9..9dcfcea63f57f45a5584bb80c34fe445d65849e8 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -161,8 +161,7 @@ public abstract class PlayerList {
|
||||
|
||||
public PlayerList(MinecraftServer server, LayeredRegistryAccess<RegistryLayer> registryManager, PlayerDataStorage saveHandler, int maxPlayers) {
|
||||
this.cserver = server.server = new CraftServer((DedicatedServer) server, this);
|
||||
- server.console = org.bukkit.craftbukkit.command.ColouredConsoleSender.getInstance();
|
||||
- server.reader.addCompleter(new org.bukkit.craftbukkit.command.ConsoleCommandCompleter(server.server));
|
||||
+ server.console = new com.destroystokyo.paper.console.TerminalConsoleCommandSender(); // Paper
|
||||
// CraftBukkit end
|
||||
|
||||
this.bans = new UserBanList(PlayerList.USERBANLIST_FILE);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 9f7634053ddfc4fc67f89cc99524e9ebd6096f46..752933ceabd7ebe7b1e9f7d41198128f6f2182a6 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -43,7 +43,7 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.imageio.ImageIO;
|
||||
-import jline.console.ConsoleReader;
|
||||
+// import jline.console.ConsoleReader;
|
||||
import net.minecraft.advancements.AdvancementHolder;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
@@ -1356,9 +1356,13 @@ public final class CraftServer implements Server {
|
||||
return this.logger;
|
||||
}
|
||||
|
||||
+ // Paper start - JLine update
|
||||
+ /*
|
||||
public ConsoleReader getReader() {
|
||||
return this.console.reader;
|
||||
}
|
||||
+ */
|
||||
+ // Paper end
|
||||
|
||||
@Override
|
||||
public PluginCommand getPluginCommand(String name) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index 3b0370256b4d8c96053b340a657c6bcc6be6c9de..bdb8e882ec1efbe5afec9ec5a5df57bf38d4ba2b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -13,7 +13,6 @@ import java.util.logging.Logger;
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.util.PathConverter;
|
||||
-import org.fusesource.jansi.AnsiConsole;
|
||||
|
||||
public class Main {
|
||||
public static boolean useJline = true;
|
||||
@@ -196,6 +195,8 @@ public class Main {
|
||||
}
|
||||
|
||||
try {
|
||||
+ // Paper start - Handled by TerminalConsoleAppender
|
||||
+ /*
|
||||
// This trick bypasses Maven Shade's clever rewriting of our getProperty call when using String literals
|
||||
String jline_UnsupportedTerminal = new String(new char[]{'j', 'l', 'i', 'n', 'e', '.', 'U', 'n', 's', 'u', 'p', 'p', 'o', 'r', 't', 'e', 'd', 'T', 'e', 'r', 'm', 'i', 'n', 'a', 'l'});
|
||||
String jline_terminal = new String(new char[]{'j', 'l', 'i', 'n', 'e', '.', 't', 'e', 'r', 'm', 'i', 'n', 'a', 'l'});
|
||||
@@ -213,9 +214,18 @@ public class Main {
|
||||
// This ensures the terminal literal will always match the jline implementation
|
||||
System.setProperty(jline.TerminalFactory.JLINE_TERMINAL, jline.UnsupportedTerminal.class.getName());
|
||||
}
|
||||
+ */
|
||||
+
|
||||
+ if (options.has("nojline")) {
|
||||
+ System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false");
|
||||
+ useJline = false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
if (options.has("noconsole")) {
|
||||
Main.useConsole = false;
|
||||
+ useJline = false; // Paper
|
||||
+ System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper
|
||||
}
|
||||
|
||||
if (Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) {
|
||||
@@ -231,6 +241,7 @@ public class Main {
|
||||
}
|
||||
}
|
||||
|
||||
+ System.setProperty("library.jansi.version", "Paper"); // Paper - set meaningless jansi version to prevent git builds from crashing on Windows
|
||||
System.out.println("Loading libraries, please wait...");
|
||||
net.minecraft.server.Main.main(options);
|
||||
} catch (Throwable t) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/command/ColouredConsoleSender.java b/src/main/java/org/bukkit/craftbukkit/command/ColouredConsoleSender.java
|
||||
index bcf1c36d07b79520a39643d3a01020a67b1c9ef2..217e7e3b9db04c7fc5f6518f39cc9d3488f9128d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/ColouredConsoleSender.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/ColouredConsoleSender.java
|
||||
@@ -5,15 +5,13 @@ import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
-import jline.Terminal;
|
||||
+//import jline.Terminal;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
-import org.fusesource.jansi.Ansi;
|
||||
-import org.fusesource.jansi.Ansi.Attribute;
|
||||
|
||||
-public class ColouredConsoleSender extends CraftConsoleCommandSender {
|
||||
+public class ColouredConsoleSender /*extends CraftConsoleCommandSender */{/* // Paper - disable
|
||||
private final Terminal terminal;
|
||||
private final Map<ChatColor, String> replacements = new EnumMap<ChatColor, String>(ChatColor.class);
|
||||
private final ChatColor[] colors = ChatColor.values();
|
||||
@@ -93,5 +91,5 @@ public class ColouredConsoleSender extends CraftConsoleCommandSender {
|
||||
} else {
|
||||
return new ColouredConsoleSender();
|
||||
}
|
||||
- }
|
||||
+ }*/ // Paper
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
||||
index 0b4c62387c1093652ac15b64a8703249de4cf088..0b27172073530617a6e0b2b83fe1e9d231653b8d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
||||
@@ -4,50 +4,73 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
-import jline.console.completer.Completer;
|
||||
+import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.craftbukkit.util.Waitable;
|
||||
+
|
||||
+// Paper start - JLine update
|
||||
+import org.jline.reader.Candidate;
|
||||
+import org.jline.reader.Completer;
|
||||
+import org.jline.reader.LineReader;
|
||||
+import org.jline.reader.ParsedLine;
|
||||
+// Paper end
|
||||
import org.bukkit.event.server.TabCompleteEvent;
|
||||
|
||||
public class ConsoleCommandCompleter implements Completer {
|
||||
- private final CraftServer server;
|
||||
+ private final DedicatedServer server; // Paper - CraftServer -> DedicatedServer
|
||||
|
||||
- public ConsoleCommandCompleter(CraftServer server) {
|
||||
+ public ConsoleCommandCompleter(DedicatedServer server) { // Paper - CraftServer -> DedicatedServer
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
+ // Paper start - Change method signature for JLine update
|
||||
@Override
|
||||
- public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
|
||||
+ public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
|
||||
+ final CraftServer server = this.server.server;
|
||||
+ final String buffer = "/" + line.line();
|
||||
+ // Paper end
|
||||
Waitable<List<String>> waitable = new Waitable<List<String>>() {
|
||||
@Override
|
||||
protected List<String> evaluate() {
|
||||
- List<String> offers = ConsoleCommandCompleter.this.server.getCommandMap().tabComplete(ConsoleCommandCompleter.this.server.getConsoleSender(), buffer);
|
||||
+ List<String> offers = server.getCommandMap().tabComplete(server.getConsoleSender(), buffer); // Paper - Remove "this."
|
||||
|
||||
- TabCompleteEvent tabEvent = new TabCompleteEvent(ConsoleCommandCompleter.this.server.getConsoleSender(), buffer, (offers == null) ? Collections.EMPTY_LIST : offers);
|
||||
- ConsoleCommandCompleter.this.server.getPluginManager().callEvent(tabEvent);
|
||||
+ TabCompleteEvent tabEvent = new TabCompleteEvent(server.getConsoleSender(), buffer, (offers == null) ? Collections.EMPTY_LIST : offers); // Paper - Remove "this."
|
||||
+ server.getPluginManager().callEvent(tabEvent); // Paper - Remove "this."
|
||||
|
||||
return tabEvent.isCancelled() ? Collections.EMPTY_LIST : tabEvent.getCompletions();
|
||||
}
|
||||
};
|
||||
- this.server.getServer().processQueue.add(waitable);
|
||||
+ server.getServer().processQueue.add(waitable); // Paper - Remove "this."
|
||||
try {
|
||||
List<String> offers = waitable.get();
|
||||
if (offers == null) {
|
||||
- return cursor;
|
||||
+ return; // Paper - Method returns void
|
||||
+ }
|
||||
+
|
||||
+ // Paper start - JLine update
|
||||
+ for (String completion : offers) {
|
||||
+ if (completion.isEmpty()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ candidates.add(new Candidate(completion));
|
||||
}
|
||||
- candidates.addAll(offers);
|
||||
+ // Paper end
|
||||
|
||||
+ // Paper start - JLine handles cursor now
|
||||
+ /*
|
||||
final int lastSpace = buffer.lastIndexOf(' ');
|
||||
if (lastSpace == -1) {
|
||||
return cursor - buffer.length();
|
||||
} else {
|
||||
return cursor - (buffer.length() - lastSpace - 1);
|
||||
}
|
||||
+ */
|
||||
+ // Paper end
|
||||
} catch (ExecutionException e) {
|
||||
- this.server.getLogger().log(Level.WARNING, "Unhandled exception when tab completing", e);
|
||||
+ server.getLogger().log(Level.WARNING, "Unhandled exception when tab completing", e); // Paper - Remove "this."
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
- return cursor;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
index 8390f5b5b957b5435efece26507a89756d0a7b3c..c6e8441e299f477ddb22c1ce2618710763978f1a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
@@ -16,7 +16,7 @@ public class ServerShutdownThread extends Thread {
|
||||
this.server.close();
|
||||
} finally {
|
||||
try {
|
||||
- this.server.reader.getTerminal().restore();
|
||||
+ net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/TerminalCompletionHandler.java b/src/main/java/org/bukkit/craftbukkit/util/TerminalCompletionHandler.java
|
||||
index 7d1c0810181c51ffa64f9a23b251e05c789870b0..09804513265e6db0c1f3501355335551100a36a8 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/TerminalCompletionHandler.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/TerminalCompletionHandler.java
|
||||
@@ -4,14 +4,12 @@ import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
-import jline.console.ConsoleReader;
|
||||
-import jline.console.completer.CompletionHandler;
|
||||
|
||||
/**
|
||||
* SPIGOT-6705: Make sure we print the display line again on tab completion, so that the user does not get stuck on it
|
||||
* e.g. The user needs to press y / n to continue
|
||||
*/
|
||||
-public class TerminalCompletionHandler implements CompletionHandler {
|
||||
+public class TerminalCompletionHandler /* implements CompletionHandler */ { /* Paper - comment out whole class
|
||||
|
||||
private final TerminalConsoleWriterThread writerThread;
|
||||
private final CompletionHandler delegate;
|
||||
@@ -50,4 +48,5 @@ public class TerminalCompletionHandler implements CompletionHandler {
|
||||
|
||||
return result;
|
||||
}
|
||||
+*/ // Paper end - comment out whole class
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleWriterThread.java b/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleWriterThread.java
|
||||
index 2e5101fca081548bb616bc5eaa0134698719b63a..6e4d50a4863d43a2d6a2d574350c74d0819df402 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleWriterThread.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleWriterThread.java
|
||||
@@ -7,13 +7,9 @@ import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
-import jline.console.ConsoleReader;
|
||||
-import jline.console.completer.CandidateListCompletionHandler;
|
||||
import org.bukkit.craftbukkit.Main;
|
||||
-import org.fusesource.jansi.Ansi;
|
||||
-import org.fusesource.jansi.Ansi.Erase;
|
||||
|
||||
-public class TerminalConsoleWriterThread extends Thread {
|
||||
+public class TerminalConsoleWriterThread /*extends Thread*/ {/* // Paper - Comment out entire class
|
||||
private final ResourceBundle bundle = ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName(), Locale.getDefault());
|
||||
private final ConsoleReader reader;
|
||||
private final OutputStream output;
|
||||
@@ -70,4 +66,5 @@ public class TerminalConsoleWriterThread extends Thread {
|
||||
void setCompletion(int completion) {
|
||||
this.completion = completion;
|
||||
}
|
||||
+*/ // Paper - Comment out entire class
|
||||
}
|
||||
diff --git a/src/main/resources/log4j2.component.properties b/src/main/resources/log4j2.component.properties
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0694b21465fb9e4164e71862ff24b62241b191f2
|
||||
--- /dev/null
|
||||
+++ b/src/main/resources/log4j2.component.properties
|
||||
@@ -0,0 +1 @@
|
||||
+log4j.skipJansi=true
|
||||
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
|
||||
index 0ff3f750fb7f684c12080894cd8660f0455c658b..301874c1fe16c52ffa6228d79e6617d746e9a035 100644
|
||||
--- a/src/main/resources/log4j2.xml
|
||||
+++ b/src/main/resources/log4j2.xml
|
||||
@@ -1,17 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="WARN">
|
||||
<Appenders>
|
||||
- <Console name="SysOut" target="SYSTEM_OUT">
|
||||
- <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg{nolookups}%n" />
|
||||
- </Console>
|
||||
<Queue name="ServerGuiConsole">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg{nolookups}%n" />
|
||||
</Queue>
|
||||
- <Queue name="TerminalConsole">
|
||||
- <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg{nolookups}%n" />
|
||||
- </Queue>
|
||||
+ <TerminalConsole name="TerminalConsole">
|
||||
+ <PatternLayout pattern="%highlightError{[%d{HH:mm:ss} %level]: %msg%n%xEx}" />
|
||||
+ </TerminalConsole>
|
||||
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
|
||||
- <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg{nolookups}%n" />
|
||||
+ <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %stripAnsi{%msg}%n" />
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy />
|
||||
<OnStartupTriggeringPolicy />
|
||||
@@ -24,10 +21,9 @@
|
||||
<filters>
|
||||
<MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL" />
|
||||
</filters>
|
||||
- <AppenderRef ref="SysOut" level="info"/>
|
||||
<AppenderRef ref="File"/>
|
||||
- <AppenderRef ref="ServerGuiConsole" level="info"/>
|
||||
<AppenderRef ref="TerminalConsole" level="info"/>
|
||||
+ <AppenderRef ref="ServerGuiConsole" level="info"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
|
@ -1,71 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Minecrell <minecrell@minecrell.net>
|
||||
Date: Thu, 21 Sep 2017 16:14:55 +0200
|
||||
Subject: [PATCH] Handle plugin prefixes using Log4J configuration
|
||||
|
||||
Display logger name in the console for all loggers except the
|
||||
root logger, Bukkit's logger ("Minecraft") and Minecraft loggers.
|
||||
Since plugins now use the plugin name as logger name this will
|
||||
restore the plugin prefixes without having to prepend them manually
|
||||
to the log messages.
|
||||
|
||||
Logger prefixes are shown by default for all loggers except for
|
||||
the root logger, the Minecraft/Mojang loggers and the Bukkit loggers.
|
||||
This may cause additional prefixes to be disabled for plugins bypassing
|
||||
the plugin logger.
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index 0a05e753ff5e7b1d741c7719524715d7364cac4f..d82d1e90cbda544b3d20edcc13d1cb955c48f731 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -23,7 +23,7 @@ dependencies {
|
||||
all its classes to check if they are plugins.
|
||||
Scanning takes about 1-2 seconds so adding this speeds up the server start.
|
||||
*/
|
||||
- runtimeOnly("org.apache.logging.log4j:log4j-core:2.19.0")
|
||||
+ implementation("org.apache.logging.log4j:log4j-core:2.19.0") // Paper - implementation
|
||||
log4jPlugins.annotationProcessorConfigurationName("org.apache.logging.log4j:log4j-core:2.19.0") // Paper - Needed to generate meta for our Log4j plugins
|
||||
runtimeOnly(log4jPlugins.output)
|
||||
alsoShade(log4jPlugins.output)
|
||||
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
|
||||
index e42677a14ec8e1a42747603fb4112822e326fb70..744edd40128c910c3ad2f3657bde995612e0a1e4 100644
|
||||
--- a/src/main/java/org/spigotmc/SpigotConfig.java
|
||||
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
|
||||
@@ -284,7 +284,7 @@ public class SpigotConfig
|
||||
private static void playerSample()
|
||||
{
|
||||
SpigotConfig.playerSample = SpigotConfig.getInt( "settings.sample-count", 12 );
|
||||
- System.out.println( "Server Ping Player Sample Count: " + SpigotConfig.playerSample );
|
||||
+ Bukkit.getLogger().log( Level.INFO, "Server Ping Player Sample Count: {0}", playerSample ); // Paper - Use logger
|
||||
}
|
||||
|
||||
public static int playerShuffle;
|
||||
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
|
||||
index 301874c1fe16c52ffa6228d79e6617d746e9a035..e073707a46397f62bedf1d413f9e5764e77dda6a 100644
|
||||
--- a/src/main/resources/log4j2.xml
|
||||
+++ b/src/main/resources/log4j2.xml
|
||||
@@ -5,10 +5,22 @@
|
||||
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg{nolookups}%n" />
|
||||
</Queue>
|
||||
<TerminalConsole name="TerminalConsole">
|
||||
- <PatternLayout pattern="%highlightError{[%d{HH:mm:ss} %level]: %msg%n%xEx}" />
|
||||
+ <PatternLayout>
|
||||
+ <LoggerNamePatternSelector defaultPattern="%highlightError{[%d{HH:mm:ss} %level]: [%logger] %msg%n%xEx}">
|
||||
+ <!-- Log root, Minecraft, Mojang and Bukkit loggers without prefix -->
|
||||
+ <PatternMatch key=",net.minecraft.,Minecraft,com.mojang."
|
||||
+ pattern="%highlightError{[%d{HH:mm:ss} %level]: %msg%n%xEx}" />
|
||||
+ </LoggerNamePatternSelector>
|
||||
+ </PatternLayout>
|
||||
</TerminalConsole>
|
||||
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
|
||||
- <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %stripAnsi{%msg}%n" />
|
||||
+ <PatternLayout>
|
||||
+ <LoggerNamePatternSelector defaultPattern="[%d{HH:mm:ss}] [%t/%level]: [%logger] %stripAnsi{%msg}%n">
|
||||
+ <!-- Log root, Minecraft, Mojang and Bukkit loggers without prefix -->
|
||||
+ <PatternMatch key=",net.minecraft.,Minecraft,com.mojang."
|
||||
+ pattern="[%d{HH:mm:ss}] [%t/%level]: %stripAnsi{%msg}%n" />
|
||||
+ </LoggerNamePatternSelector>
|
||||
+ </PatternLayout>
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy />
|
||||
<OnStartupTriggeringPolicy />
|
|
@ -1,47 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Minecrell <minecrell@minecrell.net>
|
||||
Date: Sat, 23 Sep 2017 21:07:20 +0200
|
||||
Subject: [PATCH] Improve Log4J Configuration / Plugin Loggers
|
||||
|
||||
Add full exceptions to log4j to not truncate stack traces
|
||||
|
||||
Disable logger prefix for various plugins bypassing the plugin logger
|
||||
|
||||
Some plugins bypass the plugin logger and add the plugin prefix
|
||||
manually to the log message. Since they use other logger names
|
||||
(e.g. qualified class names) these would now also appear in the
|
||||
log. Disable the logger prefix for these plugins so the messages
|
||||
show up correctly.
|
||||
|
||||
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
|
||||
index e073707a46397f62bedf1d413f9e5764e77dda6a..ab1caec640128aa90f246e4bbecf5ca275e7982e 100644
|
||||
--- a/src/main/resources/log4j2.xml
|
||||
+++ b/src/main/resources/log4j2.xml
|
||||
@@ -6,19 +6,21 @@
|
||||
</Queue>
|
||||
<TerminalConsole name="TerminalConsole">
|
||||
<PatternLayout>
|
||||
- <LoggerNamePatternSelector defaultPattern="%highlightError{[%d{HH:mm:ss} %level]: [%logger] %msg%n%xEx}">
|
||||
+ <LoggerNamePatternSelector defaultPattern="%highlightError{[%d{HH:mm:ss} %level]: [%logger] %msg%n%xEx{full}}">
|
||||
<!-- Log root, Minecraft, Mojang and Bukkit loggers without prefix -->
|
||||
- <PatternMatch key=",net.minecraft.,Minecraft,com.mojang."
|
||||
- pattern="%highlightError{[%d{HH:mm:ss} %level]: %msg%n%xEx}" />
|
||||
+ <!-- Disable prefix for various plugins that bypass the plugin logger -->
|
||||
+ <PatternMatch key=",net.minecraft.,Minecraft,com.mojang.,com.sk89q.,ru.tehkode.,Minecraft.AWE"
|
||||
+ pattern="%highlightError{[%d{HH:mm:ss} %level]: %msg%n%xEx{full}}" />
|
||||
</LoggerNamePatternSelector>
|
||||
</PatternLayout>
|
||||
</TerminalConsole>
|
||||
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
|
||||
<PatternLayout>
|
||||
- <LoggerNamePatternSelector defaultPattern="[%d{HH:mm:ss}] [%t/%level]: [%logger] %stripAnsi{%msg}%n">
|
||||
+ <LoggerNamePatternSelector defaultPattern="[%d{HH:mm:ss}] [%t/%level]: [%logger] %stripAnsi{%msg}%n%xEx{full}">
|
||||
<!-- Log root, Minecraft, Mojang and Bukkit loggers without prefix -->
|
||||
- <PatternMatch key=",net.minecraft.,Minecraft,com.mojang."
|
||||
- pattern="[%d{HH:mm:ss}] [%t/%level]: %stripAnsi{%msg}%n" />
|
||||
+ <!-- Disable prefix for various plugins that bypass the plugin logger -->
|
||||
+ <PatternMatch key=",net.minecraft.,Minecraft,com.mojang.,com.sk89q.,ru.tehkode.,Minecraft.AWE"
|
||||
+ pattern="[%d{HH:mm:ss}] [%t/%level]: %stripAnsi{%msg}%n%xEx{full}" />
|
||||
</LoggerNamePatternSelector>
|
||||
</PatternLayout>
|
||||
<Policies>
|
|
@ -1,44 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Thu, 12 Aug 2021 04:46:41 -0700
|
||||
Subject: [PATCH] Use AsyncAppender to keep logging IO off main thread
|
||||
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index d82d1e90cbda544b3d20edcc13d1cb955c48f731..3bd5c2a2add9b462523beb9dfaf2eb5a00d470b9 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -34,6 +34,7 @@ dependencies {
|
||||
implementation("commons-lang:commons-lang:2.6")
|
||||
runtimeOnly("org.xerial:sqlite-jdbc:3.46.0.0")
|
||||
runtimeOnly("com.mysql:mysql-connector-j:8.4.0")
|
||||
+ runtimeOnly("com.lmax:disruptor:3.4.4") // Paper
|
||||
|
||||
runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.6")
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18")
|
||||
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
|
||||
index ab1caec640128aa90f246e4bbecf5ca275e7982e..18e961a37b2830da6e5dab7aa35116b2f5215898 100644
|
||||
--- a/src/main/resources/log4j2.xml
|
||||
+++ b/src/main/resources/log4j2.xml
|
||||
@@ -29,15 +29,18 @@
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="1000"/>
|
||||
</RollingRandomAccessFile>
|
||||
+ <Async name="Async">
|
||||
+ <AppenderRef ref="File"/>
|
||||
+ <AppenderRef ref="TerminalConsole" level="info"/>
|
||||
+ <AppenderRef ref="ServerGuiConsole" level="info"/>
|
||||
+ </Async>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="info">
|
||||
<filters>
|
||||
<MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL" />
|
||||
</filters>
|
||||
- <AppenderRef ref="File"/>
|
||||
- <AppenderRef ref="TerminalConsole" level="info"/>
|
||||
- <AppenderRef ref="ServerGuiConsole" level="info"/>
|
||||
+ <AppenderRef ref="Async"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
|
@ -1,581 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Sun, 20 Jun 2021 18:19:09 -0700
|
||||
Subject: [PATCH] Deobfuscate stacktraces in log messages, crash reports, and
|
||||
etc.
|
||||
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index 7c81605648c6ba1360936faae25ef5fc11f0bcb4..4838ca75b9536ce5fd30906b51bdab86789668ec 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -46,6 +46,7 @@ dependencies {
|
||||
testImplementation("org.mockito:mockito-core:5.14.1")
|
||||
testImplementation("org.ow2.asm:asm-tree:9.7.1")
|
||||
testImplementation("org.junit-pioneer:junit-pioneer:2.2.0") // Paper - CartesianTest
|
||||
+ implementation("net.neoforged:srgutils:1.0.9") // Paper - mappings handling
|
||||
}
|
||||
|
||||
paperweight {
|
||||
diff --git a/src/log4jPlugins/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java b/src/log4jPlugins/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..66b6011ee3684695b2ab9292961c80bf2a420ee9
|
||||
--- /dev/null
|
||||
+++ b/src/log4jPlugins/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java
|
||||
@@ -0,0 +1,66 @@
|
||||
+package io.papermc.paper.logging;
|
||||
+
|
||||
+import java.lang.invoke.MethodHandle;
|
||||
+import java.lang.invoke.MethodHandles;
|
||||
+import java.lang.invoke.VarHandle;
|
||||
+import org.apache.logging.log4j.core.Core;
|
||||
+import org.apache.logging.log4j.core.LogEvent;
|
||||
+import org.apache.logging.log4j.core.appender.rewrite.RewritePolicy;
|
||||
+import org.apache.logging.log4j.core.config.plugins.Plugin;
|
||||
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
|
||||
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+
|
||||
+@Plugin(
|
||||
+ name = "StacktraceDeobfuscatingRewritePolicy",
|
||||
+ category = Core.CATEGORY_NAME,
|
||||
+ elementType = "rewritePolicy",
|
||||
+ printObject = true
|
||||
+)
|
||||
+public final class StacktraceDeobfuscatingRewritePolicy implements RewritePolicy {
|
||||
+ private static final MethodHandle DEOBFUSCATE_THROWABLE;
|
||||
+
|
||||
+ static {
|
||||
+ try {
|
||||
+ final Class<?> cls = Class.forName("io.papermc.paper.util.StacktraceDeobfuscator");
|
||||
+ final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
+ final VarHandle instanceHandle = lookup.findStaticVarHandle(cls, "INSTANCE", cls);
|
||||
+ final Object deobfuscator = instanceHandle.get();
|
||||
+ DEOBFUSCATE_THROWABLE = lookup
|
||||
+ .unreflect(cls.getDeclaredMethod("deobfuscateThrowable", Throwable.class))
|
||||
+ .bindTo(deobfuscator);
|
||||
+ } catch (final ReflectiveOperationException ex) {
|
||||
+ throw new IllegalStateException(ex);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private StacktraceDeobfuscatingRewritePolicy() {
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NonNull LogEvent rewrite(final @NonNull LogEvent rewrite) {
|
||||
+ final Throwable thrown = rewrite.getThrown();
|
||||
+ if (thrown != null) {
|
||||
+ deobfuscateThrowable(thrown);
|
||||
+ return new Log4jLogEvent.Builder(rewrite)
|
||||
+ .setThrownProxy(null)
|
||||
+ .build();
|
||||
+ }
|
||||
+ return rewrite;
|
||||
+ }
|
||||
+
|
||||
+ private static void deobfuscateThrowable(final Throwable thrown) {
|
||||
+ try {
|
||||
+ DEOBFUSCATE_THROWABLE.invoke(thrown);
|
||||
+ } catch (final Error e) {
|
||||
+ throw e;
|
||||
+ } catch (final Throwable e) {
|
||||
+ throw new RuntimeException(e);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @PluginFactory
|
||||
+ public static @NonNull StacktraceDeobfuscatingRewritePolicy createPolicy() {
|
||||
+ return new StacktraceDeobfuscatingRewritePolicy();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/util/ObfHelper.java b/src/main/java/io/papermc/paper/util/ObfHelper.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..9e6d48335b37fa5204bfebf396d748089884555b
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/ObfHelper.java
|
||||
@@ -0,0 +1,156 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import java.io.IOException;
|
||||
+import java.io.InputStream;
|
||||
+import java.util.HashMap;
|
||||
+import java.util.HashSet;
|
||||
+import java.util.Map;
|
||||
+import java.util.Objects;
|
||||
+import java.util.Set;
|
||||
+import java.util.stream.Collectors;
|
||||
+import net.neoforged.srgutils.IMappingFile;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public enum ObfHelper {
|
||||
+ INSTANCE;
|
||||
+
|
||||
+ private final @Nullable Map<String, ClassMapping> mappingsByObfName;
|
||||
+ private final @Nullable Map<String, ClassMapping> mappingsByMojangName;
|
||||
+
|
||||
+ ObfHelper() {
|
||||
+ final @Nullable Set<ClassMapping> maps = loadMappingsIfPresent();
|
||||
+ if (maps != null) {
|
||||
+ this.mappingsByObfName = maps.stream().collect(Collectors.toUnmodifiableMap(ClassMapping::obfName, map -> map));
|
||||
+ this.mappingsByMojangName = maps.stream().collect(Collectors.toUnmodifiableMap(ClassMapping::mojangName, map -> map));
|
||||
+ } else {
|
||||
+ this.mappingsByObfName = null;
|
||||
+ this.mappingsByMojangName = null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public @Nullable Map<String, ClassMapping> mappingsByObfName() {
|
||||
+ return this.mappingsByObfName;
|
||||
+ }
|
||||
+
|
||||
+ public @Nullable Map<String, ClassMapping> mappingsByMojangName() {
|
||||
+ return this.mappingsByMojangName;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Attempts to get the obf name for a given class by its Mojang name. Will
|
||||
+ * return the input string if mappings are not present.
|
||||
+ *
|
||||
+ * @param fullyQualifiedMojangName fully qualified class name (dotted)
|
||||
+ * @return mapped or original fully qualified (dotted) class name
|
||||
+ */
|
||||
+ public String reobfClassName(final String fullyQualifiedMojangName) {
|
||||
+ if (this.mappingsByMojangName == null) {
|
||||
+ return fullyQualifiedMojangName;
|
||||
+ }
|
||||
+
|
||||
+ final ClassMapping map = this.mappingsByMojangName.get(fullyQualifiedMojangName);
|
||||
+ if (map == null) {
|
||||
+ return fullyQualifiedMojangName;
|
||||
+ }
|
||||
+
|
||||
+ return map.obfName();
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Attempts to get the Mojang name for a given class by its obf name. Will
|
||||
+ * return the input string if mappings are not present.
|
||||
+ *
|
||||
+ * @param fullyQualifiedObfName fully qualified class name (dotted)
|
||||
+ * @return mapped or original fully qualified (dotted) class name
|
||||
+ */
|
||||
+ public String deobfClassName(final String fullyQualifiedObfName) {
|
||||
+ if (this.mappingsByObfName == null) {
|
||||
+ return fullyQualifiedObfName;
|
||||
+ }
|
||||
+
|
||||
+ final ClassMapping map = this.mappingsByObfName.get(fullyQualifiedObfName);
|
||||
+ if (map == null) {
|
||||
+ return fullyQualifiedObfName;
|
||||
+ }
|
||||
+
|
||||
+ return map.mojangName();
|
||||
+ }
|
||||
+
|
||||
+ private static @Nullable Set<ClassMapping> loadMappingsIfPresent() {
|
||||
+ try (final @Nullable InputStream mappingsInputStream = ObfHelper.class.getClassLoader().getResourceAsStream("META-INF/mappings/reobf.tiny")) {
|
||||
+ if (mappingsInputStream == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ final IMappingFile mappings = IMappingFile.load(mappingsInputStream); // Mappings are mojang->spigot
|
||||
+ final Set<ClassMapping> classes = new HashSet<>();
|
||||
+
|
||||
+ final StringPool pool = new StringPool();
|
||||
+ for (final IMappingFile.IClass cls : mappings.getClasses()) {
|
||||
+ final Map<String, String> methods = new HashMap<>();
|
||||
+ final Map<String, String> fields = new HashMap<>();
|
||||
+ final Map<String, String> strippedMethods = new HashMap<>();
|
||||
+
|
||||
+ for (final IMappingFile.IMethod methodMapping : cls.getMethods()) {
|
||||
+ methods.put(
|
||||
+ pool.string(methodKey(
|
||||
+ Objects.requireNonNull(methodMapping.getMapped()),
|
||||
+ Objects.requireNonNull(methodMapping.getMappedDescriptor())
|
||||
+ )),
|
||||
+ pool.string(Objects.requireNonNull(methodMapping.getOriginal()))
|
||||
+ );
|
||||
+
|
||||
+ strippedMethods.put(
|
||||
+ pool.string(pool.string(strippedMethodKey(
|
||||
+ methodMapping.getMapped(),
|
||||
+ methodMapping.getDescriptor()
|
||||
+ ))),
|
||||
+ pool.string(methodMapping.getOriginal())
|
||||
+ );
|
||||
+ }
|
||||
+ for (final IMappingFile.IField field : cls.getFields()) {
|
||||
+ fields.put(
|
||||
+ pool.string(field.getMapped()),
|
||||
+ pool.string(field.getOriginal())
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ final ClassMapping map = new ClassMapping(
|
||||
+ Objects.requireNonNull(cls.getMapped()).replace('/', '.'),
|
||||
+ Objects.requireNonNull(cls.getOriginal()).replace('/', '.'),
|
||||
+ Map.copyOf(methods),
|
||||
+ Map.copyOf(fields),
|
||||
+ Map.copyOf(strippedMethods)
|
||||
+ );
|
||||
+ classes.add(map);
|
||||
+ }
|
||||
+
|
||||
+ return Set.copyOf(classes);
|
||||
+ } catch (final IOException ex) {
|
||||
+ System.err.println("Failed to load mappings.");
|
||||
+ ex.printStackTrace();
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static String strippedMethodKey(final String methodName, final String methodDescriptor) {
|
||||
+ final String methodKey = methodKey(methodName, methodDescriptor);
|
||||
+ final int returnDescriptorEnd = methodKey.indexOf(')');
|
||||
+ return methodKey.substring(0, returnDescriptorEnd + 1);
|
||||
+ }
|
||||
+
|
||||
+ public static String methodKey(final String methodName, final String methodDescriptor) {
|
||||
+ return methodName + methodDescriptor;
|
||||
+ }
|
||||
+
|
||||
+ public record ClassMapping(
|
||||
+ String obfName,
|
||||
+ String mojangName,
|
||||
+ Map<String, String> methodsByObf,
|
||||
+ Map<String, String> fieldsByObf,
|
||||
+ // obf name with mapped desc to mapped name. return value is excluded from desc as reflection doesn't use it
|
||||
+ Map<String, String> strippedMethods
|
||||
+ ) {}
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..242811578a786e3807a1a7019d472d5a68f87116
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java
|
||||
@@ -0,0 +1,144 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import io.papermc.paper.configuration.GlobalConfiguration;
|
||||
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
+import java.io.IOException;
|
||||
+import java.io.InputStream;
|
||||
+import java.util.Collections;
|
||||
+import java.util.LinkedHashMap;
|
||||
+import java.util.Map;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+import org.objectweb.asm.ClassReader;
|
||||
+import org.objectweb.asm.ClassVisitor;
|
||||
+import org.objectweb.asm.Label;
|
||||
+import org.objectweb.asm.MethodVisitor;
|
||||
+import org.objectweb.asm.Opcodes;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public enum StacktraceDeobfuscator {
|
||||
+ INSTANCE;
|
||||
+
|
||||
+ private final Map<Class<?>, Int2ObjectMap<String>> lineMapCache = Collections.synchronizedMap(new LinkedHashMap<>(128, 0.75f, true) {
|
||||
+ @Override
|
||||
+ protected boolean removeEldestEntry(final Map.Entry<Class<?>, Int2ObjectMap<String>> eldest) {
|
||||
+ return this.size() > 127;
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ public void deobfuscateThrowable(final Throwable throwable) {
|
||||
+ if (GlobalConfiguration.get() != null && !GlobalConfiguration.get().logging.deobfuscateStacktraces) { // handle null as true
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ throwable.setStackTrace(this.deobfuscateStacktrace(throwable.getStackTrace()));
|
||||
+ final Throwable cause = throwable.getCause();
|
||||
+ if (cause != null) {
|
||||
+ this.deobfuscateThrowable(cause);
|
||||
+ }
|
||||
+ for (final Throwable suppressed : throwable.getSuppressed()) {
|
||||
+ this.deobfuscateThrowable(suppressed);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public StackTraceElement[] deobfuscateStacktrace(final StackTraceElement[] traceElements) {
|
||||
+ if (GlobalConfiguration.get() != null && !GlobalConfiguration.get().logging.deobfuscateStacktraces) { // handle null as true
|
||||
+ return traceElements;
|
||||
+ }
|
||||
+
|
||||
+ final @Nullable Map<String, ObfHelper.ClassMapping> mappings = ObfHelper.INSTANCE.mappingsByObfName();
|
||||
+ if (mappings == null || traceElements.length == 0) {
|
||||
+ return traceElements;
|
||||
+ }
|
||||
+ final StackTraceElement[] result = new StackTraceElement[traceElements.length];
|
||||
+ for (int i = 0; i < traceElements.length; i++) {
|
||||
+ final StackTraceElement element = traceElements[i];
|
||||
+
|
||||
+ final String className = element.getClassName();
|
||||
+ final String methodName = element.getMethodName();
|
||||
+
|
||||
+ final ObfHelper.ClassMapping classMapping = mappings.get(className);
|
||||
+ if (classMapping == null) {
|
||||
+ result[i] = element;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final Class<?> clazz;
|
||||
+ try {
|
||||
+ clazz = Class.forName(className);
|
||||
+ } catch (final ClassNotFoundException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
+ final @Nullable String methodKey = this.determineMethodForLine(clazz, element.getLineNumber());
|
||||
+ final @Nullable String mappedMethodName = methodKey == null ? null : classMapping.methodsByObf().get(methodKey);
|
||||
+
|
||||
+ result[i] = new StackTraceElement(
|
||||
+ element.getClassLoaderName(),
|
||||
+ element.getModuleName(),
|
||||
+ element.getModuleVersion(),
|
||||
+ classMapping.mojangName(),
|
||||
+ mappedMethodName != null ? mappedMethodName : methodName,
|
||||
+ sourceFileName(classMapping.mojangName()),
|
||||
+ element.getLineNumber()
|
||||
+ );
|
||||
+ }
|
||||
+ return result;
|
||||
+ }
|
||||
+
|
||||
+ private @Nullable String determineMethodForLine(final Class<?> clazz, final int lineNumber) {
|
||||
+ return this.lineMapCache.computeIfAbsent(clazz, StacktraceDeobfuscator::buildLineMap).get(lineNumber);
|
||||
+ }
|
||||
+
|
||||
+ private static String sourceFileName(final String fullClassName) {
|
||||
+ final int dot = fullClassName.lastIndexOf('.');
|
||||
+ final String className = dot == -1
|
||||
+ ? fullClassName
|
||||
+ : fullClassName.substring(dot + 1);
|
||||
+ final String rootClassName = className.split("\\$")[0];
|
||||
+ return rootClassName + ".java";
|
||||
+ }
|
||||
+
|
||||
+ private static Int2ObjectMap<String> buildLineMap(final Class<?> key) {
|
||||
+ final StringPool pool = new StringPool();
|
||||
+ final Int2ObjectMap<String> lineMap = new Int2ObjectOpenHashMap<>();
|
||||
+ final class LineCollectingMethodVisitor extends MethodVisitor {
|
||||
+ private final String name;
|
||||
+ private final String descriptor;
|
||||
+
|
||||
+ LineCollectingMethodVisitor(final String name, final String descriptor) {
|
||||
+ super(Opcodes.ASM9);
|
||||
+ this.name = name;
|
||||
+ this.descriptor = descriptor;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void visitLineNumber(final int line, final Label start) {
|
||||
+ lineMap.put(line, pool.string(ObfHelper.methodKey(this.name, this.descriptor)));
|
||||
+ }
|
||||
+ }
|
||||
+ final ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM9) {
|
||||
+ @Override
|
||||
+ public MethodVisitor visitMethod(final int access, final String name, final String descriptor, final String signature, final String[] exceptions) {
|
||||
+ return new LineCollectingMethodVisitor(name, descriptor);
|
||||
+ }
|
||||
+ };
|
||||
+ try {
|
||||
+ final @Nullable InputStream inputStream = StacktraceDeobfuscator.class.getClassLoader()
|
||||
+ .getResourceAsStream(key.getName().replace('.', '/') + ".class");
|
||||
+ if (inputStream == null) {
|
||||
+ throw new IllegalStateException("Could not find class file: " + key.getName());
|
||||
+ }
|
||||
+ final byte[] classData;
|
||||
+ try (inputStream) {
|
||||
+ classData = inputStream.readAllBytes();
|
||||
+ }
|
||||
+ final ClassReader reader = new ClassReader(classData);
|
||||
+ reader.accept(classVisitor, 0);
|
||||
+ } catch (final IOException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
+ return lineMap;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/util/StringPool.java b/src/main/java/io/papermc/paper/util/StringPool.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..c0a486cb46ff30353c3ff09567891cd36238eeb4
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/StringPool.java
|
||||
@@ -0,0 +1,34 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import java.util.HashMap;
|
||||
+import java.util.Map;
|
||||
+import java.util.function.Function;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+/**
|
||||
+ * De-duplicates {@link String} instances without using {@link String#intern()}.
|
||||
+ *
|
||||
+ * <p>Interning may not be desired as we may want to use the heap for our pool,
|
||||
+ * so it can be garbage collected as normal, etc.</p>
|
||||
+ *
|
||||
+ * <p>Additionally, interning can be slow due to the potentially large size of the
|
||||
+ * pool (as it is shared for the entire JVM), and because most JVMs implement
|
||||
+ * it using JNI.</p>
|
||||
+ */
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class StringPool {
|
||||
+ private final Map<String, String> pool;
|
||||
+
|
||||
+ public StringPool() {
|
||||
+ this(new HashMap<>());
|
||||
+ }
|
||||
+
|
||||
+ public StringPool(final Map<String, String> map) {
|
||||
+ this.pool = map;
|
||||
+ }
|
||||
+
|
||||
+ public String string(final String string) {
|
||||
+ return this.pool.computeIfAbsent(string, Function.identity());
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java
|
||||
index 1938ae691dafec1fc1e5a68792d1191bd52b4e5c..268310642181a715815d3b2d1c0f090e6252971a 100644
|
||||
--- a/src/main/java/net/minecraft/CrashReport.java
|
||||
+++ b/src/main/java/net/minecraft/CrashReport.java
|
||||
@@ -34,6 +34,7 @@ public class CrashReport {
|
||||
private final SystemReport systemReport = new SystemReport();
|
||||
|
||||
public CrashReport(String message, Throwable cause) {
|
||||
+ io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(cause); // Paper
|
||||
this.title = message;
|
||||
this.exception = cause;
|
||||
this.systemReport.setDetail("CraftBukkit Information", new org.bukkit.craftbukkit.CraftCrashReport()); // CraftBukkit
|
||||
diff --git a/src/main/java/net/minecraft/CrashReportCategory.java b/src/main/java/net/minecraft/CrashReportCategory.java
|
||||
index f367ba058018074bfe6e4fe88bcc875ea9794d9e..2176171954609fd88f97f93408e14e018c1d6eaa 100644
|
||||
--- a/src/main/java/net/minecraft/CrashReportCategory.java
|
||||
+++ b/src/main/java/net/minecraft/CrashReportCategory.java
|
||||
@@ -110,6 +110,7 @@ public class CrashReportCategory {
|
||||
} else {
|
||||
this.stackTrace = new StackTraceElement[stackTraceElements.length - 3 - ignoredCallCount];
|
||||
System.arraycopy(stackTraceElements, 3 + ignoredCallCount, this.stackTrace, 0, this.stackTrace.length);
|
||||
+ this.stackTrace = io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(this.stackTrace); // Paper
|
||||
return this.stackTrace.length;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index 77985072928a1b892fb4f7dec1d0899324780082..f5e6610d271ef2c997fb3d1a5f65e0bf0740805a 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -82,13 +82,13 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
marker.add(Connection.PACKET_MARKER);
|
||||
});
|
||||
public static final Supplier<NioEventLoopGroup> NETWORK_WORKER_GROUP = Suppliers.memoize(() -> {
|
||||
- return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Client IO #%d").setDaemon(true).build());
|
||||
+ return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
public static final Supplier<EpollEventLoopGroup> NETWORK_EPOLL_WORKER_GROUP = Suppliers.memoize(() -> {
|
||||
- return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).build());
|
||||
+ return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
public static final Supplier<DefaultEventLoopGroup> LOCAL_WORKER_GROUP = Suppliers.memoize(() -> {
|
||||
- return new DefaultEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).build());
|
||||
+ return new DefaultEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
private static final ProtocolInfo<ServerHandshakePacketListener> INITIAL_PROTOCOL = HandshakeProtocols.SERVERBOUND;
|
||||
private final PacketFlow receiving;
|
||||
@@ -197,7 +197,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
}
|
||||
}
|
||||
- if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) throwable.printStackTrace(); // Spigot
|
||||
+ if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) io.papermc.paper.util.TraceUtil.printStackTrace(throwable); // Spigot // Paper
|
||||
}
|
||||
|
||||
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet<?> packet) {
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index b41eb920b5665b7a1b7cd9f38955c31eeb350847..bb59986c211f7d6ea50b1ad4bd5565227bec8a6c 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -210,6 +210,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
org.spigotmc.SpigotConfig.init((java.io.File) this.options.valueOf("spigot-settings"));
|
||||
org.spigotmc.SpigotConfig.registerCommands();
|
||||
// Spigot end
|
||||
+ io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // Paper - load mappings for stacktrace deobf and etc.
|
||||
// Paper start - initialize global and world-defaults configuration
|
||||
this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess());
|
||||
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
index 987360a266a5a870f06929b00c9f451901188fd6..2cf3e79ec5e8706b71d27ebad4668773f0b91195 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -52,10 +52,10 @@ public class ServerConnectionListener {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final Supplier<NioEventLoopGroup> SERVER_EVENT_GROUP = Suppliers.memoize(() -> {
|
||||
- return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Server IO #%d").setDaemon(true).build());
|
||||
+ return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Server IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
public static final Supplier<EpollEventLoopGroup> SERVER_EPOLL_EVENT_GROUP = Suppliers.memoize(() -> {
|
||||
- return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Server IO #%d").setDaemon(true).build());
|
||||
+ return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Server IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
final MinecraftServer server;
|
||||
public volatile boolean running;
|
||||
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
index 8d06e8d286da2573e40794adab695ff77e5afd86..68551947f5b7d3471f15bd74ccd86519ab34c1c1 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
@@ -356,7 +356,7 @@ public class OldUsersConverter {
|
||||
try {
|
||||
root = NbtIo.readCompressed(new java.io.FileInputStream(file5), NbtAccounter.unlimitedHeap());
|
||||
} catch (Exception exception) {
|
||||
- exception.printStackTrace();
|
||||
+ io.papermc.paper.util.TraceUtil.printStackTrace(exception); // Paper
|
||||
}
|
||||
|
||||
if (root != null) {
|
||||
@@ -369,7 +369,7 @@ public class OldUsersConverter {
|
||||
try {
|
||||
NbtIo.writeCompressed(root, new java.io.FileOutputStream(file2));
|
||||
} catch (Exception exception) {
|
||||
- exception.printStackTrace();
|
||||
+ io.papermc.paper.util.TraceUtil.printStackTrace(exception); // Paper
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index c4bf7053d83d207caca0e13e19f5c1afa7062de3..f697d45e0ac4e9cdc8a46121510a04c0f294d91f 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -130,7 +130,7 @@ public class WatchdogThread extends Thread
|
||||
}
|
||||
log.log( Level.SEVERE, "\tStack:" );
|
||||
//
|
||||
- for ( StackTraceElement stack : thread.getStackTrace() )
|
||||
+ for ( StackTraceElement stack : io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(thread.getStackTrace()) ) // Paper
|
||||
{
|
||||
log.log( Level.SEVERE, "\t\t" + stack );
|
||||
}
|
||||
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
|
||||
index 18e961a37b2830da6e5dab7aa35116b2f5215898..128fa1376f22d3429a23d79a2772abf2e7fec2bc 100644
|
||||
--- a/src/main/resources/log4j2.xml
|
||||
+++ b/src/main/resources/log4j2.xml
|
||||
@@ -30,10 +30,14 @@
|
||||
<DefaultRolloverStrategy max="1000"/>
|
||||
</RollingRandomAccessFile>
|
||||
<Async name="Async">
|
||||
+ <AppenderRef ref="rewrite"/>
|
||||
+ </Async>
|
||||
+ <Rewrite name="rewrite">
|
||||
+ <StacktraceDeobfuscatingRewritePolicy />
|
||||
<AppenderRef ref="File"/>
|
||||
<AppenderRef ref="TerminalConsole" level="info"/>
|
||||
<AppenderRef ref="ServerGuiConsole" level="info"/>
|
||||
- </Async>
|
||||
+ </Rewrite>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="info">
|
|
@ -1,246 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: SirYwell <hannesgreule@outlook.de>
|
||||
Date: Sat, 10 Jul 2021 11:12:30 +0200
|
||||
Subject: [PATCH] Rewrite LogEvents to contain the source jars in stack traces
|
||||
|
||||
|
||||
diff --git a/src/log4jPlugins/java/io/papermc/paper/logging/DelegateLogEvent.java b/src/log4jPlugins/java/io/papermc/paper/logging/DelegateLogEvent.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6ffd1befe64c6c3036c22e05ed1c44808d64bd28
|
||||
--- /dev/null
|
||||
+++ b/src/log4jPlugins/java/io/papermc/paper/logging/DelegateLogEvent.java
|
||||
@@ -0,0 +1,130 @@
|
||||
+package io.papermc.paper.logging;
|
||||
+
|
||||
+import org.apache.logging.log4j.Level;
|
||||
+import org.apache.logging.log4j.Marker;
|
||||
+import org.apache.logging.log4j.ThreadContext;
|
||||
+import org.apache.logging.log4j.core.LogEvent;
|
||||
+import org.apache.logging.log4j.core.impl.ThrowableProxy;
|
||||
+import org.apache.logging.log4j.core.time.Instant;
|
||||
+import org.apache.logging.log4j.message.Message;
|
||||
+import org.apache.logging.log4j.util.ReadOnlyStringMap;
|
||||
+
|
||||
+import java.util.Map;
|
||||
+
|
||||
+public class DelegateLogEvent implements LogEvent {
|
||||
+ private final LogEvent original;
|
||||
+
|
||||
+ protected DelegateLogEvent(LogEvent original) {
|
||||
+ this.original = original;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public LogEvent toImmutable() {
|
||||
+ return this.original.toImmutable();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Map<String, String> getContextMap() {
|
||||
+ return this.original.getContextMap();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ReadOnlyStringMap getContextData() {
|
||||
+ return this.original.getContextData();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ThreadContext.ContextStack getContextStack() {
|
||||
+ return this.original.getContextStack();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String getLoggerFqcn() {
|
||||
+ return this.original.getLoggerFqcn();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Level getLevel() {
|
||||
+ return this.original.getLevel();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String getLoggerName() {
|
||||
+ return this.original.getLoggerName();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Marker getMarker() {
|
||||
+ return this.original.getMarker();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Message getMessage() {
|
||||
+ return this.original.getMessage();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public long getTimeMillis() {
|
||||
+ return this.original.getTimeMillis();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Instant getInstant() {
|
||||
+ return this.original.getInstant();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public StackTraceElement getSource() {
|
||||
+ return this.original.getSource();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String getThreadName() {
|
||||
+ return this.original.getThreadName();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public long getThreadId() {
|
||||
+ return this.original.getThreadId();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getThreadPriority() {
|
||||
+ return this.original.getThreadPriority();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Throwable getThrown() {
|
||||
+ return this.original.getThrown();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ThrowableProxy getThrownProxy() {
|
||||
+ return this.original.getThrownProxy();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isEndOfBatch() {
|
||||
+ return this.original.isEndOfBatch();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isIncludeLocation() {
|
||||
+ return this.original.isIncludeLocation();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setEndOfBatch(boolean endOfBatch) {
|
||||
+ this.original.setEndOfBatch(endOfBatch);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setIncludeLocation(boolean locationRequired) {
|
||||
+ this.original.setIncludeLocation(locationRequired);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public long getNanoTime() {
|
||||
+ return this.original.getNanoTime();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/log4jPlugins/java/io/papermc/paper/logging/ExtraClassInfoLogEvent.java b/src/log4jPlugins/java/io/papermc/paper/logging/ExtraClassInfoLogEvent.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..558427c65b4051923f73d15d85ee519be005060a
|
||||
--- /dev/null
|
||||
+++ b/src/log4jPlugins/java/io/papermc/paper/logging/ExtraClassInfoLogEvent.java
|
||||
@@ -0,0 +1,48 @@
|
||||
+package io.papermc.paper.logging;
|
||||
+
|
||||
+import org.apache.logging.log4j.core.LogEvent;
|
||||
+import org.apache.logging.log4j.core.impl.ExtendedClassInfo;
|
||||
+import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement;
|
||||
+import org.apache.logging.log4j.core.impl.ThrowableProxy;
|
||||
+
|
||||
+public class ExtraClassInfoLogEvent extends DelegateLogEvent {
|
||||
+
|
||||
+ private boolean fixed;
|
||||
+
|
||||
+ public ExtraClassInfoLogEvent(LogEvent original) {
|
||||
+ super(original);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ThrowableProxy getThrownProxy() {
|
||||
+ if (fixed) {
|
||||
+ return super.getThrownProxy();
|
||||
+ }
|
||||
+ rewriteStackTrace(super.getThrownProxy());
|
||||
+ fixed = true;
|
||||
+ return super.getThrownProxy();
|
||||
+ }
|
||||
+
|
||||
+ private void rewriteStackTrace(ThrowableProxy throwable) {
|
||||
+ ExtendedStackTraceElement[] stackTrace = throwable.getExtendedStackTrace();
|
||||
+ for (int i = 0; i < stackTrace.length; i++) {
|
||||
+ ExtendedClassInfo classInfo = stackTrace[i].getExtraClassInfo();
|
||||
+ if (classInfo.getLocation().equals("?")) {
|
||||
+ StackTraceElement element = stackTrace[i].getStackTraceElement();
|
||||
+ String classLoaderName = element.getClassLoaderName();
|
||||
+ if (classLoaderName != null) {
|
||||
+ stackTrace[i] = new ExtendedStackTraceElement(element,
|
||||
+ new ExtendedClassInfo(classInfo.getExact(), classLoaderName, "?"));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if (throwable.getCauseProxy() != null) {
|
||||
+ rewriteStackTrace(throwable.getCauseProxy());
|
||||
+ }
|
||||
+ if (throwable.getSuppressedProxies() != null) {
|
||||
+ for (ThrowableProxy proxy : throwable.getSuppressedProxies()) {
|
||||
+ rewriteStackTrace(proxy);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/log4jPlugins/java/io/papermc/paper/logging/ExtraClassInfoRewritePolicy.java b/src/log4jPlugins/java/io/papermc/paper/logging/ExtraClassInfoRewritePolicy.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..34734bb969a1a74c7a4f9c17d40ebf007ad5d701
|
||||
--- /dev/null
|
||||
+++ b/src/log4jPlugins/java/io/papermc/paper/logging/ExtraClassInfoRewritePolicy.java
|
||||
@@ -0,0 +1,29 @@
|
||||
+package io.papermc.paper.logging;
|
||||
+
|
||||
+import org.apache.logging.log4j.core.Core;
|
||||
+import org.apache.logging.log4j.core.LogEvent;
|
||||
+import org.apache.logging.log4j.core.appender.rewrite.RewritePolicy;
|
||||
+import org.apache.logging.log4j.core.config.plugins.Plugin;
|
||||
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+
|
||||
+@Plugin(
|
||||
+ name = "ExtraClassInfoRewritePolicy",
|
||||
+ category = Core.CATEGORY_NAME,
|
||||
+ elementType = "rewritePolicy",
|
||||
+ printObject = true
|
||||
+)
|
||||
+public final class ExtraClassInfoRewritePolicy implements RewritePolicy {
|
||||
+ @Override
|
||||
+ public LogEvent rewrite(LogEvent source) {
|
||||
+ if (source.getThrown() != null) {
|
||||
+ return new ExtraClassInfoLogEvent(source);
|
||||
+ }
|
||||
+ return source;
|
||||
+ }
|
||||
+
|
||||
+ @PluginFactory
|
||||
+ public static @NotNull ExtraClassInfoRewritePolicy createPolicy() {
|
||||
+ return new ExtraClassInfoRewritePolicy();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
|
||||
index 128fa1376f22d3429a23d79a2772abf2e7fec2bc..637d64da9938e51a97338b9253b43889585c67bb 100644
|
||||
--- a/src/main/resources/log4j2.xml
|
||||
+++ b/src/main/resources/log4j2.xml
|
||||
@@ -34,6 +34,10 @@
|
||||
</Async>
|
||||
<Rewrite name="rewrite">
|
||||
<StacktraceDeobfuscatingRewritePolicy />
|
||||
+ <AppenderRef ref="rewrite2"/>
|
||||
+ </Rewrite>
|
||||
+ <Rewrite name="rewrite2">
|
||||
+ <ExtraClassInfoRewritePolicy />
|
||||
<AppenderRef ref="File"/>
|
||||
<AppenderRef ref="TerminalConsole" level="info"/>
|
||||
<AppenderRef ref="ServerGuiConsole" level="info"/>
|
|
@ -1,665 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Mon, 29 Feb 2016 21:02:09 -0600
|
||||
Subject: [PATCH] Paper command
|
||||
|
||||
Co-authored-by: Zach Brown <zach.brown@destroystokyo.com>
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/command/CallbackCommand.java b/src/main/java/io/papermc/paper/command/CallbackCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..fa4202abd13c1c286bd398938103d1103d5443e7
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/command/CallbackCommand.java
|
||||
@@ -0,0 +1,35 @@
|
||||
+package io.papermc.paper.command;
|
||||
+
|
||||
+import io.papermc.paper.adventure.providers.ClickCallbackProviderImpl;
|
||||
+import org.bukkit.command.Command;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+import java.util.UUID;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public class CallbackCommand extends Command {
|
||||
+
|
||||
+ protected CallbackCommand(final String name) {
|
||||
+ super(name);
|
||||
+ this.description = "ClickEvent callback";
|
||||
+ this.usageMessage = "/callback <uuid>";
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean execute(final CommandSender sender, final String commandLabel, final String[] args) {
|
||||
+ if (args.length != 1) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ final UUID id;
|
||||
+ try {
|
||||
+ id = UUID.fromString(args[0]);
|
||||
+ } catch (final IllegalArgumentException ignored) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ ClickCallbackProviderImpl.CALLBACK_MANAGER.runCallback(sender, id);
|
||||
+ return true;
|
||||
+ }
|
||||
+}
|
||||
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..95d3320c865d24609252063be07cddfd07d0d6d8
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
@@ -0,0 +1,143 @@
|
||||
+package io.papermc.paper.command;
|
||||
+
|
||||
+import io.papermc.paper.command.subcommands.*;
|
||||
+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));
|
||||
+ });
|
||||
+ private static final Set<String> COMPLETABLE_SUBCOMMANDS = SUBCOMMANDS.entrySet().stream().filter(entry -> entry.getValue().tabCompletes()).map(Map.Entry::getKey).collect(Collectors.toSet());
|
||||
+ // 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, COMPLETABLE_SUBCOMMANDS);
|
||||
+ }
|
||||
+
|
||||
+ 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.ROOT);
|
||||
+ @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..5e5ec700a368cfdaa1ea0b3f0fa82089895d4b92
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/command/PaperCommands.java
|
||||
@@ -0,0 +1,28 @@
|
||||
+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"));
|
||||
+ COMMANDS.put("callback", new CallbackCommand("callback"));
|
||||
+ }
|
||||
+
|
||||
+ 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..7e9e0ff8639be135bf8575e375cbada5b57164e1
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/command/PaperSubcommand.java
|
||||
@@ -0,0 +1,20 @@
|
||||
+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();
|
||||
+ }
|
||||
+
|
||||
+ default boolean tabCompletes() {
|
||||
+ return true;
|
||||
+ }
|
||||
+}
|
||||
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..67fcba634f8183bb33834ac3b2c3dcfb8d87129e
|
||||
--- /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.ROOT).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.ROOT))) {
|
||||
+ String filter = "*";
|
||||
+ if (args.length > 1) {
|
||||
+ if (args[1].toLowerCase(Locale.ROOT).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 bb59986c211f7d6ea50b1ad4bd5565227bec8a6c..9c950fc1de15b5039e34a9fdf893e97a8cc13237 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -215,6 +215,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess());
|
||||
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());
|
||||
// Paper end - initialize global and world-defaults configuration
|
||||
+ io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
|
||||
|
||||
this.setPvpAllowed(dedicatedserverproperties.pvp);
|
||||
this.setFlightAllowed(dedicatedserverproperties.allowFlight);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 752933ceabd7ebe7b1e9f7d41198128f6f2182a6..492af80bc4a252ad3b82aef0c46c3e6625ec9146 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -988,6 +988,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");
|
||||
|
||||
@@ -2710,6 +2711,34 @@ public final class CraftServer implements Server {
|
||||
// Paper 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() {
|
|
@ -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 9c950fc1de15b5039e34a9fdf893e97a8cc13237..6ba90739c20995362a5275e2259cac9e17fbcf59 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -216,6 +216,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());
|
||||
// Paper end - initialize global and world-defaults configuration
|
||||
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
|
||||
+ com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
|
||||
|
||||
this.setPvpAllowed(dedicatedserverproperties.pvp);
|
||||
this.setFlightAllowed(dedicatedserverproperties.allowFlight);
|
||||
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
|
||||
index b717c9d8b6edc2cafc9281140913b7bdb6108cf0..ba621fdc82896245f6ce448e084847edc4d3fe08 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
|
@ -1,185 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach@zachbr.io>
|
||||
Date: Wed, 3 Oct 2018 20:09:18 -0400
|
||||
Subject: [PATCH] Hook into CB plugin rewrites
|
||||
|
||||
Allows us to do fun stuff like rewrite the OBC util fastutil location to
|
||||
our own relocation. Also lets us rewrite NMS calls for when we're
|
||||
debugging in an IDE pre-relocate.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java
|
||||
index b60b715af8c3259aed8d386a5165653e0b6ed667..2a29f60c3e82239ab7acd85242fc3390cb9129cd 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java
|
||||
@@ -12,6 +12,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
+import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -22,6 +23,7 @@ import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
+import javax.annotation.Nonnull;
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpec;
|
||||
@@ -123,6 +125,40 @@ public class Commodore {
|
||||
return this.reroutes;
|
||||
}
|
||||
|
||||
+ // Paper start - Plugin rewrites
|
||||
+ private static final Map<String, String> SEARCH_AND_REMOVE = initReplacementsMap();
|
||||
+ private static Map<String, String> initReplacementsMap() {
|
||||
+ Map<String, String> getAndRemove = new HashMap<>();
|
||||
+ // Be wary of maven shade's relocations
|
||||
+
|
||||
+ final java.util.jar.Manifest manifest = io.papermc.paper.util.JarManifests.manifest(Commodore.class);
|
||||
+ if (Boolean.getBoolean( "debug.rewriteForIde") && manifest != null)
|
||||
+ {
|
||||
+ // unversion incoming calls for pre-relocate debug work
|
||||
+ final String NMS_REVISION_PACKAGE = "v" + manifest.getMainAttributes().getValue("CraftBukkit-Package-Version") + "/";
|
||||
+
|
||||
+ getAndRemove.put("org/bukkit/".concat("craftbukkit/" + NMS_REVISION_PACKAGE), NMS_REVISION_PACKAGE);
|
||||
+ }
|
||||
+
|
||||
+ return getAndRemove;
|
||||
+ }
|
||||
+
|
||||
+ @Nonnull
|
||||
+ private static String getOriginalOrRewrite(@Nonnull String original)
|
||||
+ {
|
||||
+ String rewrite = null;
|
||||
+ for ( Map.Entry<String, String> entry : SEARCH_AND_REMOVE.entrySet() )
|
||||
+ {
|
||||
+ if ( original.contains( entry.getKey() ) )
|
||||
+ {
|
||||
+ rewrite = original.replace( entry.getValue(), "" );
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return rewrite != null ? rewrite : original;
|
||||
+ }
|
||||
+ // Paper end - Plugin rewrites
|
||||
+
|
||||
public static void main(String[] args) {
|
||||
OptionParser parser = new OptionParser();
|
||||
OptionSpec<File> inputFlag = parser.acceptsAll(Arrays.asList("i", "input")).withRequiredArg().ofType(File.class).required();
|
||||
@@ -278,9 +314,49 @@ public class Commodore {
|
||||
}
|
||||
|
||||
return new MethodVisitor(this.api, super.visitMethod(access, name, desc, signature, exceptions)) {
|
||||
+ // Paper start - Plugin rewrites
|
||||
+ @Override
|
||||
+ public void visitTypeInsn(int opcode, String type) {
|
||||
+ type = getOriginalOrRewrite(type);
|
||||
+
|
||||
+ super.visitTypeInsn(opcode, type);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
|
||||
+ for (int i = 0; i < local.length; i++)
|
||||
+ {
|
||||
+ if (!(local[i] instanceof String)) { continue; }
|
||||
+
|
||||
+ local[i] = getOriginalOrRewrite((String) local[i]);
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < stack.length; i++)
|
||||
+ {
|
||||
+ if (!(stack[i] instanceof String)) { continue; }
|
||||
+
|
||||
+ stack[i] = getOriginalOrRewrite((String) stack[i]);
|
||||
+ }
|
||||
+
|
||||
+ super.visitFrame(type, nLocal, local, nStack, stack);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
|
||||
+ descriptor = getOriginalOrRewrite(descriptor);
|
||||
+
|
||||
+ super.visitLocalVariable(name, descriptor, signature, start, end, index);
|
||||
+ }
|
||||
+ // Paper end - Plugin rewrites
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
|
||||
+ // Paper start - Rewrite plugins
|
||||
+ owner = getOriginalOrRewrite(owner);
|
||||
+ if (desc != null) {
|
||||
+ desc = getOriginalOrRewrite(desc);
|
||||
+ }
|
||||
+ // Paper end
|
||||
name = FieldRename.rename(pluginVersion, owner, name);
|
||||
|
||||
if (modern) {
|
||||
@@ -393,6 +469,13 @@ public class Commodore {
|
||||
return;
|
||||
}
|
||||
|
||||
+ // Paper start - Rewrite plugins
|
||||
+ owner = getOriginalOrRewrite(owner) ;
|
||||
+ if (desc != null) {
|
||||
+ desc = getOriginalOrRewrite(desc);
|
||||
+ }
|
||||
+ // Paper end - Rewrite plugins
|
||||
+
|
||||
if (modern) {
|
||||
if (owner.equals("org/bukkit/Material") || (instantiatedMethodType != null && instantiatedMethodType.getDescriptor().startsWith("(Lorg/bukkit/Material;)"))) {
|
||||
switch (name) {
|
||||
@@ -489,6 +572,13 @@ public class Commodore {
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(Object value) {
|
||||
+ // Paper start
|
||||
+ if (value instanceof Type type) {
|
||||
+ if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
|
||||
+ value = Type.getType(getOriginalOrRewrite(type.getDescriptor()));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (value instanceof String && ((String) value).equals("com.mysql.jdbc.Driver")) {
|
||||
super.visitLdcInsn("com.mysql.cj.jdbc.Driver");
|
||||
return;
|
||||
@@ -499,6 +589,14 @@ public class Commodore {
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
|
||||
+ // Paper start - Rewrite plugins
|
||||
+ name = getOriginalOrRewrite(name);
|
||||
+ if (descriptor != null) {
|
||||
+ descriptor = getOriginalOrRewrite(descriptor);
|
||||
+ }
|
||||
+ final String fName = name;
|
||||
+ final String fDescriptor = descriptor;
|
||||
+ // Paper end - Rewrite plugins
|
||||
if (bootstrapMethodHandle.getOwner().equals("java/lang/invoke/LambdaMetafactory")
|
||||
&& bootstrapMethodHandle.getName().equals("metafactory") && bootstrapMethodArguments.length == 3) {
|
||||
Type samMethodType = (Type) bootstrapMethodArguments[0];
|
||||
@@ -515,7 +613,7 @@ public class Commodore {
|
||||
methodArgs.add(new Handle(newOpcode, newOwner, newName, newDescription, newItf));
|
||||
methodArgs.add(newInstantiated);
|
||||
|
||||
- super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, methodArgs.toArray(Object[]::new));
|
||||
+ super.visitInvokeDynamicInsn(fName, fDescriptor, bootstrapMethodHandle, methodArgs.toArray(Object[]::new)); // Paper - use final local vars
|
||||
}, implMethod.getTag(), implMethod.getOwner(), implMethod.getName(), implMethod.getDesc(), implMethod.isInterface(), samMethodType, instantiatedMethodType);
|
||||
return;
|
||||
}
|
||||
@@ -566,6 +664,12 @@ public class Commodore {
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
|
||||
+ // Paper start - Rewrite plugins
|
||||
+ descriptor = getOriginalOrRewrite(descriptor);
|
||||
+ if ( signature != null ) {
|
||||
+ signature = getOriginalOrRewrite(signature);
|
||||
+ }
|
||||
+ // Paper end
|
||||
return new FieldVisitor(this.api, super.visitField(access, name, descriptor, signature, value)) {
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
|
|
@ -1,740 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Sun, 30 Oct 2022 23:47:26 +0100
|
||||
Subject: [PATCH] Remap reflection calls in plugins using internals
|
||||
|
||||
Co-authored-by: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index 381a4885c4f52c1e094af350fcb7e04b590f849a..6d8f4c3b290609d60dbcabe3d2c8274b017246c8 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -48,6 +48,12 @@ dependencies {
|
||||
testImplementation("org.junit-pioneer:junit-pioneer:2.2.0") // Paper - CartesianTest
|
||||
implementation("net.neoforged:srgutils:1.0.9") // Paper - mappings handling
|
||||
implementation("net.neoforged:AutoRenamingTool:2.0.3") // Paper - remap plugins
|
||||
+ // Paper start - Remap reflection
|
||||
+ val reflectionRewriterVersion = "0.0.3"
|
||||
+ implementation("io.papermc:reflection-rewriter:$reflectionRewriterVersion")
|
||||
+ implementation("io.papermc:reflection-rewriter-runtime:$reflectionRewriterVersion")
|
||||
+ implementation("io.papermc:reflection-rewriter-proxy-generator:$reflectionRewriterVersion")
|
||||
+ // Paper end - Remap reflection
|
||||
}
|
||||
|
||||
paperweight {
|
||||
diff --git a/src/main/java/io/papermc/paper/configuration/serializer/PacketClassSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/PacketClassSerializer.java
|
||||
index 893ad5e7c2d32ccd64962d95d146bbd317c28ab8..3d73ea0e63c97b2b08e719b7be7af3894fb2d4e8 100644
|
||||
--- a/src/main/java/io/papermc/paper/configuration/serializer/PacketClassSerializer.java
|
||||
+++ b/src/main/java/io/papermc/paper/configuration/serializer/PacketClassSerializer.java
|
||||
@@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableBiMap;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import io.papermc.paper.configuration.serializer.collections.MapSerializer;
|
||||
+import io.papermc.paper.util.MappingEnvironment;
|
||||
import io.papermc.paper.util.ObfHelper;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
@@ -69,7 +70,7 @@ public final class PacketClassSerializer extends ScalarSerializer<Class<? extend
|
||||
@Override
|
||||
protected @Nullable Object serialize(final Class<? extends Packet<?>> packetClass, final Predicate<Class<?>> typeSupported) {
|
||||
final String name = packetClass.getName();
|
||||
- @Nullable String mojName = ObfHelper.INSTANCE.mappingsByMojangName() == null ? name : MOJANG_TO_OBF.inverse().get(name); // if the mappings are null, running on moj-mapped server
|
||||
+ @Nullable String mojName = ObfHelper.INSTANCE.mappingsByMojangName() == null || !MappingEnvironment.reobf() ? name : MOJANG_TO_OBF.inverse().get(name); // if the mappings are null, running on moj-mapped server
|
||||
if (mojName == null && MOJANG_TO_OBF.containsKey(name)) {
|
||||
mojName = name;
|
||||
}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java b/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..1240c061c121e8d5eb9add4e5e21955ee6df9368
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java
|
||||
@@ -0,0 +1,187 @@
|
||||
+package io.papermc.paper.plugin.entrypoint.classloader;
|
||||
+
|
||||
+import io.papermc.paper.pluginremap.reflect.ReflectionRemapper;
|
||||
+import java.io.IOException;
|
||||
+import java.io.InputStream;
|
||||
+import java.io.UncheckedIOException;
|
||||
+import java.net.JarURLConnection;
|
||||
+import java.net.URI;
|
||||
+import java.net.URL;
|
||||
+import java.net.URLClassLoader;
|
||||
+import java.security.CodeSigner;
|
||||
+import java.security.CodeSource;
|
||||
+import java.util.Map;
|
||||
+import java.util.concurrent.ConcurrentHashMap;
|
||||
+import java.util.function.Function;
|
||||
+import java.util.jar.Attributes;
|
||||
+import java.util.jar.Manifest;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.objectweb.asm.ClassReader;
|
||||
+import org.objectweb.asm.ClassVisitor;
|
||||
+import org.objectweb.asm.ClassWriter;
|
||||
+
|
||||
+import static java.util.Objects.requireNonNullElse;
|
||||
+
|
||||
+public final class BytecodeModifyingURLClassLoader extends URLClassLoader {
|
||||
+ static {
|
||||
+ ClassLoader.registerAsParallelCapable();
|
||||
+ }
|
||||
+
|
||||
+ private static final Object MISSING_MANIFEST = new Object();
|
||||
+
|
||||
+ private final Function<byte[], byte[]> modifier;
|
||||
+ private final Map<String, Object> manifests = new ConcurrentHashMap<>();
|
||||
+
|
||||
+ public BytecodeModifyingURLClassLoader(
|
||||
+ final URL[] urls,
|
||||
+ final ClassLoader parent,
|
||||
+ final Function<byte[], byte[]> modifier
|
||||
+ ) {
|
||||
+ super(urls, parent);
|
||||
+ this.modifier = modifier;
|
||||
+ }
|
||||
+
|
||||
+ public BytecodeModifyingURLClassLoader(
|
||||
+ final URL[] urls,
|
||||
+ final ClassLoader parent
|
||||
+ ) {
|
||||
+ this(urls, parent, bytes -> {
|
||||
+ final ClassReader classReader = new ClassReader(bytes);
|
||||
+ final ClassWriter classWriter = new ClassWriter(classReader, 0);
|
||||
+ final ClassVisitor visitor = ReflectionRemapper.visitor(classWriter);
|
||||
+ if (visitor == classWriter) {
|
||||
+ return bytes;
|
||||
+ }
|
||||
+ classReader.accept(visitor, 0);
|
||||
+ return classWriter.toByteArray();
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected Class<?> findClass(final String name) throws ClassNotFoundException {
|
||||
+ final Class<?> result;
|
||||
+ final String path = name.replace('.', '/').concat(".class");
|
||||
+ final URL url = this.findResource(path);
|
||||
+ if (url != null) {
|
||||
+ try {
|
||||
+ result = this.defineClass(name, url);
|
||||
+ } catch (final IOException e) {
|
||||
+ throw new ClassNotFoundException(name, e);
|
||||
+ }
|
||||
+ } else {
|
||||
+ result = null;
|
||||
+ }
|
||||
+ if (result == null) {
|
||||
+ throw new ClassNotFoundException(name);
|
||||
+ }
|
||||
+ return result;
|
||||
+ }
|
||||
+
|
||||
+ private Class<?> defineClass(String name, URL url) throws IOException {
|
||||
+ int i = name.lastIndexOf('.');
|
||||
+ if (i != -1) {
|
||||
+ String pkgname = name.substring(0, i);
|
||||
+ // Check if package already loaded.
|
||||
+ final @Nullable Manifest man = this.manifestFor(url);
|
||||
+ final URL jarUrl = URI.create(jarName(url)).toURL();
|
||||
+ if (this.getAndVerifyPackage(pkgname, man, jarUrl) == null) {
|
||||
+ try {
|
||||
+ if (man != null) {
|
||||
+ this.definePackage(pkgname, man, jarUrl);
|
||||
+ } else {
|
||||
+ this.definePackage(pkgname, null, null, null, null, null, null, null);
|
||||
+ }
|
||||
+ } catch (IllegalArgumentException iae) {
|
||||
+ // parallel-capable class loaders: re-verify in case of a
|
||||
+ // race condition
|
||||
+ if (this.getAndVerifyPackage(pkgname, man, jarUrl) == null) {
|
||||
+ // Should never happen
|
||||
+ throw new AssertionError("Cannot find package " +
|
||||
+ pkgname);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ final byte[] bytes;
|
||||
+ try (final InputStream is = url.openStream()) {
|
||||
+ bytes = is.readAllBytes();
|
||||
+ }
|
||||
+
|
||||
+ final byte[] modified = this.modifier.apply(bytes);
|
||||
+
|
||||
+ final CodeSource cs = new CodeSource(url, (CodeSigner[]) null);
|
||||
+ return this.defineClass(name, modified, 0, modified.length, cs);
|
||||
+ }
|
||||
+
|
||||
+ private Package getAndVerifyPackage(
|
||||
+ String pkgname,
|
||||
+ Manifest man, URL url
|
||||
+ ) {
|
||||
+ Package pkg = getDefinedPackage(pkgname);
|
||||
+ if (pkg != null) {
|
||||
+ // Package found, so check package sealing.
|
||||
+ if (pkg.isSealed()) {
|
||||
+ // Verify that code source URL is the same.
|
||||
+ if (!pkg.isSealed(url)) {
|
||||
+ throw new SecurityException(
|
||||
+ "sealing violation: package " + pkgname + " is sealed");
|
||||
+ }
|
||||
+ } else {
|
||||
+ // Make sure we are not attempting to seal the package
|
||||
+ // at this code source URL.
|
||||
+ if ((man != null) && this.isSealed(pkgname, man)) {
|
||||
+ throw new SecurityException(
|
||||
+ "sealing violation: can't seal package " + pkgname +
|
||||
+ ": already loaded");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return pkg;
|
||||
+ }
|
||||
+
|
||||
+ private boolean isSealed(String name, Manifest man) {
|
||||
+ Attributes attr = man.getAttributes(name.replace('.', '/').concat("/"));
|
||||
+ String sealed = null;
|
||||
+ if (attr != null) {
|
||||
+ sealed = attr.getValue(Attributes.Name.SEALED);
|
||||
+ }
|
||||
+ if (sealed == null) {
|
||||
+ if ((attr = man.getMainAttributes()) != null) {
|
||||
+ sealed = attr.getValue(Attributes.Name.SEALED);
|
||||
+ }
|
||||
+ }
|
||||
+ return "true".equalsIgnoreCase(sealed);
|
||||
+ }
|
||||
+
|
||||
+ private @Nullable Manifest manifestFor(final URL url) throws IOException {
|
||||
+ Manifest man = null;
|
||||
+ if (url.getProtocol().equals("jar")) {
|
||||
+ try {
|
||||
+ final Object computedManifest = this.manifests.computeIfAbsent(jarName(url), $ -> {
|
||||
+ try {
|
||||
+ final Manifest m = ((JarURLConnection) url.openConnection()).getManifest();
|
||||
+ return requireNonNullElse(m, MISSING_MANIFEST);
|
||||
+ } catch (final IOException e) {
|
||||
+ throw new UncheckedIOException(e);
|
||||
+ }
|
||||
+ });
|
||||
+ if (computedManifest instanceof Manifest found) {
|
||||
+ man = found;
|
||||
+ }
|
||||
+ } catch (final UncheckedIOException e) {
|
||||
+ throw e.getCause();
|
||||
+ } catch (final IllegalArgumentException e) {
|
||||
+ throw new IOException(e);
|
||||
+ }
|
||||
+ }
|
||||
+ return man;
|
||||
+ }
|
||||
+
|
||||
+ private static String jarName(final URL sourceUrl) {
|
||||
+ final int exclamationIdx = sourceUrl.getPath().lastIndexOf('!');
|
||||
+ if (exclamationIdx != -1) {
|
||||
+ return sourceUrl.getPath().substring(0, exclamationIdx);
|
||||
+ }
|
||||
+ throw new IllegalArgumentException("Could not find jar for URL " + sourceUrl);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperClassloaderBytecodeModifier.java b/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperClassloaderBytecodeModifier.java
|
||||
index f9a2c55a354c877749db3f92956de802ae575788..0e734c07dbe82ba4c319a237f9e79b08b57b997f 100644
|
||||
--- a/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperClassloaderBytecodeModifier.java
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperClassloaderBytecodeModifier.java
|
||||
@@ -7,6 +7,6 @@ public class PaperClassloaderBytecodeModifier implements ClassloaderBytecodeModi
|
||||
|
||||
@Override
|
||||
public byte[] modify(PluginMeta configuration, byte[] bytecode) {
|
||||
- return bytecode;
|
||||
+ return io.papermc.paper.pluginremap.reflect.ReflectionRemapper.processClass(bytecode);
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java b/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java
|
||||
index f576060c8fe872772bbafe2016fc9b83a3c095f1..f871a329eb52da077f58d0ceaaabd3349f84cad0 100644
|
||||
--- a/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java
|
||||
@@ -2,12 +2,12 @@ package io.papermc.paper.plugin.loader;
|
||||
|
||||
import io.papermc.paper.plugin.PluginInitializerManager;
|
||||
import io.papermc.paper.plugin.bootstrap.PluginProviderContext;
|
||||
+import io.papermc.paper.plugin.entrypoint.classloader.BytecodeModifyingURLClassLoader;
|
||||
+import io.papermc.paper.plugin.entrypoint.classloader.PaperPluginClassLoader;
|
||||
import io.papermc.paper.plugin.loader.library.ClassPathLibrary;
|
||||
import io.papermc.paper.plugin.loader.library.PaperLibraryStore;
|
||||
-import io.papermc.paper.plugin.entrypoint.classloader.PaperPluginClassLoader;
|
||||
import io.papermc.paper.plugin.provider.configuration.PaperPluginMeta;
|
||||
-import org.jetbrains.annotations.NotNull;
|
||||
-
|
||||
+import io.papermc.paper.util.MappingEnvironment;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
@@ -17,6 +17,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.logging.Logger;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PaperClasspathBuilder implements PluginClasspathBuilder {
|
||||
|
||||
@@ -60,7 +61,10 @@ public class PaperClasspathBuilder implements PluginClasspathBuilder {
|
||||
}
|
||||
|
||||
try {
|
||||
- return new PaperPluginClassLoader(logger, source, jarFile, configuration, this.getClass().getClassLoader(), new URLClassLoader(urls, getClass().getClassLoader()));
|
||||
+ final URLClassLoader libraryLoader = MappingEnvironment.DISABLE_PLUGIN_REMAPPING
|
||||
+ ? new URLClassLoader(urls, this.getClass().getClassLoader())
|
||||
+ : new BytecodeModifyingURLClassLoader(urls, this.getClass().getClassLoader());
|
||||
+ return new PaperPluginClassLoader(logger, source, jarFile, configuration, this.getClass().getClassLoader(), libraryLoader);
|
||||
} catch (IOException exception) {
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java b/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java
|
||||
index bdd9bc8a414719b9f1d6f01f90539ddb8603a878..1bf0fa1530b8e5f94d726d0313b7a00f675b500c 100644
|
||||
--- a/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java
|
||||
@@ -1,9 +1,12 @@
|
||||
package io.papermc.paper.plugin.provider.type.spigot;
|
||||
|
||||
+import io.papermc.paper.plugin.entrypoint.classloader.BytecodeModifyingURLClassLoader;
|
||||
import io.papermc.paper.plugin.provider.configuration.serializer.constraints.PluginConfigConstraints;
|
||||
import io.papermc.paper.plugin.provider.type.PluginTypeFactory;
|
||||
+import io.papermc.paper.util.MappingEnvironment;
|
||||
import org.bukkit.plugin.InvalidDescriptionException;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
+import org.bukkit.plugin.java.LibraryLoader;
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -15,6 +18,12 @@ import java.util.jar.JarFile;
|
||||
|
||||
class SpigotPluginProviderFactory implements PluginTypeFactory<SpigotPluginProvider, PluginDescriptionFile> {
|
||||
|
||||
+ static {
|
||||
+ if (!MappingEnvironment.DISABLE_PLUGIN_REMAPPING) {
|
||||
+ LibraryLoader.LIBRARY_LOADER_FACTORY = BytecodeModifyingURLClassLoader::new;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public SpigotPluginProvider build(JarFile file, PluginDescriptionFile configuration, Path source) throws InvalidDescriptionException {
|
||||
// Copied from SimplePluginManager#loadPlugins
|
||||
diff --git a/src/main/java/io/papermc/paper/pluginremap/reflect/PaperReflection.java b/src/main/java/io/papermc/paper/pluginremap/reflect/PaperReflection.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..92bc8e4933ff13764fa2ac7f3729216332e202c9
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/pluginremap/reflect/PaperReflection.java
|
||||
@@ -0,0 +1,211 @@
|
||||
+package io.papermc.paper.pluginremap.reflect;
|
||||
+
|
||||
+import com.mojang.logging.LogUtils;
|
||||
+import io.papermc.paper.util.MappingEnvironment;
|
||||
+import io.papermc.paper.util.ObfHelper;
|
||||
+import io.papermc.reflectionrewriter.runtime.AbstractDefaultRulesReflectionProxy;
|
||||
+import io.papermc.reflectionrewriter.runtime.DefineClassReflectionProxy;
|
||||
+import java.lang.invoke.MethodHandles;
|
||||
+import java.nio.ByteBuffer;
|
||||
+import java.security.CodeSource;
|
||||
+import java.security.ProtectionDomain;
|
||||
+import java.util.Map;
|
||||
+import java.util.Objects;
|
||||
+import java.util.stream.Collectors;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+import org.slf4j.Logger;
|
||||
+
|
||||
+// todo proper inheritance handling
|
||||
+@SuppressWarnings("unused")
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class PaperReflection extends AbstractDefaultRulesReflectionProxy implements DefineClassReflectionProxy {
|
||||
+ // concat to avoid being rewritten by shadow
|
||||
+ private static final Logger LOGGER = LogUtils.getLogger();
|
||||
+ private static final String CB_PACKAGE_PREFIX = "org.bukkit.".concat("craftbukkit.");
|
||||
+ private static final String LEGACY_CB_PACKAGE_PREFIX = "org.bukkit.".concat("craftbukkit.") + MappingEnvironment.LEGACY_CB_VERSION + ".";
|
||||
+
|
||||
+ private final DefineClassReflectionProxy defineClassProxy;
|
||||
+ private final Map<String, ObfHelper.ClassMapping> mappingsByMojangName;
|
||||
+ private final Map<String, ObfHelper.ClassMapping> mappingsByObfName;
|
||||
+ // Reflection does not care about method return values, so this map removes the return value descriptor from the key
|
||||
+ private final Map<String, Map<String, String>> strippedMethodMappings;
|
||||
+
|
||||
+ PaperReflection() {
|
||||
+ this.defineClassProxy = DefineClassReflectionProxy.create(PaperReflection::processClass);
|
||||
+ if (!MappingEnvironment.hasMappings()) {
|
||||
+ this.mappingsByMojangName = Map.of();
|
||||
+ this.mappingsByObfName = Map.of();
|
||||
+ this.strippedMethodMappings = Map.of();
|
||||
+ return;
|
||||
+ }
|
||||
+ final ObfHelper obfHelper = ObfHelper.INSTANCE;
|
||||
+ this.mappingsByMojangName = Objects.requireNonNull(obfHelper.mappingsByMojangName(), "mappingsByMojangName");
|
||||
+ this.mappingsByObfName = Objects.requireNonNull(obfHelper.mappingsByObfName(), "mappingsByObfName");
|
||||
+ this.strippedMethodMappings = this.mappingsByMojangName.entrySet().stream().collect(Collectors.toUnmodifiableMap(
|
||||
+ Map.Entry::getKey,
|
||||
+ entry -> entry.getValue().strippedMethods()
|
||||
+ ));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected String mapClassName(final String name) {
|
||||
+ final ObfHelper.@Nullable ClassMapping mapping = this.mappingsByObfName.get(name);
|
||||
+ return mapping != null ? mapping.mojangName() : removeCraftBukkitRelocation(name);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected String mapDeclaredMethodName(final Class<?> clazz, final String name, final Class<?> @Nullable ... parameterTypes) {
|
||||
+ final @Nullable Map<String, String> mapping = this.strippedMethodMappings.get(clazz.getName());
|
||||
+ if (mapping == null) {
|
||||
+ return name;
|
||||
+ }
|
||||
+ return mapping.getOrDefault(strippedMethodKey(name, parameterTypes), name);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected String mapMethodName(final Class<?> clazz, final String name, final Class<?> @Nullable ... parameterTypes) {
|
||||
+ final @Nullable String mapped = this.findMappedMethodName(clazz, name, parameterTypes);
|
||||
+ return mapped != null ? mapped : name;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected String mapDeclaredFieldName(final Class<?> clazz, final String name) {
|
||||
+ final ObfHelper.@Nullable ClassMapping mapping = this.mappingsByMojangName.get(clazz.getName());
|
||||
+ if (mapping == null) {
|
||||
+ return name;
|
||||
+ }
|
||||
+ return mapping.fieldsByObf().getOrDefault(name, name);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected String mapFieldName(final Class<?> clazz, final String name) {
|
||||
+ final @Nullable String mapped = this.findMappedFieldName(clazz, name);
|
||||
+ return mapped != null ? mapped : name;
|
||||
+ }
|
||||
+
|
||||
+ private @Nullable String findMappedMethodName(final Class<?> clazz, final String name, final Class<?> @Nullable ... parameterTypes) {
|
||||
+ final Map<String, String> map = this.strippedMethodMappings.get(clazz.getName());
|
||||
+ @Nullable String mapped = null;
|
||||
+ if (map != null) {
|
||||
+ mapped = map.get(strippedMethodKey(name, parameterTypes));
|
||||
+ if (mapped != null) {
|
||||
+ return mapped;
|
||||
+ }
|
||||
+ }
|
||||
+ // JVM checks super before interfaces
|
||||
+ final Class<?> superClass = clazz.getSuperclass();
|
||||
+ if (superClass != null) {
|
||||
+ mapped = this.findMappedMethodName(superClass, name, parameterTypes);
|
||||
+ }
|
||||
+ if (mapped == null) {
|
||||
+ for (final Class<?> i : clazz.getInterfaces()) {
|
||||
+ mapped = this.findMappedMethodName(i, name, parameterTypes);
|
||||
+ if (mapped != null) {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return mapped;
|
||||
+ }
|
||||
+
|
||||
+ private @Nullable String findMappedFieldName(final Class<?> clazz, final String name) {
|
||||
+ final ObfHelper.ClassMapping mapping = this.mappingsByMojangName.get(clazz.getName());
|
||||
+ @Nullable String mapped = null;
|
||||
+ if (mapping != null) {
|
||||
+ mapped = mapping.fieldsByObf().get(name);
|
||||
+ if (mapped != null) {
|
||||
+ return mapped;
|
||||
+ }
|
||||
+ }
|
||||
+ // The JVM checks super before interfaces
|
||||
+ final Class<?> superClass = clazz.getSuperclass();
|
||||
+ if (superClass != null) {
|
||||
+ mapped = this.findMappedFieldName(superClass, name);
|
||||
+ }
|
||||
+ if (mapped == null) {
|
||||
+ for (final Class<?> i : clazz.getInterfaces()) {
|
||||
+ mapped = this.findMappedFieldName(i, name);
|
||||
+ if (mapped != null) {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return mapped;
|
||||
+ }
|
||||
+
|
||||
+ private static String strippedMethodKey(final String methodName, final Class<?> @Nullable ... parameterTypes) {
|
||||
+ return methodName + parameterDescriptor(parameterTypes);
|
||||
+ }
|
||||
+
|
||||
+ private static String parameterDescriptor(final Class<?> @Nullable ... parameterTypes) {
|
||||
+ if (parameterTypes == null) {
|
||||
+ // Null parameterTypes is treated as an empty array
|
||||
+ return "()";
|
||||
+ }
|
||||
+ final StringBuilder builder = new StringBuilder();
|
||||
+ builder.append('(');
|
||||
+ for (final Class<?> parameterType : parameterTypes) {
|
||||
+ builder.append(parameterType.descriptorString());
|
||||
+ }
|
||||
+ builder.append(')');
|
||||
+ return builder.toString();
|
||||
+ }
|
||||
+
|
||||
+ private static String removeCraftBukkitRelocation(final String name) {
|
||||
+ if (MappingEnvironment.hasMappings()) {
|
||||
+ // Relocation is applied in reobf, and when mappings are present they handle the relocation
|
||||
+ return name;
|
||||
+ }
|
||||
+ if (name.startsWith(LEGACY_CB_PACKAGE_PREFIX)) {
|
||||
+ return CB_PACKAGE_PREFIX + name.substring(LEGACY_CB_PACKAGE_PREFIX.length());
|
||||
+ }
|
||||
+ return name;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Class<?> defineClass(final Object loader, final byte[] b, final int off, final int len) throws ClassFormatError {
|
||||
+ return this.defineClassProxy.defineClass(loader, b, off, len);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Class<?> defineClass(final Object loader, final String name, final byte[] b, final int off, final int len) throws ClassFormatError {
|
||||
+ return this.defineClassProxy.defineClass(loader, name, b, off, len);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Class<?> defineClass(final Object loader, final @Nullable String name, final byte[] b, final int off, final int len, final @Nullable ProtectionDomain protectionDomain) throws ClassFormatError {
|
||||
+ return this.defineClassProxy.defineClass(loader, name, b, off, len, protectionDomain);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Class<?> defineClass(final Object loader, final String name, final ByteBuffer b, final ProtectionDomain protectionDomain) throws ClassFormatError {
|
||||
+ return this.defineClassProxy.defineClass(loader, name, b, protectionDomain);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Class<?> defineClass(final Object secureLoader, final String name, final byte[] b, final int off, final int len, final CodeSource cs) {
|
||||
+ return this.defineClassProxy.defineClass(secureLoader, name, b, off, len, cs);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Class<?> defineClass(final Object secureLoader, final String name, final ByteBuffer b, final CodeSource cs) {
|
||||
+ return this.defineClassProxy.defineClass(secureLoader, name, b, cs);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Class<?> defineClass(final MethodHandles.Lookup lookup, final byte[] bytes) throws IllegalAccessException {
|
||||
+ return this.defineClassProxy.defineClass(lookup, bytes);
|
||||
+ }
|
||||
+
|
||||
+ // todo apply bytecode remap here as well
|
||||
+ private static byte[] processClass(final byte[] bytes) {
|
||||
+ try {
|
||||
+ return ReflectionRemapper.processClass(bytes);
|
||||
+ } catch (final Exception ex) {
|
||||
+ LOGGER.warn("Failed to process class bytes", ex);
|
||||
+ return bytes;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/pluginremap/reflect/ReflectionRemapper.java b/src/main/java/io/papermc/paper/pluginremap/reflect/ReflectionRemapper.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..a3045afbc0cc057e99189b909367b21cf6a9e03f
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/pluginremap/reflect/ReflectionRemapper.java
|
||||
@@ -0,0 +1,66 @@
|
||||
+package io.papermc.paper.pluginremap.reflect;
|
||||
+
|
||||
+import io.papermc.asm.ClassInfoProvider;
|
||||
+import io.papermc.asm.RewriteRuleVisitorFactory;
|
||||
+import io.papermc.paper.util.MappingEnvironment;
|
||||
+import io.papermc.reflectionrewriter.BaseReflectionRules;
|
||||
+import io.papermc.reflectionrewriter.DefineClassRule;
|
||||
+import io.papermc.reflectionrewriter.proxygenerator.ProxyGenerator;
|
||||
+import java.lang.invoke.MethodHandles;
|
||||
+import java.lang.reflect.Method;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+import org.objectweb.asm.ClassReader;
|
||||
+import org.objectweb.asm.ClassVisitor;
|
||||
+import org.objectweb.asm.ClassWriter;
|
||||
+import org.objectweb.asm.Opcodes;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class ReflectionRemapper {
|
||||
+ private static final String PAPER_REFLECTION_HOLDER = "io.papermc.paper.pluginremap.reflect.PaperReflectionHolder";
|
||||
+ private static final String PAPER_REFLECTION_HOLDER_DESC = PAPER_REFLECTION_HOLDER.replace('.', '/');
|
||||
+ private static final RewriteRuleVisitorFactory VISITOR_FACTORY = RewriteRuleVisitorFactory.create(
|
||||
+ Opcodes.ASM9,
|
||||
+ chain -> chain.then(new BaseReflectionRules(PAPER_REFLECTION_HOLDER).rules())
|
||||
+ .then(DefineClassRule.create(PAPER_REFLECTION_HOLDER_DESC, true)),
|
||||
+ ClassInfoProvider.basic()
|
||||
+ );
|
||||
+
|
||||
+ static {
|
||||
+ if (!MappingEnvironment.reobf()) {
|
||||
+ setupProxy();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private ReflectionRemapper() {
|
||||
+ }
|
||||
+
|
||||
+ public static ClassVisitor visitor(final ClassVisitor parent) {
|
||||
+ if (MappingEnvironment.reobf() || MappingEnvironment.DISABLE_PLUGIN_REMAPPING) {
|
||||
+ return parent;
|
||||
+ }
|
||||
+ return VISITOR_FACTORY.createVisitor(parent);
|
||||
+ }
|
||||
+
|
||||
+ public static byte[] processClass(final byte[] bytes) {
|
||||
+ if (MappingEnvironment.DISABLE_PLUGIN_REMAPPING) {
|
||||
+ return bytes;
|
||||
+ }
|
||||
+ final ClassReader classReader = new ClassReader(bytes);
|
||||
+ final ClassWriter classWriter = new ClassWriter(classReader, 0);
|
||||
+ classReader.accept(ReflectionRemapper.visitor(classWriter), 0);
|
||||
+ return classWriter.toByteArray();
|
||||
+ }
|
||||
+
|
||||
+ private static void setupProxy() {
|
||||
+ try {
|
||||
+ final byte[] bytes = ProxyGenerator.generateProxy(PaperReflection.class, PAPER_REFLECTION_HOLDER_DESC);
|
||||
+ final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
+ final Class<?> generated = lookup.defineClass(bytes);
|
||||
+ final Method init = generated.getDeclaredMethod("init", PaperReflection.class);
|
||||
+ init.invoke(null, new PaperReflection());
|
||||
+ } catch (final ReflectiveOperationException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/util/MappingEnvironment.java b/src/main/java/io/papermc/paper/util/MappingEnvironment.java
|
||||
index 8e4229634d41a42b3d93948eebb77def7c0c72b1..fb6aa9e2575b22e3089ea7fb32e6abfa6bb07d18 100644
|
||||
--- a/src/main/java/io/papermc/paper/util/MappingEnvironment.java
|
||||
+++ b/src/main/java/io/papermc/paper/util/MappingEnvironment.java
|
||||
@@ -10,6 +10,8 @@ import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
public final class MappingEnvironment {
|
||||
+ public static final boolean DISABLE_PLUGIN_REMAPPING = Boolean.getBoolean("paper.disablePluginRemapping");
|
||||
+ public static final String LEGACY_CB_VERSION = "v1_21_R1";
|
||||
private static final @Nullable String MAPPINGS_HASH = readMappingsHash();
|
||||
private static final boolean REOBF = checkReobf();
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java
|
||||
index 242811578a786e3807a1a7019d472d5a68f87116..0b65fdf53124f3dd042b2363b1b8df8e1ca7de00 100644
|
||||
--- a/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java
|
||||
+++ b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java
|
||||
@@ -29,6 +29,9 @@ public enum StacktraceDeobfuscator {
|
||||
});
|
||||
|
||||
public void deobfuscateThrowable(final Throwable throwable) {
|
||||
+ if (!MappingEnvironment.reobf()) {
|
||||
+ return;
|
||||
+ }
|
||||
if (GlobalConfiguration.get() != null && !GlobalConfiguration.get().logging.deobfuscateStacktraces) { // handle null as true
|
||||
return;
|
||||
}
|
||||
@@ -44,6 +47,9 @@ public enum StacktraceDeobfuscator {
|
||||
}
|
||||
|
||||
public StackTraceElement[] deobfuscateStacktrace(final StackTraceElement[] traceElements) {
|
||||
+ if (!MappingEnvironment.reobf()) {
|
||||
+ return traceElements;
|
||||
+ }
|
||||
if (GlobalConfiguration.get() != null && !GlobalConfiguration.get().logging.deobfuscateStacktraces) { // handle null as true
|
||||
return traceElements;
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java
|
||||
index 2a29f60c3e82239ab7acd85242fc3390cb9129cd..91c6721201b095eb32c5fd5a1aaf2cbcf3ee196d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java
|
||||
@@ -126,36 +126,26 @@ public class Commodore {
|
||||
}
|
||||
|
||||
// Paper start - Plugin rewrites
|
||||
- private static final Map<String, String> SEARCH_AND_REMOVE = initReplacementsMap();
|
||||
- private static Map<String, String> initReplacementsMap() {
|
||||
- Map<String, String> getAndRemove = new HashMap<>();
|
||||
- // Be wary of maven shade's relocations
|
||||
-
|
||||
- final java.util.jar.Manifest manifest = io.papermc.paper.util.JarManifests.manifest(Commodore.class);
|
||||
- if (Boolean.getBoolean( "debug.rewriteForIde") && manifest != null)
|
||||
- {
|
||||
- // unversion incoming calls for pre-relocate debug work
|
||||
- final String NMS_REVISION_PACKAGE = "v" + manifest.getMainAttributes().getValue("CraftBukkit-Package-Version") + "/";
|
||||
-
|
||||
- getAndRemove.put("org/bukkit/".concat("craftbukkit/" + NMS_REVISION_PACKAGE), NMS_REVISION_PACKAGE);
|
||||
+ private static final String CB_PACKAGE_PREFIX = "org/bukkit/".concat("craftbukkit/");
|
||||
+ private static final String LEGACY_CB_PACKAGE_PREFIX = CB_PACKAGE_PREFIX + io.papermc.paper.util.MappingEnvironment.LEGACY_CB_VERSION + "/";
|
||||
+ private static String runtimeCbPkgPrefix() {
|
||||
+ if (io.papermc.paper.util.MappingEnvironment.reobf()) {
|
||||
+ return LEGACY_CB_PACKAGE_PREFIX;
|
||||
}
|
||||
-
|
||||
- return getAndRemove;
|
||||
+ return CB_PACKAGE_PREFIX;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static String getOriginalOrRewrite(@Nonnull String original)
|
||||
{
|
||||
- String rewrite = null;
|
||||
- for ( Map.Entry<String, String> entry : SEARCH_AND_REMOVE.entrySet() )
|
||||
- {
|
||||
- if ( original.contains( entry.getKey() ) )
|
||||
- {
|
||||
- rewrite = original.replace( entry.getValue(), "" );
|
||||
+ // Relocation is applied in reobf, and when mappings are present they handle the relocation
|
||||
+ if (!io.papermc.paper.util.MappingEnvironment.reobf() && !io.papermc.paper.util.MappingEnvironment.hasMappings()) {
|
||||
+ if (original.contains(LEGACY_CB_PACKAGE_PREFIX)) {
|
||||
+ original = original.replace(LEGACY_CB_PACKAGE_PREFIX, CB_PACKAGE_PREFIX);
|
||||
}
|
||||
}
|
||||
|
||||
- return rewrite != null ? rewrite : original;
|
||||
+ return original;
|
||||
}
|
||||
// Paper end - Plugin rewrites
|
||||
|
||||
@@ -240,6 +230,7 @@ public class Commodore {
|
||||
visitor = new LimitedClassRemapper(cw, new SimpleRemapper(Commodore.ENUM_RENAMES));
|
||||
}
|
||||
|
||||
+ visitor = io.papermc.paper.pluginremap.reflect.ReflectionRemapper.visitor(visitor); // Paper
|
||||
cr.accept(new ClassRemapper(new ClassVisitor(Opcodes.ASM9, visitor) {
|
||||
final Set<RerouteMethodData> rerouteMethodData = new HashSet<>();
|
||||
String className;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index a339a0aa6fd7cc7be810e93bc9eb192437519c75..33d3085d0d44d748fcb1fc203dfd14c9e1b4aff0 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -74,6 +74,7 @@ import org.bukkit.potion.PotionType;
|
||||
@SuppressWarnings("deprecation")
|
||||
public final class CraftMagicNumbers implements UnsafeValues {
|
||||
public static final CraftMagicNumbers INSTANCE = new CraftMagicNumbers();
|
||||
+ public static final boolean DISABLE_OLD_API_SUPPORT = Boolean.getBoolean("paper.disableOldApiSupport"); // Paper
|
||||
|
||||
private final Commodore commodore = new Commodore();
|
||||
|
||||
@@ -346,7 +347,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
throw new InvalidPluginException("Plugin API version " + pdf.getAPIVersion() + " is lower than the minimum allowed version. Please update or replace it.");
|
||||
}
|
||||
|
||||
- if (toCheck.isOlderThan(ApiVersion.FLATTENING)) {
|
||||
+ if (!DISABLE_OLD_API_SUPPORT && toCheck.isOlderThan(ApiVersion.FLATTENING)) { // Paper
|
||||
CraftLegacy.init();
|
||||
}
|
||||
|
||||
@@ -361,6 +362,12 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
|
||||
@Override
|
||||
public byte[] processClass(PluginDescriptionFile pdf, String path, byte[] clazz) {
|
||||
+ // Paper start
|
||||
+ if (DISABLE_OLD_API_SUPPORT) {
|
||||
+ // Make sure we still go through our reflection rewriting if needed
|
||||
+ return io.papermc.paper.pluginremap.reflect.ReflectionRemapper.processClass(clazz);
|
||||
+ }
|
||||
+ // Paper end
|
||||
try {
|
||||
clazz = this.commodore.convert(clazz, pdf.getName(), ApiVersion.getOrCreateVersion(pdf.getAPIVersion()), ((CraftServer) Bukkit.getServer()).activeCompatibilities);
|
||||
} catch (Exception ex) {
|
File diff suppressed because it is too large
Load diff
|
@ -1,233 +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 49de4625c57689a3624ed421c0b03512507c97c3..46e03617bb32e4037d700c1b3698d397bd75de5c 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -296,7 +296,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public org.bukkit.craftbukkit.CraftServer server;
|
||||
public OptionSet options;
|
||||
public org.bukkit.command.ConsoleCommandSender console;
|
||||
- public static int currentTick = (int) (System.currentTimeMillis() / 50);
|
||||
+ public static int currentTick; // Paper - improve tick loop
|
||||
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
|
||||
public int autosavePeriod;
|
||||
public Commands vanillaCommandDispatcher;
|
||||
@@ -305,7 +305,8 @@ 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 - improve server tick loop
|
||||
+ @Deprecated(forRemoval = true) // Paper
|
||||
public final double[] recentTps = new double[ 3 ];
|
||||
// Spigot end
|
||||
public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations; // Paper - add paper configuration files
|
||||
@@ -1019,6 +1020,57 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
{
|
||||
return ( avg * exp ) + ( tps * ( 1 - exp ) );
|
||||
}
|
||||
+
|
||||
+ // Paper start - Further improve server tick loop
|
||||
+ private static final long SEC_IN_NANO = 1000000000;
|
||||
+ private static final long MAX_CATCHUP_BUFFER = TICK_TIME * TPS * 60L;
|
||||
+ private long lastTick = 0;
|
||||
+ private long catchupTime = 0;
|
||||
+ public final RollingAverage tps1 = new RollingAverage(60);
|
||||
+ public final RollingAverage tps5 = new RollingAverage(60 * 5);
|
||||
+ public final RollingAverage tps15 = new RollingAverage(60 * 15);
|
||||
+
|
||||
+ public static class RollingAverage {
|
||||
+ private final int size;
|
||||
+ private long time;
|
||||
+ private java.math.BigDecimal total;
|
||||
+ private int index = 0;
|
||||
+ private final java.math.BigDecimal[] samples;
|
||||
+ private final long[] times;
|
||||
+
|
||||
+ RollingAverage(int size) {
|
||||
+ this.size = size;
|
||||
+ this.time = size * SEC_IN_NANO;
|
||||
+ this.total = dec(TPS).multiply(dec(SEC_IN_NANO)).multiply(dec(size));
|
||||
+ this.samples = new java.math.BigDecimal[size];
|
||||
+ this.times = new long[size];
|
||||
+ for (int i = 0; i < size; i++) {
|
||||
+ this.samples[i] = dec(TPS);
|
||||
+ this.times[i] = SEC_IN_NANO;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static java.math.BigDecimal dec(long t) {
|
||||
+ return new java.math.BigDecimal(t);
|
||||
+ }
|
||||
+ public void add(java.math.BigDecimal x, long t) {
|
||||
+ time -= times[index];
|
||||
+ total = total.subtract(samples[index].multiply(dec(times[index])));
|
||||
+ samples[index] = x;
|
||||
+ times[index] = t;
|
||||
+ time += t;
|
||||
+ total = total.add(x.multiply(dec(t)));
|
||||
+ if (++index == size) {
|
||||
+ index = 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public double getAverage() {
|
||||
+ return total.divide(dec(time), 30, java.math.RoundingMode.HALF_UP).doubleValue();
|
||||
+ }
|
||||
+ }
|
||||
+ private static final java.math.BigDecimal TPS_BASE = new java.math.BigDecimal(1E9).multiply(new java.math.BigDecimal(SAMPLE_INTERVAL));
|
||||
+ // Paper end
|
||||
// Spigot End
|
||||
|
||||
protected void runServer() {
|
||||
@@ -1033,7 +1085,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
// Spigot start
|
||||
Arrays.fill( this.recentTps, 20 );
|
||||
- long tickSection = Util.getMillis(), tickCount = 1;
|
||||
+ // Paper start - further improve server tick loop
|
||||
+ long tickSection = Util.getNanos();
|
||||
+ long currentTime;
|
||||
+ // Paper end - further improve server tick loop
|
||||
while (this.running) {
|
||||
long i;
|
||||
|
||||
@@ -1055,15 +1110,22 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
}
|
||||
// Spigot start
|
||||
- if ( tickCount++ % MinecraftServer.SAMPLE_INTERVAL == 0 )
|
||||
- {
|
||||
- long curTime = Util.getMillis();
|
||||
- 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)
|
||||
- tickSection = curTime;
|
||||
+ // Paper start - further improve server tick loop
|
||||
+ currentTime = Util.getNanos();
|
||||
+ if (++MinecraftServer.currentTick % MinecraftServer.SAMPLE_INTERVAL == 0) {
|
||||
+ final long diff = currentTime - tickSection;
|
||||
+ final java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP);
|
||||
+ 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();
|
||||
+ tickSection = currentTime;
|
||||
}
|
||||
+ // Paper end - further improve server tick loop
|
||||
// Spigot end
|
||||
|
||||
boolean flag = i == 0L;
|
||||
@@ -1073,7 +1135,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 = currentTime;
|
||||
this.nextTickTimeNanos += i;
|
||||
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 0fda501dedcc1f3f7d35e3b66a4b40394c4b3cb5..2c3efcf07f933278a8b897cf7b1f6f24b452a7c5 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2672,7 +2672,11 @@ public final class CraftServer implements Server {
|
||||
|
||||
@Override
|
||||
public double[] getTPS() {
|
||||
- return new double[]{0, 0, 0}; // TODO
|
||||
+ 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 start - adventure sounds
|
||||
diff --git a/src/main/java/org/spigotmc/TicksPerSecondCommand.java b/src/main/java/org/spigotmc/TicksPerSecondCommand.java
|
||||
index d9ec48be0fdd2bfea938aa29e36b0f6ffa839ab2..9eb2823cc8f83bad2626fc77578b0162d9ed5782 100644
|
||||
--- a/src/main/java/org/spigotmc/TicksPerSecondCommand.java
|
||||
+++ b/src/main/java/org/spigotmc/TicksPerSecondCommand.java
|
||||
@@ -15,6 +15,12 @@ public class TicksPerSecondCommand extends Command
|
||||
this.usageMessage = "/tps";
|
||||
this.setPermission( "bukkit.command.tps" );
|
||||
}
|
||||
+ // Paper start
|
||||
+ private static final net.kyori.adventure.text.Component WARN_MSG = net.kyori.adventure.text.Component.text()
|
||||
+ .append(net.kyori.adventure.text.Component.text("Warning: ", net.kyori.adventure.text.format.NamedTextColor.RED))
|
||||
+ .append(net.kyori.adventure.text.Component.text("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.", net.kyori.adventure.text.format.NamedTextColor.GOLD))
|
||||
+ .build();
|
||||
+ // Paper end
|
||||
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, String currentAlias, String[] args)
|
||||
@@ -24,22 +30,40 @@ 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();
|
||||
+ net.kyori.adventure.text.Component[] tpsAvg = new net.kyori.adventure.text.Component[tps.length];
|
||||
+
|
||||
+ for ( int i = 0; i < tps.length; i++) {
|
||||
+ tpsAvg[i] = TicksPerSecondCommand.format( tps[i] );
|
||||
+ }
|
||||
+
|
||||
+ net.kyori.adventure.text.TextComponent.Builder builder = net.kyori.adventure.text.Component.text();
|
||||
+ builder.append(net.kyori.adventure.text.Component.text("TPS from last 1m, 5m, 15m: ", net.kyori.adventure.text.format.NamedTextColor.GOLD));
|
||||
+ builder.append(net.kyori.adventure.text.Component.join(net.kyori.adventure.text.JoinConfiguration.commas(true), tpsAvg));
|
||||
+ sender.sendMessage(builder.asComponent());
|
||||
+ if (args.length > 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) {
|
||||
+ sender.sendMessage(net.kyori.adventure.text.Component.text()
|
||||
+ .append(net.kyori.adventure.text.Component.text("Current Memory Usage: ", net.kyori.adventure.text.format.NamedTextColor.GOLD))
|
||||
+ .append(net.kyori.adventure.text.Component.text(((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)", net.kyori.adventure.text.format.NamedTextColor.GREEN))
|
||||
+ );
|
||||
+ if (!this.hasShownMemoryWarning) {
|
||||
+ sender.sendMessage(WARN_MSG);
|
||||
+ this.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 net.kyori.adventure.text.Component 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 );
|
||||
+ // Paper
|
||||
+ net.kyori.adventure.text.format.TextColor color = ( ( tps > 18.0 ) ? net.kyori.adventure.text.format.NamedTextColor.GREEN : ( tps > 16.0 ) ? net.kyori.adventure.text.format.NamedTextColor.YELLOW : net.kyori.adventure.text.format.NamedTextColor.RED );
|
||||
+ String amount = Math.min(Math.round(tps * 100.0) / 100.0, 20.0) + (tps > 21.0 ? "*" : ""); // Paper - only print * at 21, we commonly peak to 20.02 as the tick sleep is not accurate enough, stop the noise
|
||||
+ return net.kyori.adventure.text.Component.text(amount, color);
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
|
@ -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 2c3efcf07f933278a8b897cf7b1f6f24b452a7c5..b8b2e582115cc42a913b03a35861fa810d774cbb 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -459,6 +459,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 this.console.getPluginsFolder();
|
||||
+ }
|
||||
+
|
||||
+ 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 bdb8e882ec1efbe5afec9ec5a5df57bf38d4ba2b..034d68c2715b6a90f31e56f949ff3d27235a26eb 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -160,6 +160,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
|
||||
}
|
||||
};
|
|
@ -1,83 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MiniDigger <admin@benndorf.dev>
|
||||
Date: Sat, 6 Jun 2020 18:13:42 +0200
|
||||
Subject: [PATCH] Support components in ItemMeta
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
index 0c73854243f7fa21d1ffdb3b4c85ee0a69c9c5e4..f6ac13f91f08498a8adda7d34518a5cfe34c15b2 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
@@ -978,11 +978,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
return CraftChatMessage.fromComponent(this.displayName);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public net.md_5.bungee.api.chat.BaseComponent[] getDisplayNameComponent() {
|
||||
+ return displayName == null ? new net.md_5.bungee.api.chat.BaseComponent[0] : net.md_5.bungee.chat.ComponentSerializer.parse(CraftChatMessage.toJSON(displayName));
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public final void setDisplayName(String name) {
|
||||
this.displayName = CraftChatMessage.fromStringOrNull(name);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void setDisplayNameComponent(net.md_5.bungee.api.chat.BaseComponent[] component) {
|
||||
+ this.displayName = CraftChatMessage.fromJSON(net.md_5.bungee.chat.ComponentSerializer.toString(component));
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public boolean hasDisplayName() {
|
||||
return this.displayName != null;
|
||||
@@ -1156,6 +1168,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
return this.lore == null ? null : new ArrayList<String>(Lists.transform(this.lore, CraftChatMessage::fromComponent));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public List<net.md_5.bungee.api.chat.BaseComponent[]> getLoreComponents() {
|
||||
+ return this.lore == null ? null : new ArrayList<>(this.lore.stream().map(entry ->
|
||||
+ net.md_5.bungee.chat.ComponentSerializer.parse(CraftChatMessage.toJSON(entry))
|
||||
+ ).collect(java.util.stream.Collectors.toList()));
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public void setLore(List<String> lore) {
|
||||
if (lore == null || lore.isEmpty()) {
|
||||
@@ -1170,6 +1190,21 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void setLoreComponents(List<net.md_5.bungee.api.chat.BaseComponent[]> lore) {
|
||||
+ if (lore == null) {
|
||||
+ this.lore = null;
|
||||
+ } else {
|
||||
+ if (this.lore == null) {
|
||||
+ safelyAdd(lore, this.lore = new ArrayList<>(lore.size()), false);
|
||||
+ } else {
|
||||
+ this.lore.clear();
|
||||
+ safelyAdd(lore, this.lore, false);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public boolean hasCustomModelData() {
|
||||
return this.customModelData != null;
|
||||
@@ -1882,6 +1917,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
}
|
||||
|
||||
for (Object object : addFrom) {
|
||||
+ // Paper start - support components
|
||||
+ if(object instanceof net.md_5.bungee.api.chat.BaseComponent[] baseComponentArr) {
|
||||
+ addTo.add(CraftChatMessage.fromJSON(net.md_5.bungee.chat.ComponentSerializer.toString(baseComponentArr)));
|
||||
+ } else
|
||||
+ // Paper end
|
||||
if (!(object instanceof String)) {
|
||||
if (object != null) {
|
||||
// SPIGOT-7399: Null check via if is important,
|
|
@ -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 height
|
||||
|
||||
Bamboo - Both the minimum fully-grown height 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 eda75b316acd09120539c92ff8adb97d92e9523f..e2951dd077441fe9cda461a2d3ef0c0671308316 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/BambooStalkBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/BambooStalkBlock.java
|
||||
@@ -137,7 +137,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 - Configurable cactus/bamboo/reed growth height
|
||||
this.growBamboo(state, world, pos, random, i);
|
||||
}
|
||||
}
|
||||
@@ -168,7 +168,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 - Configurable cactus/bamboo/reed growth height
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -187,7 +187,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/reed growth height
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -228,7 +228,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 - Configurable cactus/bamboo/reed growth height
|
||||
|
||||
// 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)) {
|
||||
@@ -243,7 +243,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 - Configurable cactus/bamboo/reed growth height
|
||||
;
|
||||
}
|
||||
|
||||
@@ -253,7 +253,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 - Configurable cactus/bamboo/reed growth height
|
||||
;
|
||||
}
|
||||
|
||||
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 c7e462a187196da906aec3b528f7945afec9f6b0..fd344c5cf0d6d523abe34d5e3f8d939106942cbb 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/CactusBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/CactusBlock.java
|
||||
@@ -61,7 +61,7 @@ public class CactusBlock extends Block {
|
||||
;
|
||||
}
|
||||
|
||||
- if (i < 3) {
|
||||
+ if (i < world.paperConfig().maxGrowthHeight.cactus) { // Paper - Configurable cactus/bamboo/reed 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 f034a7dbc0124353f8cb9b2c841226e73d83423a..c48c622e92cedeaa46b929c7adfedec98dd5a3fb 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
|
||||
@@ -59,7 +59,7 @@ public class SugarCaneBlock extends Block {
|
||||
;
|
||||
}
|
||||
|
||||
- if (i < 3) {
|
||||
+ if (i < world.paperConfig().maxGrowthHeight.reeds) { // Paper - Configurable cactus/bamboo/reed growth heigh
|
||||
int j = (Integer) state.getValue(SugarCaneBlock.AGE);
|
||||
|
||||
int modifier = world.spigotConfig.caneModifier; // Spigot - SPIGOT-7159: Better modifier resolution
|
|
@ -1,31 +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 60a9db4131bcf69a33003b83db6117c9a7a83276..393a9c704f4637a0e8031328d2a0facef4723dd8 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
@@ -75,7 +75,7 @@ import org.bukkit.event.entity.EntityTransformEvent;
|
||||
public class Zombie extends Monster {
|
||||
|
||||
private static final ResourceLocation SPEED_MODIFIER_BABY_ID = ResourceLocation.withDefaultNamespace("baby");
|
||||
- private static final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_ID, 0.5D, AttributeModifier.Operation.ADD_MULTIPLIED_BASE);
|
||||
+ private final AttributeModifier babyModifier = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_ID, this.level().paperConfig().entities.behavior.babyZombieMovementModifier, AttributeModifier.Operation.ADD_MULTIPLIED_BASE); // Paper - Make baby speed configurable
|
||||
private static final ResourceLocation REINFORCEMENT_CALLER_CHARGE_ID = ResourceLocation.withDefaultNamespace("reinforcement_caller_charge");
|
||||
private static final AttributeModifier ZOMBIE_REINFORCEMENT_CALLEE_CHARGE = new AttributeModifier(ResourceLocation.withDefaultNamespace("reinforcement_callee_charge"), -0.05000000074505806D, AttributeModifier.Operation.ADD_VALUE);
|
||||
private static final ResourceLocation LEADER_ZOMBIE_BONUS_ID = ResourceLocation.withDefaultNamespace("leader_zombie_bonus");
|
||||
@@ -188,9 +188,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_ID);
|
||||
+ attributemodifiable.removeModifier(this.babyModifier.id()); // Paper - Make baby speed configurable
|
||||
if (baby) {
|
||||
- attributemodifiable.addTransientModifier(Zombie.SPEED_MODIFIER_BABY);
|
||||
+ attributemodifiable.addTransientModifier(this.babyModifier); // Paper - Make baby speed configurable
|
||||
}
|
||||
}
|
||||
|
|
@ -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 0acb45014039d4392988c7d853595f96e856af4a..ed43ad94ca007a54e3c32d5e17c141048eeb5835 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
|
||||
@@ -94,6 +94,10 @@ public class FishingHook extends Projectile {
|
||||
this.noCulling = true;
|
||||
this.luck = Math.max(0, luckBonus);
|
||||
this.lureSpeed = Math.max(0, waitTimeReductionTicks);
|
||||
+ // Paper start - Configurable fishing time ranges
|
||||
+ minWaitTime = world.paperConfig().fishingTimeRange.minimum;
|
||||
+ maxWaitTime = world.paperConfig().fishingTimeRange.maximum;
|
||||
+ // Paper end - Configurable fishing time ranges
|
||||
}
|
||||
|
||||
public FishingHook(EntityType<? extends FishingHook> type, Level world) {
|
||||
@@ -411,7 +415,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 : 0;
|
||||
+ this.timeUntilLured -= (this.applyLure) ? (this.lureSpeed >= this.maxWaitTime ? this.timeUntilLured - 1 : this.lureSpeed ) : 0; // Paper - Fix Lure infinite loop
|
||||
// CraftBukkit end
|
||||
}
|
||||
}
|
|
@ -1,47 +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
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
index 930b5002aa6eaa1137314f7b38fad99778b6edaa..0593d828c911c94c9833bf12b9c294e5dac1f4e8 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
@@ -124,6 +124,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
private final BodyRotationControl bodyRotationControl;
|
||||
protected PathNavigation navigation;
|
||||
public GoalSelector goalSelector;
|
||||
+ @Nullable public net.minecraft.world.entity.ai.goal.FloatGoal goalFloat; // Paper - Allow nerfed mobs to jump and float
|
||||
public GoalSelector targetSelector;
|
||||
@Nullable
|
||||
private LivingEntity target;
|
||||
@@ -888,7 +889,15 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
@Override
|
||||
protected final void serverAiStep() {
|
||||
++this.noActionTime;
|
||||
- if (!this.aware) return; // CraftBukkit
|
||||
+ // Paper start - Allow nerfed mobs to jump and float
|
||||
+ if (!this.aware) {
|
||||
+ if (goalFloat != null) {
|
||||
+ if (goalFloat.canUse()) goalFloat.tick();
|
||||
+ this.getJumpControl().tick();
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Allow nerfed mobs to jump and float
|
||||
ProfilerFiller gameprofilerfiller = this.level().getProfiler();
|
||||
|
||||
gameprofilerfiller.push("sensing");
|
||||
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 5fbb5d2bf8945a361babfe50f5f92fa46b9e8b5f..7eb0e0486203d9ad6ce89d17a4da96a7563088a4 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 - Allow nerfed mobs to jump and float
|
||||
this.setFlags(EnumSet.of(Goal.Flag.JUMP));
|
||||
mob.getNavigation().setCanFloat(true);
|
||||
}
|
|
@ -1,47 +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 entity despawn distances
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
index 0593d828c911c94c9833bf12b9c294e5dac1f4e8..02c8c52930640114592148fd5509ad8fffee5435 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
@@ -863,20 +863,24 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
Player entityhuman = this.level().getNearestPlayer(this, -1.0D);
|
||||
|
||||
if (entityhuman != null) {
|
||||
- double d0 = entityhuman.distanceToSqr((Entity) this);
|
||||
- int i = this.getType().getCategory().getDespawnDistance();
|
||||
- int j = i * i;
|
||||
-
|
||||
- if (d0 > (double) j && this.removeWhenFarAway(d0)) {
|
||||
+ // Paper start - Configurable despawn distances
|
||||
+ final io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DespawnRangePair despawnRangePair = this.level().paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory());
|
||||
+ final io.papermc.paper.configuration.type.DespawnRange.Shape shape = this.level().paperConfig().entities.spawning.despawnRangeShape;
|
||||
+ final double dy = Math.abs(entityhuman.getY() - this.getY());
|
||||
+ final double dySqr = Math.pow(dy, 2);
|
||||
+ final double dxSqr = Math.pow(entityhuman.getX() - this.getX(), 2);
|
||||
+ final double dzSqr = Math.pow(entityhuman.getZ() - this.getZ(), 2);
|
||||
+ final double distanceSquared = dxSqr + dzSqr + dySqr;
|
||||
+ // Despawn if hard/soft limit is exceeded
|
||||
+ if (despawnRangePair.hard().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy) && this.removeWhenFarAway(distanceSquared)) {
|
||||
this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||
}
|
||||
-
|
||||
- int k = this.getType().getCategory().getNoDespawnDistance();
|
||||
- int l = k * k;
|
||||
-
|
||||
- if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d0 > (double) l && this.removeWhenFarAway(d0)) {
|
||||
- this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||
- } else if (d0 < (double) l) {
|
||||
+ if (despawnRangePair.soft().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy)) {
|
||||
+ if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && this.removeWhenFarAway(distanceSquared)) {
|
||||
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||
+ }
|
||||
+ } else {
|
||||
+ // Paper end - Configurable despawn distances
|
||||
this.noActionTime = 0;
|
||||
}
|
||||
}
|
|
@ -1,62 +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 a4e8fa5267b8853603e4683bf9d002db7465e4b6..c3a16691e8a843c02e0aea6469822cd8869ad593 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
@@ -149,6 +149,16 @@ public class FallingBlockEntity extends Entity {
|
||||
++this.time;
|
||||
this.applyGravity();
|
||||
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
+ // Paper start - Configurable falling blocks 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(EntityRemoveEvent.Cause.OUT_OF_WORLD);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Configurable falling blocks height nerf
|
||||
this.handlePortal();
|
||||
if (!this.level().isClientSide && (this.isAlive() || this.forceTickAfterTeleportToDuplicate)) {
|
||||
BlockPos blockposition = this.blockPosition();
|
||||
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 8f693bb45099124bca62849528c81d717131a48c..15432b512fc0d0d38bf28499e2afa5e48fec7aaa 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
@@ -99,6 +99,12 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||
this.handlePortal();
|
||||
this.applyGravity();
|
||||
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
+ // Paper start - Configurable TNT height nerf
|
||||
+ if (this.level().paperConfig().fixes.tntEntityHeightNerf.test(v -> this.getY() > v)) {
|
||||
+ this.discard(EntityRemoveEvent.Cause.OUT_OF_WORLD);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Configurable TNT height nerf
|
||||
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 c112c4b103c34e05f4de973eec94a969f60b085e..b7036f8399e2500ba01736c6006b972f7ca4838e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartTNT.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartTNT.java
|
||||
@@ -54,6 +54,12 @@ public class MinecartTNT extends AbstractMinecart {
|
||||
public void tick() {
|
||||
super.tick();
|
||||
if (this.fuse > 0) {
|
||||
+ // Paper start - Configurable TNT height nerf
|
||||
+ if (this.level().paperConfig().fixes.tntEntityHeightNerf.test(v -> this.getY() > v)) {
|
||||
+ this.discard(EntityRemoveEvent.Cause.OUT_OF_WORLD);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Configurable TNT height nerf
|
||||
--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) {
|
|
@ -1,756 +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] Expose server build information
|
||||
|
||||
Co-authored-by: Zach Brown <zach@zachbr.io>
|
||||
Co-authored-by: Kyle Wood <kyle@denwav.dev>
|
||||
Co-authored-by: Mark Vainomaa <mikroskeem@mikroskeem.eu>
|
||||
Co-authored-by: Riley Park <rileysebastianpark@gmail.com>
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Co-authored-by: masmc05 <masmc05@gmail.com>
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index 6d8f4c3b290609d60dbcabe3d2c8274b017246c8..0c349354ba76dfd2c5f16fb232263b18e77a9a40 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -1,4 +1,5 @@
|
||||
import io.papermc.paperweight.util.*
|
||||
+import java.time.Instant
|
||||
|
||||
plugins {
|
||||
java
|
||||
@@ -65,18 +66,24 @@ tasks.jar {
|
||||
|
||||
manifest {
|
||||
val git = Git(rootProject.layout.projectDirectory.path)
|
||||
+ val mcVersion = rootProject.providers.gradleProperty("mcVersion").get()
|
||||
+ val build = System.getenv("BUILD_NUMBER") ?: null
|
||||
val gitHash = git("rev-parse", "--short=7", "HEAD").getText().trim()
|
||||
- val implementationVersion = System.getenv("BUILD_NUMBER") ?: "\"$gitHash\""
|
||||
+ val implementationVersion = "$mcVersion-${build ?: "DEV"}-$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",
|
||||
- "Implementation-Version" to "git-Paper-$implementationVersion",
|
||||
+ "Implementation-Title" to "Paper",
|
||||
+ "Implementation-Version" to implementationVersion,
|
||||
"Implementation-Vendor" to date, // Paper
|
||||
- "Specification-Title" to "Bukkit",
|
||||
+ "Specification-Title" to "Paper",
|
||||
"Specification-Version" to project.version,
|
||||
- "Specification-Vendor" to "Bukkit Team",
|
||||
+ "Specification-Vendor" to "Paper Team",
|
||||
+ "Brand-Id" to "papermc:paper",
|
||||
+ "Brand-Name" to "Paper",
|
||||
+ "Build-Number" to (build ?: ""),
|
||||
+ "Build-Time" to Instant.now().toString(),
|
||||
"Git-Branch" to gitBranch, // Paper
|
||||
"Git-Commit" to gitHash, // Paper
|
||||
"CraftBukkit-Package-Version" to paperweight.craftBukkitPackageVersion.get(), // Paper
|
||||
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..532306cacd52579cdf37e4aca25887b1ed3ba6a1
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
|
||||
@@ -0,0 +1,146 @@
|
||||
+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.Gson;
|
||||
+import com.google.gson.JsonArray;
|
||||
+import com.google.gson.JsonElement;
|
||||
+import com.google.gson.JsonObject;
|
||||
+import com.google.gson.JsonSyntaxException;
|
||||
+import com.mojang.logging.LogUtils;
|
||||
+import io.papermc.paper.ServerBuildInfo;
|
||||
+import java.io.BufferedReader;
|
||||
+import java.io.IOException;
|
||||
+import java.io.InputStreamReader;
|
||||
+import java.net.HttpURLConnection;
|
||||
+import java.net.URI;
|
||||
+import java.util.Optional;
|
||||
+import java.util.OptionalInt;
|
||||
+import java.util.stream.StreamSupport;
|
||||
+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 org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+import org.slf4j.Logger;
|
||||
+
|
||||
+import static net.kyori.adventure.text.Component.text;
|
||||
+import static net.kyori.adventure.text.format.TextColor.color;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public class PaperVersionFetcher implements VersionFetcher {
|
||||
+ private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||
+ private static final int DISTANCE_ERROR = -1;
|
||||
+ private static final int DISTANCE_UNKNOWN = -2;
|
||||
+ private static final String DOWNLOAD_PAGE = "https://papermc.io/downloads/paper";
|
||||
+
|
||||
+ @Override
|
||||
+ public long getCacheTime() {
|
||||
+ return 720000;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Component getVersionMessage(final String serverVersion) {
|
||||
+ final Component updateMessage;
|
||||
+ final ServerBuildInfo build = ServerBuildInfo.buildInfo();
|
||||
+ if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) {
|
||||
+ updateMessage = text("You are running a development version without access to version information", color(0xFF5300));
|
||||
+ } else {
|
||||
+ updateMessage = getUpdateStatusMessage("PaperMC/Paper", build);
|
||||
+ }
|
||||
+ final @Nullable Component history = this.getHistory();
|
||||
+
|
||||
+ return history != null ? Component.textOfChildren(updateMessage, Component.newline(), history) : updateMessage;
|
||||
+ }
|
||||
+
|
||||
+ private static Component getUpdateStatusMessage(final String repo, final ServerBuildInfo build) {
|
||||
+ int distance = DISTANCE_ERROR;
|
||||
+
|
||||
+ final OptionalInt buildNumber = build.buildNumber();
|
||||
+ if (buildNumber.isPresent()) {
|
||||
+ distance = fetchDistanceFromSiteApi(build, buildNumber.getAsInt());
|
||||
+ } else {
|
||||
+ final Optional<String> gitBranch = build.gitBranch();
|
||||
+ final Optional<String> gitCommit = build.gitCommit();
|
||||
+ if (gitBranch.isPresent() && gitCommit.isPresent()) {
|
||||
+ distance = fetchDistanceFromGitHub(repo, gitBranch.get(), gitCommit.get());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return switch (distance) {
|
||||
+ case DISTANCE_ERROR -> text("Error obtaining version information", NamedTextColor.YELLOW);
|
||||
+ case 0 -> text("You are running the latest version", NamedTextColor.GREEN);
|
||||
+ case DISTANCE_UNKNOWN -> text("Unknown version", NamedTextColor.YELLOW);
|
||||
+ default -> text("You are " + distance + " version(s) behind", NamedTextColor.YELLOW)
|
||||
+ .append(Component.newline())
|
||||
+ .append(text("Download the new version at: ")
|
||||
+ .append(text(DOWNLOAD_PAGE, NamedTextColor.GOLD)
|
||||
+ .hoverEvent(text("Click to open", NamedTextColor.WHITE))
|
||||
+ .clickEvent(ClickEvent.openUrl(DOWNLOAD_PAGE))));
|
||||
+ };
|
||||
+ }
|
||||
+
|
||||
+ private static int fetchDistanceFromSiteApi(final ServerBuildInfo build, final int jenkinsBuild) {
|
||||
+ try {
|
||||
+ try (final BufferedReader reader = Resources.asCharSource(
|
||||
+ URI.create("https://api.papermc.io/v2/projects/paper/versions/" + build.minecraftVersionId()).toURL(),
|
||||
+ Charsets.UTF_8
|
||||
+ ).openBufferedStream()) {
|
||||
+ final JsonObject json = new Gson().fromJson(reader, JsonObject.class);
|
||||
+ final JsonArray builds = json.getAsJsonArray("builds");
|
||||
+ final int latest = StreamSupport.stream(builds.spliterator(), false)
|
||||
+ .mapToInt(JsonElement::getAsInt)
|
||||
+ .max()
|
||||
+ .orElseThrow();
|
||||
+ return latest - jenkinsBuild;
|
||||
+ } catch (final JsonSyntaxException ex) {
|
||||
+ LOGGER.error("Error parsing json from Paper's downloads API", ex);
|
||||
+ return DISTANCE_ERROR;
|
||||
+ }
|
||||
+ } catch (final IOException e) {
|
||||
+ LOGGER.error("Error while parsing version", e);
|
||||
+ return DISTANCE_ERROR;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Contributed by Techcable <Techcable@outlook.com> in GH-65
|
||||
+ private static int fetchDistanceFromGitHub(final String repo, final String branch, final String hash) {
|
||||
+ try {
|
||||
+ final HttpURLConnection connection = (HttpURLConnection) URI.create("https://api.github.com/repos/%s/compare/%s...%s".formatted(repo, branch, hash)).toURL().openConnection();
|
||||
+ connection.connect();
|
||||
+ if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) return DISTANCE_UNKNOWN; // Unknown commit
|
||||
+ try (final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8))) {
|
||||
+ final JsonObject obj = new Gson().fromJson(reader, JsonObject.class);
|
||||
+ final String status = obj.get("status").getAsString();
|
||||
+ return switch (status) {
|
||||
+ case "identical" -> 0;
|
||||
+ case "behind" -> obj.get("behind_by").getAsInt();
|
||||
+ default -> DISTANCE_ERROR;
|
||||
+ };
|
||||
+ } catch (final JsonSyntaxException | NumberFormatException e) {
|
||||
+ LOGGER.error("Error parsing json from GitHub's API", e);
|
||||
+ return DISTANCE_ERROR;
|
||||
+ }
|
||||
+ } catch (final IOException e) {
|
||||
+ LOGGER.error("Error while parsing version", e);
|
||||
+ return DISTANCE_ERROR;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private @Nullable Component getHistory() {
|
||||
+ final VersionHistoryManager.@Nullable VersionData data = VersionHistoryManager.INSTANCE.getVersionData();
|
||||
+ if (data == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ final @Nullable String oldVersion = data.getOldVersion();
|
||||
+ if (oldVersion == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ return 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..660b2ec6b63a4ceffee44ab11f54dfa7c0d0996f
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/VersionHistoryManager.java
|
||||
@@ -0,0 +1,153 @@
|
||||
+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 (currentData == null) {
|
||||
+ // Empty file
|
||||
+ currentData = new VersionData();
|
||||
+ currentData.setCurrentVersion(version);
|
||||
+ writeFile(path);
|
||||
+ 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/io/papermc/paper/PaperBootstrap.java b/src/main/java/io/papermc/paper/PaperBootstrap.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..d543b1b107ab8d3eeb1fc3c1cadf489928d2786e
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/PaperBootstrap.java
|
||||
@@ -0,0 +1,55 @@
|
||||
+package io.papermc.paper;
|
||||
+
|
||||
+import java.util.List;
|
||||
+import joptsimple.OptionSet;
|
||||
+import net.minecraft.SharedConstants;
|
||||
+import net.minecraft.server.Main;
|
||||
+import org.slf4j.Logger;
|
||||
+import org.slf4j.LoggerFactory;
|
||||
+
|
||||
+public final class PaperBootstrap {
|
||||
+ private static final Logger LOGGER = LoggerFactory.getLogger("bootstrap");
|
||||
+
|
||||
+ private PaperBootstrap() {
|
||||
+ }
|
||||
+
|
||||
+ public static void boot(final OptionSet options) {
|
||||
+ SharedConstants.tryDetectVersion();
|
||||
+
|
||||
+ getStartupVersionMessages().forEach(LOGGER::info);
|
||||
+
|
||||
+ Main.main(options);
|
||||
+ }
|
||||
+
|
||||
+ private static List<String> getStartupVersionMessages() {
|
||||
+ final String javaSpecVersion = System.getProperty("java.specification.version");
|
||||
+ final String javaVmName = System.getProperty("java.vm.name");
|
||||
+ final String javaVmVersion = System.getProperty("java.vm.version");
|
||||
+ final String javaVendor = System.getProperty("java.vendor");
|
||||
+ final String javaVendorVersion = System.getProperty("java.vendor.version");
|
||||
+ final String osName = System.getProperty("os.name");
|
||||
+ final String osVersion = System.getProperty("os.version");
|
||||
+ final String osArch = System.getProperty("os.arch");
|
||||
+
|
||||
+ final ServerBuildInfo bi = ServerBuildInfo.buildInfo();
|
||||
+ return List.of(
|
||||
+ String.format(
|
||||
+ "Running Java %s (%s %s; %s %s) on %s %s (%s)",
|
||||
+ javaSpecVersion,
|
||||
+ javaVmName,
|
||||
+ javaVmVersion,
|
||||
+ javaVendor,
|
||||
+ javaVendorVersion,
|
||||
+ osName,
|
||||
+ osVersion,
|
||||
+ osArch
|
||||
+ ),
|
||||
+ String.format(
|
||||
+ "Loading %s %s for Minecraft %s",
|
||||
+ bi.brandName(),
|
||||
+ bi.asString(ServerBuildInfo.StringRepresentation.VERSION_FULL),
|
||||
+ bi.minecraftVersionId()
|
||||
+ )
|
||||
+ );
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..790bad0494454ca12ee152e3de6da3da634d9b20
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
||||
@@ -0,0 +1,104 @@
|
||||
+package io.papermc.paper;
|
||||
+
|
||||
+import com.google.common.base.Strings;
|
||||
+import io.papermc.paper.util.JarManifests;
|
||||
+import java.time.Instant;
|
||||
+import java.time.temporal.ChronoUnit;
|
||||
+import java.util.Optional;
|
||||
+import java.util.OptionalInt;
|
||||
+import java.util.jar.Manifest;
|
||||
+import net.kyori.adventure.key.Key;
|
||||
+import net.minecraft.SharedConstants;
|
||||
+import org.bukkit.craftbukkit.CraftServer;
|
||||
+import org.bukkit.craftbukkit.Main;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+
|
||||
+public record ServerBuildInfoImpl(
|
||||
+ Key brandId,
|
||||
+ String brandName,
|
||||
+ String minecraftVersionId,
|
||||
+ String minecraftVersionName,
|
||||
+ OptionalInt buildNumber,
|
||||
+ Instant buildTime,
|
||||
+ Optional<String> gitBranch,
|
||||
+ Optional<String> gitCommit
|
||||
+) implements ServerBuildInfo {
|
||||
+ private static final String ATTRIBUTE_BRAND_ID = "Brand-Id";
|
||||
+ private static final String ATTRIBUTE_BRAND_NAME = "Brand-Name";
|
||||
+ private static final String ATTRIBUTE_BUILD_TIME = "Build-Time";
|
||||
+ private static final String ATTRIBUTE_BUILD_NUMBER = "Build-Number";
|
||||
+ private static final String ATTRIBUTE_GIT_BRANCH = "Git-Branch";
|
||||
+ private static final String ATTRIBUTE_GIT_COMMIT = "Git-Commit";
|
||||
+
|
||||
+ private static final String BRAND_PAPER_NAME = "Paper";
|
||||
+
|
||||
+ private static final String BUILD_DEV = "DEV";
|
||||
+
|
||||
+ public ServerBuildInfoImpl() {
|
||||
+ this(JarManifests.manifest(CraftServer.class));
|
||||
+ }
|
||||
+
|
||||
+ private ServerBuildInfoImpl(final Manifest manifest) {
|
||||
+ this(
|
||||
+ getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID)
|
||||
+ .map(Key::key)
|
||||
+ .orElse(BRAND_PAPER_ID),
|
||||
+ getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME)
|
||||
+ .orElse(BRAND_PAPER_NAME),
|
||||
+ SharedConstants.getCurrentVersion().getId(),
|
||||
+ SharedConstants.getCurrentVersion().getName(),
|
||||
+ getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER)
|
||||
+ .map(Integer::parseInt)
|
||||
+ .map(OptionalInt::of)
|
||||
+ .orElse(OptionalInt.empty()),
|
||||
+ getManifestAttribute(manifest, ATTRIBUTE_BUILD_TIME)
|
||||
+ .map(Instant::parse)
|
||||
+ .orElse(Main.BOOT_TIME),
|
||||
+ getManifestAttribute(manifest, ATTRIBUTE_GIT_BRANCH),
|
||||
+ getManifestAttribute(manifest, ATTRIBUTE_GIT_COMMIT)
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isBrandCompatible(final @NotNull Key brandId) {
|
||||
+ return brandId.equals(this.brandId);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NotNull String asString(final @NotNull StringRepresentation representation) {
|
||||
+ final StringBuilder sb = new StringBuilder();
|
||||
+ sb.append(this.minecraftVersionId);
|
||||
+ sb.append('-');
|
||||
+ if (this.buildNumber.isPresent()) {
|
||||
+ sb.append(this.buildNumber.getAsInt());
|
||||
+ } else {
|
||||
+ sb.append(BUILD_DEV);
|
||||
+ }
|
||||
+ final boolean hasGitBranch = this.gitBranch.isPresent();
|
||||
+ final boolean hasGitCommit = this.gitCommit.isPresent();
|
||||
+ if (hasGitBranch || hasGitCommit) {
|
||||
+ sb.append('-');
|
||||
+ }
|
||||
+ if (hasGitBranch && representation == StringRepresentation.VERSION_FULL) {
|
||||
+ sb.append(this.gitBranch.get());
|
||||
+ if (hasGitCommit) {
|
||||
+ sb.append('@');
|
||||
+ }
|
||||
+ }
|
||||
+ if (hasGitCommit) {
|
||||
+ sb.append(this.gitCommit.get());
|
||||
+ }
|
||||
+ if (representation == StringRepresentation.VERSION_FULL) {
|
||||
+ sb.append(' ');
|
||||
+ sb.append('(');
|
||||
+ sb.append(this.buildTime.truncatedTo(ChronoUnit.SECONDS));
|
||||
+ sb.append(')');
|
||||
+ }
|
||||
+ return sb.toString();
|
||||
+ }
|
||||
+
|
||||
+ private static Optional<String> getManifestAttribute(final Manifest manifest, final String name) {
|
||||
+ final String value = manifest != null ? manifest.getMainAttributes().getValue(name) : null;
|
||||
+ return Optional.ofNullable(Strings.emptyToNull(value));
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 46e03617bb32e4037d700c1b3698d397bd75de5c..2f57739431eb695149019724e2923f0d02e88d07 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -43,7 +43,6 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
-import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Consumer;
|
||||
@@ -191,8 +190,6 @@ import net.minecraft.world.phys.Vec2;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.CraftRegistry;
|
||||
-import org.bukkit.craftbukkit.CraftServer;
|
||||
-import org.bukkit.craftbukkit.Main;
|
||||
import org.bukkit.event.server.ServerLoadEvent;
|
||||
// CraftBukkit end
|
||||
|
||||
@@ -1700,7 +1697,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
@DontObfuscate
|
||||
public String getServerModName() {
|
||||
- return "Spigot"; // Spigot - Spigot > // CraftBukkit - cb > vanilla!
|
||||
+ return io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); // Paper
|
||||
}
|
||||
|
||||
public SystemReport fillSystemReport(SystemReport details) {
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index b51c3f8c485496734ea58c15377a1215a334c765..48107f8eb50483430053b990496862d71c9f8a3e 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -218,6 +218,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
// Paper end - initialize global and world-defaults configuration
|
||||
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
|
||||
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
|
||||
+ com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
||||
|
||||
this.setPvpAllowed(dedicatedserverproperties.pvp);
|
||||
this.setFlightAllowed(dedicatedserverproperties.allowFlight);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftCrashReport.java b/src/main/java/org/bukkit/craftbukkit/CraftCrashReport.java
|
||||
index f077b8ff0bf0d96628db3569132696b68fd79921..5f11f5b16766f9d1d5640ae037e259bed9020384 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftCrashReport.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftCrashReport.java
|
||||
@@ -18,8 +18,10 @@ public class CraftCrashReport implements Supplier<String> {
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
+ final io.papermc.paper.ServerBuildInfo build = io.papermc.paper.ServerBuildInfo.buildInfo(); // Paper
|
||||
StringWriter value = new StringWriter();
|
||||
try {
|
||||
+ value.append("\n BrandInfo: ").append(String.format("%s (%s) version %s", build.brandName(), build.brandId(), build.asString(io.papermc.paper.ServerBuildInfo.StringRepresentation.VERSION_FULL))); // Paper
|
||||
value.append("\n Running: ").append(Bukkit.getName()).append(" version ").append(Bukkit.getVersion()).append(" (Implementing API version ").append(Bukkit.getBukkitVersion()).append(") ").append(String.valueOf(MinecraftServer.getServer().usesAuthentication()));
|
||||
value.append("\n Plugins: {");
|
||||
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index b8b2e582115cc42a913b03a35861fa810d774cbb..8f79d7611c3ee1c817d5671152e459ec4f413418 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -11,8 +11,6 @@ import com.google.common.collect.MapMaker;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
-import com.mojang.brigadier.tree.CommandNode;
|
||||
-import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
@@ -27,7 +25,6 @@ import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
-import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -155,7 +152,6 @@ import org.bukkit.craftbukkit.ban.CraftProfileBanList;
|
||||
import org.bukkit.craftbukkit.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.boss.CraftBossBar;
|
||||
import org.bukkit.craftbukkit.boss.CraftKeyedBossbar;
|
||||
-import org.bukkit.craftbukkit.command.BukkitCommandWrapper;
|
||||
import org.bukkit.craftbukkit.command.CraftCommandMap;
|
||||
import org.bukkit.craftbukkit.command.VanillaCommandWrapper;
|
||||
import org.bukkit.craftbukkit.entity.CraftEntityFactory;
|
||||
@@ -251,7 +247,6 @@ import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.ServicesManager;
|
||||
import org.bukkit.plugin.SimplePluginManager;
|
||||
import org.bukkit.plugin.SimpleServicesManager;
|
||||
-import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import org.bukkit.plugin.messaging.Messenger;
|
||||
import org.bukkit.plugin.messaging.StandardMessenger;
|
||||
import org.bukkit.profile.PlayerProfile;
|
||||
@@ -268,7 +263,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 = io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); // Paper
|
||||
private final String serverVersion;
|
||||
private final String bukkitVersion = Versioning.getBukkitVersion();
|
||||
private final Logger logger = Logger.getLogger("Minecraft");
|
||||
@@ -324,7 +319,7 @@ public final class CraftServer implements Server {
|
||||
return player.getBukkitEntity();
|
||||
}
|
||||
}));
|
||||
- this.serverVersion = CraftServer.class.getPackage().getImplementationVersion();
|
||||
+ this.serverVersion = io.papermc.paper.ServerBuildInfo.buildInfo().asString(io.papermc.paper.ServerBuildInfo.StringRepresentation.VERSION_SIMPLE); // Paper - improve version
|
||||
this.structureManager = new CraftStructureManager(console.getStructureManager(), console.registryAccess());
|
||||
this.dataPackManager = new CraftDataPackManager(this.getServer().getPackRepository());
|
||||
this.serverTickManager = new CraftServerTickManager(console.tickRateManager());
|
||||
@@ -607,6 +602,13 @@ public final class CraftServer implements Server {
|
||||
return this.bukkitVersion;
|
||||
}
|
||||
|
||||
+ // Paper start - expose game version
|
||||
+ @Override
|
||||
+ public String getMinecraftVersion() {
|
||||
+ return console.getServerVersion();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public List<CraftPlayer> getOnlinePlayers() {
|
||||
return this.playerView;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index 034d68c2715b6a90f31e56f949ff3d27235a26eb..a7fbbe40f2382e7af185c4bfdd451fc1998b3636 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -15,6 +15,7 @@ import joptsimple.OptionSet;
|
||||
import joptsimple.util.PathConverter;
|
||||
|
||||
public class Main {
|
||||
+ public static final java.time.Instant BOOT_TIME = java.time.Instant.now(); // Paper - track initial start time
|
||||
public static boolean useJline = true;
|
||||
public static boolean useConsole = true;
|
||||
|
||||
@@ -241,15 +242,17 @@ 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 ***"); // Paper
|
||||
System.err.println("*** Server will start in 20 seconds ***");
|
||||
Thread.sleep(TimeUnit.SECONDS.toMillis(20));
|
||||
}
|
||||
}
|
||||
|
||||
System.setProperty("library.jansi.version", "Paper"); // Paper - set meaningless jansi version to prevent git builds from crashing on Windows
|
||||
- System.out.println("Loading libraries, please wait...");
|
||||
- net.minecraft.server.Main.main(options);
|
||||
+
|
||||
+ //System.out.println("Loading libraries, please wait...");
|
||||
+ //net.minecraft.server.Main.main(options);
|
||||
+ io.papermc.paper.PaperBootstrap.boot(options);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index f7b80cf8c89ae5eb9d8f0893e05ffc753fdace19..432f019afff36aa6143c052f7387a6c275a09de8 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -459,6 +459,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
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index f697d45e0ac4e9cdc8a46121510a04c0f294d91f..e086765dec32241bc5a77afcf072c77a40c6d785 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -19,7 +19,7 @@ public class WatchdogThread extends Thread
|
||||
|
||||
private WatchdogThread(long timeoutTime, boolean restart)
|
||||
{
|
||||
- super( "Spigot Watchdog Thread" );
|
||||
+ super( "Paper Watchdog Thread" );
|
||||
this.timeoutTime = timeoutTime;
|
||||
this.restart = restart;
|
||||
}
|
||||
@@ -65,14 +65,14 @@ public class WatchdogThread extends Thread
|
||||
{
|
||||
Logger log = Bukkit.getServer().getLogger();
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
- log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Spigot bug." );
|
||||
+ log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug." ); // Paper
|
||||
log.log( Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author" );
|
||||
log.log( Level.SEVERE, "\t *Especially* if it looks like HTTP or MySQL operations are occurring" );
|
||||
log.log( Level.SEVERE, "If you see a world save or edit, then it means you did far more than your server can handle at once" );
|
||||
log.log( Level.SEVERE, "\t If this is the case, consider increasing timeout-time in spigot.yml but note that this will replace the crash with LARGE lag spikes" );
|
||||
- log.log( Level.SEVERE, "If you are unsure or still think this is a Spigot bug, please report to https://www.spigotmc.org/" );
|
||||
+ log.log( Level.SEVERE, "If you are unsure or still think this is a Paper bug, please report this to https://github.com/PaperMC/Paper/issues" );
|
||||
log.log( Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports" );
|
||||
- log.log( Level.SEVERE, "Spigot version: " + Bukkit.getServer().getVersion() );
|
||||
+ log.log( Level.SEVERE, "Paper version: " + Bukkit.getServer().getVersion() );
|
||||
//
|
||||
if ( net.minecraft.world.level.Level.lastPhysicsProblem != null )
|
||||
{
|
||||
@@ -82,7 +82,7 @@ public class WatchdogThread extends Thread
|
||||
}
|
||||
//
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
- log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Spigot!):" );
|
||||
+ log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
||||
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
//
|
||||
diff --git a/src/main/resources/META-INF/services/io.papermc.paper.ServerBuildInfo b/src/main/resources/META-INF/services/io.papermc.paper.ServerBuildInfo
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..79b4b25784cfeabd5f619ed5454ef843f35041db
|
||||
--- /dev/null
|
||||
+++ b/src/main/resources/META-INF/services/io.papermc.paper.ServerBuildInfo
|
||||
@@ -0,0 +1 @@
|
||||
+io.papermc.paper.ServerBuildInfoImpl
|
|
@ -1,158 +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 3126e8cab3c40e3af47f4c8925e1c6a9523309ba..3207166061bf9c4d7bf3f38e5a9f7aff23ccd5c1 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
@@ -30,6 +30,11 @@ public final class EntitySelector {
|
||||
public static final Predicate<Entity> CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith);
|
||||
|
||||
private EntitySelector() {}
|
||||
+ // Paper start - Affects Spawning API
|
||||
+ public static final Predicate<Entity> PLAYER_AFFECTS_SPAWNING = (entity) -> {
|
||||
+ return !entity.isSpectator() && entity.isAlive() && entity instanceof Player player && player.affectsSpawning;
|
||||
+ };
|
||||
+ // Paper end - Affects Spawning API
|
||||
|
||||
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 4ce1586351b417aede1fd401907388b5fa0e9fd6..d8beadc96a7f779c39c8e22ffe52d872ac49a0ad 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
@@ -860,7 +860,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
|
||||
this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||
} 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 - Affects Spawning API
|
||||
|
||||
if (entityhuman != null) {
|
||||
// Paper start - Configurable despawn distances
|
||||
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 3b7fc11b7832a72fb9b0806fe9847f4e30759e7b..3cb84856c10347162a8736ae1ef65165183ec8fe 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
|
||||
@@ -27,7 +27,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 95e9d38dbccbd1c43ababd707e18dfe6779256c1..9ff42b0ae2b82dc3092e38e1439d89b4ab554b17 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
|
||||
@@ -118,7 +118,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 393a9c704f4637a0e8031328d2a0facef4723dd8..d97c3c139f10a45febc0cfb1057ff6e33266228e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
@@ -328,7 +328,7 @@ public class Zombie extends Monster {
|
||||
|
||||
if (SpawnPlacements.isSpawnPositionOk(entitytypes, this.level(), blockposition) && 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);
|
||||
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 56f4d85d0d2014dfe4fb2598fa813ffc4a768d25..ba279ab6ec0ab41309607333b62a941e35dbf581 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -195,6 +195,7 @@ public abstract class Player extends LivingEntity {
|
||||
public Entity currentExplosionCause;
|
||||
private boolean ignoreFallDamageFromCurrentImpulse;
|
||||
private int currentImpulseContextResetGraceTime;
|
||||
+ public boolean affectsSpawning = true; // Paper - Affects Spawning API
|
||||
|
||||
// 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 cc54da2987fafcbd69153c33033a6f272dd3be66..418e29971326008ebca0cc4b696a41a49c1c7bb7 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -58,7 +58,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 f38f62e777d88a783e1e3b7e1a48da921cc67cf4..77ae7882a08441d9a80b50492be5e48487a2fdab 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/EntityGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java
|
||||
@@ -74,6 +74,11 @@ public interface EntityGetter {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Affects Spawning API
|
||||
+ 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 - Affects Spawning API
|
||||
@Nullable
|
||||
default Player getNearestPlayer(double x, double y, double z, double maxDistance, @Nullable Predicate<Entity> targetPredicate) {
|
||||
double d = -1.0;
|
||||
@@ -103,6 +108,20 @@ public interface EntityGetter {
|
||||
return this.getNearestPlayer(x, y, z, maxDistance, predicate);
|
||||
}
|
||||
|
||||
+ // Paper start - Affects Spawning API
|
||||
+ 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 - Affects Spawning API
|
||||
+
|
||||
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 68b9b4aba7dba31e4526165e6efb8c40f9e841bc..1b2ead250233d9f228bfe8e79f988026506895f9 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -2425,6 +2425,17 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
return this.getHandle().language;
|
||||
}
|
||||
|
||||
+ // 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;
|
|
@ -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 4cc6b3162cea049134f194ed84a7552830cb85af..c2be21491183f5f113dbfc71a7e0ccd195679296 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -2093,12 +2093,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()) {
|
||||
Preconditions.checkArgument(!value, "Player is not allowed to fly (check #getAllowFlight())");
|
||||
}
|
||||
|
||||
this.getHandle().getAbilities().flying = value;
|
||||
- this.getHandle().onUpdateAbilities();
|
||||
+ if (needsUpdate) this.getHandle().onUpdateAbilities(); // Paper - Only refresh abilities if needed
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,121 +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 eb98bb1bd76869fd76b34885223c8e57a04e0c51..754045e71f180862fa57fd1c97e5d7deb1d788e6 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2141,6 +2141,15 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
|
||||
entity.inWorld = true; // CraftBukkit - Mark entity as in world
|
||||
entity.valid = true; // CraftBukkit
|
||||
+ // Paper start - Entity origin API
|
||||
+ 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 - Entity origin API
|
||||
}
|
||||
|
||||
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 63f45a77c8511e05954030cf117c5e4cda0a518f..dbe5239b1a1769ef9f2ef66c32b1a68cd684428e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -328,7 +328,27 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
public long activatedTick = Integer.MIN_VALUE;
|
||||
public void inactiveTick() { }
|
||||
// Spigot end
|
||||
+ // Paper start - Entity origin API
|
||||
+ @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 - Entity origin API
|
||||
public float getBukkitYaw() {
|
||||
return this.yRot;
|
||||
}
|
||||
@@ -2153,6 +2173,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
this.bukkitEntity.storeBukkitValues(nbttagcompound);
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Paper start
|
||||
+ if (this.origin != null) {
|
||||
+ UUID originWorld = this.originWorld != null ? this.originWorld : this.level != null ? this.level.getWorld().getUID() : null;
|
||||
+ if (originWorld != null) {
|
||||
+ nbttagcompound.putUUID("Paper.OriginWorld", originWorld);
|
||||
+ }
|
||||
+ nbttagcompound.put("Paper.Origin", this.newDoubleList(origin.getX(), origin.getY(), origin.getZ()));
|
||||
+ }
|
||||
+ // Paper end
|
||||
return nbttagcompound;
|
||||
} catch (Throwable throwable) {
|
||||
CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT");
|
||||
@@ -2280,6 +2309,20 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
+ // Paper start
|
||||
+ ListTag originTag = nbt.getList("Paper.Origin", net.minecraft.nbt.Tag.TAG_DOUBLE);
|
||||
+ 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/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index 269326e7689eba91bcfd3475006e8cbf8f5694ef..7b45a1216ff824f1b528bb5759d10b70858832a1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -963,4 +963,21 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
return this.spigot;
|
||||
}
|
||||
// Spigot end
|
||||
+
|
||||
+ // Paper start - entity origin API
|
||||
+ @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 - entity origin API
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 1 Mar 2016 23:52:34 -0600
|
||||
Subject: [PATCH] Prevent block entity and entity crashes
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 79d5423be919dfe4db75ad7dd0ce403ad0214462..e8b8475dd6fd7b89651f744da2cb9696c73ddc3e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -731,11 +731,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
try {
|
||||
tickConsumer.accept(entity);
|
||||
} catch (Throwable throwable) {
|
||||
- CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking entity");
|
||||
- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being ticked");
|
||||
-
|
||||
- entity.fillCrashReportCategory(crashreportsystemdetails);
|
||||
- throw new ReportedException(crashreport);
|
||||
+ // Paper start - Prevent block entity and entity crashes
|
||||
+ final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
|
||||
+ MinecraftServer.LOGGER.error(msg, throwable);
|
||||
+ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
||||
+ // Paper end - Prevent block entity and entity crashes
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
index 17cda4c8b61efd99c1a43f921ed604827bb064f3..d6ad310d3b472c40c128cfb459171d9f48e50915 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
@@ -272,7 +272,12 @@ public abstract class BlockEntity {
|
||||
public void fillCrashReportCategory(CrashReportCategory crashReportSection) {
|
||||
crashReportSection.setDetail("Name", this::getNameForReporting);
|
||||
if (this.level != null) {
|
||||
- CrashReportCategory.populateBlockDetails(crashReportSection, this.level, this.worldPosition, this.getBlockState());
|
||||
+ // Paper start - Prevent block entity and entity crashes
|
||||
+ BlockState block = this.getBlockState();
|
||||
+ if (block != null) {
|
||||
+ CrashReportCategory.populateBlockDetails(crashReportSection, this.level, this.worldPosition, block);
|
||||
+ }
|
||||
+ // Paper end - Prevent block entity and entity crashes
|
||||
CrashReportCategory.populateBlockDetails(crashReportSection, this.level, this.worldPosition, this.level.getBlockState(this.worldPosition));
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 418ba374886d93f69afd614e4be05f6561e1f897..6889991885cc2075e0936b2c480befeef30d308c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -953,11 +953,11 @@ public class LevelChunk extends ChunkAccess {
|
||||
|
||||
gameprofilerfiller.pop();
|
||||
} catch (Throwable throwable) {
|
||||
- CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking block entity");
|
||||
- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block entity being ticked");
|
||||
-
|
||||
- this.blockEntity.fillCrashReportCategory(crashreportsystemdetails);
|
||||
- throw new ReportedException(crashreport);
|
||||
+ // Paper start - Prevent block entity and entity crashes
|
||||
+ final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
|
||||
+ net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
|
||||
+ LevelChunk.this.removeBlockEntity(this.getPos());
|
||||
+ // Paper end - Prevent block entity and entity crashes
|
||||
// Spigot start
|
||||
} finally {
|
||||
this.blockEntity.tickTimer.stopTiming();
|
|
@ -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 23:58:50 -0600
|
||||
Subject: [PATCH] Configurable top of nether void damage
|
||||
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index dbe5239b1a1769ef9f2ef66c32b1a68cd684428e..d5f5864b7c1ad4c30f37b360b317b63c129e3a3f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -706,7 +706,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public void checkBelowWorld() {
|
||||
- if (this.getY() < (double) (this.level().getMinBuildHeight() - 64)) {
|
||||
+ // Paper start - Configurable nether ceiling damage
|
||||
+ if (this.getY() < (double) (this.level.getMinBuildHeight() - 64) || (this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER
|
||||
+ && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> this.getY() >= v)
|
||||
+ && (!(this instanceof Player player) || !player.getAbilities().invulnerable))) {
|
||||
+ // Paper end - Configurable nether ceiling damage
|
||||
this.onBelowWorld();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
index 46448259cd60ea5e2e08fb58cd2b2b7f8a4ec3cc..aef1dd28da7e0c0a13a0a7a5b52daa27635c48ea 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
@@ -58,7 +58,7 @@ public class PortalForcer {
|
||||
}, blockposition, i, PoiManager.Occupancy.ANY).map(PoiRecord::getPos);
|
||||
|
||||
Objects.requireNonNull(worldborder);
|
||||
- return stream.filter(worldborder::isWithinBounds).filter((blockposition1) -> {
|
||||
+ return stream.filter(worldborder::isWithinBounds).filter(pos -> !(this.level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> pos.getY() >= v))).filter((blockposition1) -> { // Paper - Configurable nether ceiling damage
|
||||
return this.level.getBlockState(blockposition1).hasProperty(BlockStateProperties.HORIZONTAL_AXIS);
|
||||
}).min(Comparator.comparingDouble((BlockPos blockposition1) -> { // CraftBukkit - decompile error
|
||||
return blockposition1.distSqr(blockposition);
|
||||
@@ -79,6 +79,11 @@ public class PortalForcer {
|
||||
BlockPos blockposition2 = null;
|
||||
WorldBorder worldborder = this.level.getWorldBorder();
|
||||
int i = Math.min(this.level.getMaxBuildHeight(), this.level.getMinBuildHeight() + this.level.getLogicalHeight()) - 1;
|
||||
+ // Paper start - Configurable nether ceiling damage; make sure the max height doesn't exceed the void damage height
|
||||
+ if (this.level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.enabled()) {
|
||||
+ i = Math.min(i, this.level.paperConfig().environment.netherCeilingVoidDamageHeight.intValue() - 1);
|
||||
+ }
|
||||
+ // Paper end - Configurable nether ceiling damage
|
||||
boolean flag = true;
|
||||
BlockPos.MutableBlockPos blockposition_mutableblockposition = blockposition.mutable();
|
||||
Iterator iterator = BlockPos.spiralAround(blockposition, createRadius, Direction.EAST, Direction.SOUTH).iterator(); // CraftBukkit
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Wed, 2 Mar 2016 00:03:55 -0600
|
||||
Subject: [PATCH] Check online mode before converting and renaming player data
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
|
||||
index 79222a04ef104bf2eed85684479384b7c350ea19..cd013567dd6224c86c0f1813d8a3d5fb7b8cabb5 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
|
||||
@@ -78,7 +78,7 @@ public class PlayerDataStorage {
|
||||
File file1 = new File(file, s1 + s);
|
||||
// Spigot Start
|
||||
boolean usingWrongFile = false;
|
||||
- if ( !file1.exists() )
|
||||
+ if ( org.bukkit.Bukkit.getOnlineMode() && !file1.exists() ) // Paper - Check online mode first
|
||||
{
|
||||
file1 = new File( file, java.util.UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + name ).getBytes( java.nio.charset.StandardCharsets.UTF_8 ) ).toString() + s );
|
||||
if ( file1.exists() )
|
|
@ -1,20 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Wed, 2 Mar 2016 00:32:25 -0600
|
||||
Subject: [PATCH] Add more entities to activation range ignore list
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
index a5da6c1cae0afbde684be250e2fc3c0c32a1265b..6d51464f6368151e8acc532414ee223714584e96 100644
|
||||
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
||||
+++ b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
@@ -92,6 +92,9 @@ public class ActivationRange
|
||||
|| entity instanceof AbstractHurtingProjectile
|
||||
|| entity instanceof LightningBolt
|
||||
|| entity instanceof PrimedTnt
|
||||
+ || entity instanceof net.minecraft.world.entity.item.FallingBlockEntity // Paper - Always tick falling blocks
|
||||
+ || entity instanceof net.minecraft.world.entity.vehicle.AbstractMinecart // Paper
|
||||
+ || entity instanceof net.minecraft.world.entity.vehicle.Boat // Paper
|
||||
|| entity instanceof EndCrystal
|
||||
|| entity instanceof FireworkRocketEntity
|
||||
|| entity instanceof ThrownTrident )
|
|
@ -1,18 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: DoctorDark <doctordark11@gmail.com>
|
||||
Date: Wed, 16 Mar 2016 02:21:39 -0500
|
||||
Subject: [PATCH] Configurable end credits
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java
|
||||
index e2d6693da4abe6204c0ecb5e924a3903fa80ab7d..a9c7a74b38a57c118c1ad67a77ba6f2e5c05d91e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java
|
||||
@@ -71,6 +71,7 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal {
|
||||
if (!world.isClientSide && world.dimension() == Level.END && entity instanceof ServerPlayer) {
|
||||
ServerPlayer entityplayer = (ServerPlayer) entity;
|
||||
|
||||
+ if (world.paperConfig().misc.disableEndCredits) entityplayer.seenCredits = true; // Paper - Option to disable end credits
|
||||
if (!entityplayer.seenCredits) {
|
||||
entityplayer.showEndCredits();
|
||||
return;
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Iceee <andrew@opticgaming.tv>
|
||||
Date: Wed, 2 Mar 2016 01:39:52 -0600
|
||||
Subject: [PATCH] Fix lag from explosions processing dead entities
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
index 4a30928cd11f528f8ac06950b8052ebb7f2dd33c..458020575050284544761ec61c52abac7bfd15be 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
@@ -227,7 +227,7 @@ public class Explosion {
|
||||
int i1 = Mth.floor(this.y + (double) f2 + 1.0D);
|
||||
int j1 = Mth.floor(this.z - (double) f2 - 1.0D);
|
||||
int k1 = Mth.floor(this.z + (double) f2 + 1.0D);
|
||||
- List<Entity> list = this.level.getEntities(this.source, new AABB((double) i, (double) l, (double) j1, (double) j, (double) i1, (double) k1));
|
||||
+ List<Entity> list = this.level.getEntities(this.source, new AABB((double) i, (double) l, (double) j1, (double) j, (double) i1, (double) k1), (com.google.common.base.Predicate<Entity>) entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities
|
||||
Vec3 vec3d = new Vec3(this.x, this.y, this.z);
|
||||
Iterator iterator = list.iterator();
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Byteflux <byte@byteflux.net>
|
||||
Date: Wed, 2 Mar 2016 11:59:48 -0600
|
||||
Subject: [PATCH] Optimize explosions
|
||||
|
||||
The process of determining an entity's exposure from explosions can be
|
||||
expensive when there are hundreds or more entities in range.
|
||||
|
||||
This patch adds a per-tick cache that is used for storing and retrieving
|
||||
an entity's exposure during an explosion.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 2f57739431eb695149019724e2923f0d02e88d07..1ba2b1aaf0936963aca73a43632f978c95bf95e6 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1571,6 +1571,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
this.profiler.pop();
|
||||
this.profiler.pop();
|
||||
+ worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
|
||||
}
|
||||
|
||||
this.profiler.popPush("connection");
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
index 35d541c549cb07508e68388b18f38a4ffd788176..23a0a8d9beb7ca400134fb6a65b3133baceeed83 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
@@ -279,7 +279,7 @@ public class Explosion {
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
- double d12 = (1.0D - d7) * (double) Explosion.getSeenPercent(vec3d, entity) * (double) this.damageCalculator.getKnockbackMultiplier(entity);
|
||||
+ double d12 = (1.0D - d7) * this.getBlockDensity(vec3d, entity) * (double) this.damageCalculator.getKnockbackMultiplier(entity); // Paper - Optimize explosions
|
||||
double d13;
|
||||
|
||||
if (entity instanceof LivingEntity) {
|
||||
@@ -536,4 +536,84 @@ public class Explosion {
|
||||
|
||||
private BlockInteraction() {}
|
||||
}
|
||||
+ // Paper start - Optimize explosions
|
||||
+ private float getBlockDensity(Vec3 vec3d, Entity entity) {
|
||||
+ if (!this.level.paperConfig().environment.optimizeExplosions) {
|
||||
+ return getSeenPercent(vec3d, entity);
|
||||
+ }
|
||||
+ CacheKey key = new CacheKey(this, entity.getBoundingBox());
|
||||
+ Float blockDensity = this.level.explosionDensityCache.get(key);
|
||||
+ if (blockDensity == null) {
|
||||
+ blockDensity = getSeenPercent(vec3d, entity);
|
||||
+ this.level.explosionDensityCache.put(key, blockDensity);
|
||||
+ }
|
||||
+
|
||||
+ return blockDensity;
|
||||
+ }
|
||||
+
|
||||
+ static class CacheKey {
|
||||
+ private final Level world;
|
||||
+ private final double posX, posY, posZ;
|
||||
+ private final double minX, minY, minZ;
|
||||
+ private final double maxX, maxY, maxZ;
|
||||
+
|
||||
+ public CacheKey(Explosion explosion, AABB aabb) {
|
||||
+ this.world = explosion.level;
|
||||
+ this.posX = explosion.x;
|
||||
+ this.posY = explosion.y;
|
||||
+ this.posZ = explosion.z;
|
||||
+ this.minX = aabb.minX;
|
||||
+ this.minY = aabb.minY;
|
||||
+ this.minZ = aabb.minZ;
|
||||
+ this.maxX = aabb.maxX;
|
||||
+ this.maxY = aabb.maxY;
|
||||
+ this.maxZ = aabb.maxZ;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean equals(Object o) {
|
||||
+ if (this == o) return true;
|
||||
+ if (o == null || getClass() != o.getClass()) return false;
|
||||
+
|
||||
+ CacheKey cacheKey = (CacheKey) o;
|
||||
+
|
||||
+ if (Double.compare(cacheKey.posX, posX) != 0) return false;
|
||||
+ if (Double.compare(cacheKey.posY, posY) != 0) return false;
|
||||
+ if (Double.compare(cacheKey.posZ, posZ) != 0) return false;
|
||||
+ if (Double.compare(cacheKey.minX, minX) != 0) return false;
|
||||
+ if (Double.compare(cacheKey.minY, minY) != 0) return false;
|
||||
+ if (Double.compare(cacheKey.minZ, minZ) != 0) return false;
|
||||
+ if (Double.compare(cacheKey.maxX, maxX) != 0) return false;
|
||||
+ if (Double.compare(cacheKey.maxY, maxY) != 0) return false;
|
||||
+ if (Double.compare(cacheKey.maxZ, maxZ) != 0) return false;
|
||||
+ return world.equals(cacheKey.world);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int hashCode() {
|
||||
+ int result;
|
||||
+ long temp;
|
||||
+ result = world.hashCode();
|
||||
+ temp = Double.doubleToLongBits(posX);
|
||||
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
+ temp = Double.doubleToLongBits(posY);
|
||||
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
+ temp = Double.doubleToLongBits(posZ);
|
||||
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
+ temp = Double.doubleToLongBits(minX);
|
||||
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
+ temp = Double.doubleToLongBits(minY);
|
||||
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
+ temp = Double.doubleToLongBits(minZ);
|
||||
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
+ temp = Double.doubleToLongBits(maxX);
|
||||
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
+ temp = Double.doubleToLongBits(maxY);
|
||||
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
+ temp = Double.doubleToLongBits(maxZ);
|
||||
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
+ return result;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index e8b8475dd6fd7b89651f744da2cb9696c73ddc3e..a272aaff11ac077853c06f729a5d8b09f866e0f8 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -168,6 +168,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
private org.spigotmc.TickLimiter entityLimiter;
|
||||
private org.spigotmc.TickLimiter tileLimiter;
|
||||
private int tileTickPosition;
|
||||
+ public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
|
||||
|
||||
public CraftWorld getWorld() {
|
||||
return this.world;
|
|
@ -1,28 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sudzzy <originmc@outlook.com>
|
||||
Date: Wed, 2 Mar 2016 14:48:03 -0600
|
||||
Subject: [PATCH] Disable explosion knockback
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
index 55d66aa8264d5b444a23e2132206bcc9835cfe00..d93ed33d5ae72e9dd3e6cf044ef79e4b9689dc1c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
@@ -285,7 +285,7 @@ public class Explosion {
|
||||
if (entity instanceof LivingEntity) {
|
||||
LivingEntity entityliving = (LivingEntity) entity;
|
||||
|
||||
- d13 = d12 * (1.0D - entityliving.getAttributeValue(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE));
|
||||
+ d13 = entity instanceof Player && this.level.paperConfig().environment.disableExplosionKnockback ? 0 : d12 * (1.0D - entityliving.getAttributeValue(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE));
|
||||
} else {
|
||||
d13 = d12;
|
||||
}
|
||||
@@ -310,7 +310,7 @@ public class Explosion {
|
||||
if (entity instanceof Player) {
|
||||
Player entityhuman = (Player) entity;
|
||||
|
||||
- if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying)) {
|
||||
+ if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying) && !level.paperConfig().environment.disableExplosionKnockback) { // Paper - Option to disable explosion knockback
|
||||
this.hitPlayers.put(entityhuman, vec3d1);
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sudzzy <originmc@outlook.com>
|
||||
Date: Wed, 2 Mar 2016 14:52:43 -0600
|
||||
Subject: [PATCH] Disable thunder
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 754045e71f180862fa57fd1c97e5d7deb1d788e6..aca595551c90d5515309c9c82ad6ffcfa1d680c8 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -616,7 +616,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
ProfilerFiller gameprofilerfiller = this.getProfiler();
|
||||
|
||||
gameprofilerfiller.push("thunder");
|
||||
- if (flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot
|
||||
+ if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder
|
||||
BlockPos blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
|
||||
|
||||
if (this.isRainingAt(blockposition)) {
|
|
@ -1,24 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sudzzy <originmc@outlook.com>
|
||||
Date: Wed, 2 Mar 2016 14:57:24 -0600
|
||||
Subject: [PATCH] Disable ice and snow
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index aca595551c90d5515309c9c82ad6ffcfa1d680c8..6d89dc22e28a9c3557d9972be0935d75719e7f7d 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -646,11 +646,13 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
gameprofilerfiller.popPush("iceandsnow");
|
||||
|
||||
+ if (!this.paperConfig().environment.disableIceAndSnow) { // Paper - Option to disable ice and snow
|
||||
for (int l = 0; l < randomTickSpeed; ++l) {
|
||||
if (this.random.nextInt(48) == 0) {
|
||||
this.tickPrecipitation(this.getBlockRandomPos(j, 0, k, 15));
|
||||
}
|
||||
}
|
||||
+ } // Paper - Option to disable ice and snow
|
||||
|
||||
gameprofilerfiller.popPush("tickBlocks");
|
||||
timings.chunkTicksBlocks.startTiming(); // Paper
|
|
@ -1,39 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sudzzy <originmc@outlook.com>
|
||||
Date: Wed, 2 Mar 2016 15:03:53 -0600
|
||||
Subject: [PATCH] Configurable mob spawner tick rate
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
index 418e29971326008ebca0cc4b696a41a49c1c7bb7..aa54237205989f619ac6a3faa2e4285427b9e31d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -49,6 +49,7 @@ public abstract class BaseSpawner {
|
||||
public int maxNearbyEntities = 6;
|
||||
public int requiredPlayerRange = 16;
|
||||
public int spawnRange = 4;
|
||||
+ private int tickDelay = 0; // Paper - Configurable mob spawner tick rate
|
||||
|
||||
public BaseSpawner() {}
|
||||
|
||||
@@ -83,13 +84,18 @@ public abstract class BaseSpawner {
|
||||
}
|
||||
|
||||
public void serverTick(ServerLevel world, BlockPos pos) {
|
||||
+ // Paper start - Configurable mob spawner tick rate
|
||||
+ if (spawnDelay > 0 && --tickDelay > 0) return;
|
||||
+ tickDelay = world.paperConfig().tickRates.mobSpawner;
|
||||
+ if (tickDelay == -1) { return; } // If disabled
|
||||
+ // Paper end - Configurable mob spawner tick rate
|
||||
if (this.isNearPlayer(world, pos)) {
|
||||
- if (this.spawnDelay == -1) {
|
||||
+ if (this.spawnDelay < -tickDelay) { // Paper - Configurable mob spawner tick rate
|
||||
this.delay(world, pos);
|
||||
}
|
||||
|
||||
if (this.spawnDelay > 0) {
|
||||
- --this.spawnDelay;
|
||||
+ this.spawnDelay -= tickDelay; // Paper - Configurable mob spawner tick rate
|
||||
} else {
|
||||
boolean flag = false;
|
||||
RandomSource randomsource = world.getRandom();
|
|
@ -1,53 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Isaac Moore <rmsy@me.com>
|
||||
Date: Tue, 19 Apr 2016 14:09:31 -0500
|
||||
Subject: [PATCH] Use null Locale by default
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index ee5188f3aa2ff71306f5af8046e8ddf919c8601b..13a069483db22f25008bf4081d4aa2b36a75bc68 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -237,7 +237,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
private int levitationStartTime;
|
||||
private boolean disconnected;
|
||||
private int requestedViewDistance;
|
||||
- public String language = "en_us"; // CraftBukkit - default
|
||||
+ public String language = null; // CraftBukkit - default // Paper - default to null
|
||||
public java.util.Locale adventure$locale = java.util.Locale.US; // Paper
|
||||
@Nullable
|
||||
private Vec3 startingToFallPosition;
|
||||
@@ -293,7 +293,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
this.lastActionTime = Util.getMillis();
|
||||
this.recipeBook = new ServerRecipeBook();
|
||||
this.requestedViewDistance = 2;
|
||||
- this.language = "en_us";
|
||||
+ this.language = null; // Paper - default to null
|
||||
this.lastSectionPos = SectionPos.of(0, 0, 0);
|
||||
this.chunkTrackingView = ChunkTrackingView.EMPTY;
|
||||
this.respawnDimension = Level.OVERWORLD;
|
||||
@@ -2051,7 +2051,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), this.getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT);
|
||||
this.server.server.getPluginManager().callEvent(event);
|
||||
}
|
||||
- if (!this.language.equals(clientOptions.language())) {
|
||||
+ if (this.language == null || !this.language.equals(clientOptions.language())) { // Paper
|
||||
PlayerLocaleChangeEvent event = new PlayerLocaleChangeEvent(this.getBukkitEntity(), clientOptions.language());
|
||||
this.server.server.getPluginManager().callEvent(event);
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 1a003335a4f3cc2fdeadca9c0c6cdafa61a6a1ac..fb5548b92a0fe7866cf98e25293c4b0702344c9b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -2423,7 +2423,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
@Override
|
||||
public String getLocale() {
|
||||
- return this.getHandle().language;
|
||||
+ // Paper start - Locale change event
|
||||
+ final String locale = this.getHandle().language;
|
||||
+ return locale != null ? locale : "en_us";
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
// Paper start
|
|
@ -1,66 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Byteflux <byte@byteflux.net>
|
||||
Date: Wed, 2 Mar 2016 23:30:53 -0600
|
||||
Subject: [PATCH] Add BeaconEffectEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
|
||||
index 9fc5f72ac2d23a03584d3c0357bc1a55ea40bab3..fc915797d2a085447747d9ce23a5a354fb3eb6b6 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.minecraft.world.level.block.entity;
|
||||
|
||||
+import com.destroystokyo.paper.event.block.BeaconEffectEvent;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.Collection;
|
||||
@@ -46,6 +47,7 @@ import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
// CraftBukkit start
|
||||
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||
import org.bukkit.craftbukkit.potion.CraftPotionUtil;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
// CraftBukkit end
|
||||
@@ -295,15 +297,23 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name
|
||||
}
|
||||
}
|
||||
|
||||
- private static void applyEffect(List list, @Nullable Holder<MobEffect> holder, int j, int b0) {
|
||||
- {
|
||||
+ private static void applyEffect(List list, @Nullable Holder<MobEffect> holder, int j, int b0, boolean isPrimary, BlockPos worldPosition) { // Paper - BeaconEffectEvent
|
||||
+ if (!list.isEmpty()) { // Paper - BeaconEffectEvent
|
||||
Iterator iterator = list.iterator();
|
||||
|
||||
Player entityhuman;
|
||||
+ // Paper start - BeaconEffectEvent
|
||||
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(((Player) list.get(0)).level(), worldPosition);
|
||||
+ PotionEffect effect = CraftPotionUtil.toBukkit(new MobEffectInstance(holder, j, b0, true, true));
|
||||
+ // Paper end - BeaconEffectEvent
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
- entityhuman = (Player) iterator.next();
|
||||
- entityhuman.addEffect(new MobEffectInstance(holder, j, b0, true, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.BEACON);
|
||||
+ // Paper start - BeaconEffectEvent
|
||||
+ entityhuman = (ServerPlayer) iterator.next();
|
||||
+ BeaconEffectEvent event = new BeaconEffectEvent(block, effect, (org.bukkit.entity.Player) entityhuman.getBukkitEntity(), isPrimary);
|
||||
+ if (CraftEventFactory.callEvent(event).isCancelled()) continue;
|
||||
+ entityhuman.addEffect(new MobEffectInstance(CraftPotionUtil.fromBukkit(event.getEffect())), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.BEACON);
|
||||
+ // Paper end - BeaconEffectEvent
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,10 +336,10 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name
|
||||
int j = BeaconBlockEntity.getLevel(beaconLevel);
|
||||
List list = BeaconBlockEntity.getHumansInRange(world, pos, beaconLevel);
|
||||
|
||||
- BeaconBlockEntity.applyEffect(list, primaryEffect, j, b0);
|
||||
+ BeaconBlockEntity.applyEffect(list, primaryEffect, j, b0, true, pos); // Paper - BeaconEffectEvent
|
||||
|
||||
if (BeaconBlockEntity.hasSecondaryEffect(beaconLevel, primaryEffect, secondaryEffect)) {
|
||||
- BeaconBlockEntity.applyEffect(list, secondaryEffect, j, 0);
|
||||
+ BeaconBlockEntity.applyEffect(list, secondaryEffect, j, 0, false, pos); // Paper - BeaconEffectEvent
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sudzzy <originmc@outlook.com>
|
||||
Date: Wed, 2 Mar 2016 23:34:44 -0600
|
||||
Subject: [PATCH] Configurable container update tick rate
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index e61460a06708429738e0ed5f903a4226158aa334..ed920ed90569b7b8886a09a1c3772fd7147d44f9 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -268,6 +268,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
public final Object object;
|
||||
private int containerCounter;
|
||||
public boolean wonGame;
|
||||
+ private int containerUpdateDelay; // Paper - Configurable container update tick rate
|
||||
|
||||
// CraftBukkit start
|
||||
public CraftPlayer.TransferCookieConnection transferCookieConnection;
|
||||
@@ -696,7 +697,12 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
--this.invulnerableTime;
|
||||
}
|
||||
|
||||
- this.containerMenu.broadcastChanges();
|
||||
+ // Paper start - Configurable container update tick rate
|
||||
+ if (--containerUpdateDelay <= 0) {
|
||||
+ this.containerMenu.broadcastChanges();
|
||||
+ containerUpdateDelay = this.level().paperConfig().tickRates.containerUpdate;
|
||||
+ }
|
||||
+ // Paper end - Configurable container update tick rate
|
||||
if (!this.level().isClientSide && !this.containerMenu.stillValid(this)) {
|
||||
this.closeContainer();
|
||||
this.containerMenu = this.inventoryMenu;
|
|
@ -1,25 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Techcable <Techcable@outlook.com>
|
||||
Date: Wed, 2 Mar 2016 23:42:37 -0600
|
||||
Subject: [PATCH] Use UserCache for player heads
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
|
||||
index 43609c99347c2e3e6ee9a1b8926b32b458781fba..7181d81c231908f208b48a29f918136cb143f476 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
|
||||
@@ -172,7 +172,13 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
|
||||
if (name == null) {
|
||||
this.setProfile(null);
|
||||
} else {
|
||||
- this.setProfile(new ResolvableProfile(new GameProfile(Util.NIL_UUID, name)));
|
||||
+ // Paper start - Use Online Players Skull
|
||||
+ GameProfile newProfile = null;
|
||||
+ net.minecraft.server.level.ServerPlayer player = net.minecraft.server.MinecraftServer.getServer().getPlayerList().getPlayerByName(name);
|
||||
+ if (player != null) newProfile = player.getGameProfile();
|
||||
+ if (newProfile == null) newProfile = new GameProfile(Util.NIL_UUID, name);
|
||||
+ this.setProfile(new ResolvableProfile(newProfile));
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
return true;
|
|
@ -1,21 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Wed, 2 Mar 2016 23:45:17 -0600
|
||||
Subject: [PATCH] Disable spigot tick limiters
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index da7b1b705da9f17de858f72a20d3a932cd8f7fad..68436413645e0e33f22cdee0ea101ca01b343d75 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -704,9 +704,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
boolean flag = this.tickRateManager().runsNormally();
|
||||
|
||||
int tilesThisCycle = 0;
|
||||
- for (this.tileLimiter.initTick();
|
||||
- tilesThisCycle < this.blockEntityTickers.size() && (tilesThisCycle % 10 != 0 || this.tileLimiter.shouldContinue());
|
||||
- this.tileTickPosition++, tilesThisCycle++) {
|
||||
+ for (tileTickPosition = 0; tileTickPosition < this.blockEntityTickers.size(); tileTickPosition++) { // Paper - Disable tick limiters
|
||||
this.tileTickPosition = (this.tileTickPosition < this.blockEntityTickers.size()) ? this.tileTickPosition : 0;
|
||||
TickingBlockEntity tickingblockentity = (TickingBlockEntity) this.blockEntityTickers.get(this.tileTickPosition);
|
||||
// Spigot end
|
|
@ -1,24 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Steve Anton <anxuiz.nx@gmail.com>
|
||||
Date: Thu, 3 Mar 2016 00:09:38 -0600
|
||||
Subject: [PATCH] Fix spawn location event changing location
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.Entity setRot(FF)V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 765c412cd0c5cd410c224b4bc55dbf431fd6617b..8a91a44e46a2d49e2f4b9e9970c2b77f2e87767e 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -234,7 +234,10 @@ public abstract class PlayerList {
|
||||
|
||||
player.spawnIn(worldserver1);
|
||||
player.gameMode.setLevel((ServerLevel) player.level());
|
||||
- player.absMoveTo(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
|
||||
+ // Paper start - set raw so we aren't fully joined to the world (not added to chunk or world)
|
||||
+ player.setPosRaw(loc.getX(), loc.getY(), loc.getZ());
|
||||
+ player.setRot(loc.getYaw(), loc.getPitch());
|
||||
+ // Paper end - set raw so we aren't fully joined to the world
|
||||
// Spigot end
|
||||
|
||||
// CraftBukkit - Moved message to after join
|
|
@ -1,23 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 3 Mar 2016 01:13:45 -0600
|
||||
Subject: [PATCH] Configurable Disabling Cat Chest Detection
|
||||
|
||||
Offers a gameplay feature to stop cats from blocking chests
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/ChestBlock.java b/src/main/java/net/minecraft/world/level/block/ChestBlock.java
|
||||
index e197891f61580f92787d9400ff486439a92a54c7..8fbfd18b3caeed769396b3ffb1b1778b2f38edc0 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/ChestBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/ChestBlock.java
|
||||
@@ -349,6 +349,11 @@ public class ChestBlock extends AbstractChestBlock<ChestBlockEntity> implements
|
||||
}
|
||||
|
||||
private static boolean isCatSittingOnChest(LevelAccessor world, BlockPos pos) {
|
||||
+ // Paper start - Option to disable chest cat detection
|
||||
+ if (world.getMinecraftWorld().paperConfig().entities.behavior.disableChestCatDetection) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - Option to disable chest cat detection
|
||||
List<Cat> list = world.getEntitiesOfClass(Cat.class, new AABB((double) pos.getX(), (double) (pos.getY() + 1), (double) pos.getZ(), (double) (pos.getX() + 1), (double) (pos.getY() + 2), (double) (pos.getZ() + 1)));
|
||||
|
||||
if (!list.isEmpty()) {
|
|
@ -1,80 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 3 Mar 2016 01:17:12 -0600
|
||||
Subject: [PATCH] Improve Player chat API handling
|
||||
|
||||
Properly split up the chat and command handling to reflect the server now
|
||||
having separate packets for both, and the client always using the correct packet. Text
|
||||
from a chat packet should never be parsed into a command, even if it starts with the `/`
|
||||
character.
|
||||
|
||||
Add a missing async catcher and improve Spigot's async catcher error message.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.server.network.ServerGamePacketListenerImpl isChatMessageIllegal(Ljava/lang/String;)Z
|
||||
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Co-authored-by: SoSeDiK <mrsosedik@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 3a67b2b6a6d3204b2a7bbe8adbf2b0ecf7898551..02b9e1ed57f5d65698c461387ff7d48450e6a70f 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2013,7 +2013,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
OutgoingChatMessage outgoing = OutgoingChatMessage.create(original);
|
||||
|
||||
- if (!async && s.startsWith("/")) {
|
||||
+ if (false && !async && s.startsWith("/")) { // Paper - Don't handle commands in chat logic
|
||||
this.handleCommand(s);
|
||||
} else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) {
|
||||
// Do nothing, this is coming from a plugin
|
||||
@@ -2100,7 +2100,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
- private void handleCommand(String s) {
|
||||
+ public void handleCommand(String s) { // Paper - private -> public
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + s); // Paper - Add async catcher
|
||||
co.aikar.timings.MinecraftTimings.playerCommandTimer.startTiming(); // Paper
|
||||
if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot
|
||||
this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 8f79d7611c3ee1c817d5671152e459ec4f413418..441a8d3355e0db773a5da330bf9361234da1ca89 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -934,7 +934,7 @@ public final class CraftServer implements Server {
|
||||
public boolean dispatchCommand(CommandSender sender, String commandLine) {
|
||||
Preconditions.checkArgument(sender != null, "sender cannot be null");
|
||||
Preconditions.checkArgument(commandLine != null, "commandLine cannot be null");
|
||||
- org.spigotmc.AsyncCatcher.catchOp("command dispatch"); // Spigot
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + commandLine); // Spigot // Paper - Include command in error message
|
||||
|
||||
if (this.commandMap.dispatch(sender, commandLine)) {
|
||||
return true;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 545da59af2436b9a4363ec459456c8f15650b79f..9751cace64d9ad2b8b55080b13834e8ccb056b42 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -546,7 +546,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
if (this.getHandle().connection == null) return;
|
||||
|
||||
- this.getHandle().connection.chat(msg, PlayerChatMessage.system(msg), false);
|
||||
+ // Paper start - Improve chat handling
|
||||
+ if (ServerGamePacketListenerImpl.isChatMessageIllegal(msg)) {
|
||||
+ this.getHandle().connection.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"));
|
||||
+ } else {
|
||||
+ if (msg.startsWith("/")) {
|
||||
+ this.getHandle().connection.handleCommand(msg);
|
||||
+ } else {
|
||||
+ final PlayerChatMessage playerChatMessage = PlayerChatMessage.system(msg).withUnsignedContent(Component.literal(msg));
|
||||
+ // TODO chat decorating
|
||||
+ // TODO text filtering
|
||||
+ this.getHandle().connection.chat(msg, playerChatMessage, false);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Improve chat handling
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,32 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: vemacs <d@nkmem.es>
|
||||
Date: Thu, 3 Mar 2016 01:19:22 -0600
|
||||
Subject: [PATCH] All chunks are slime spawn chunks toggle
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java
|
||||
index b7e6f6e195d8b947c06e2bf58f4c644bda8eba99..b1f7ea02e533660322675e1bddb070f0a41084f2 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Slime.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java
|
||||
@@ -350,7 +350,7 @@ public class Slime extends Mob implements Enemy {
|
||||
}
|
||||
|
||||
ChunkPos chunkcoordintpair = new ChunkPos(pos);
|
||||
- boolean flag = WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot
|
||||
+ boolean flag = world.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper
|
||||
|
||||
if (random.nextInt(10) == 0 && flag && pos.getY() < 40) {
|
||||
return checkMobSpawnRules(type, world, spawnReason, pos, random);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
index 5db1be69f0c4ef6976789587866c7a9bb6d19b0d..e37dae711e7059834612ead5f4fcea9f28ad436f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
@@ -218,7 +218,7 @@ public class CraftChunk implements Chunk {
|
||||
@Override
|
||||
public boolean isSlimeChunk() {
|
||||
// 987234911L is deterimined in EntitySlime when seeing if a slime can spawn in a chunk
|
||||
- return WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), this.worldServer.spigotConfig.slimeSeed).nextInt(10) == 0;
|
||||
+ return this.worldServer.paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0; // Paper
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,18 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kashike <kashike@vq.lc>
|
||||
Date: Thu, 3 Mar 2016 02:15:57 -0600
|
||||
Subject: [PATCH] Expose server CommandMap
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 441a8d3355e0db773a5da330bf9361234da1ca89..32d1e4bc8279a9adb83501c99fc7ff33d4c7f81c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2179,6 +2179,7 @@ public final class CraftServer implements Server {
|
||||
return this.helpMap;
|
||||
}
|
||||
|
||||
+ @Override // Paper - add override
|
||||
public SimpleCommandMap getCommandMap() {
|
||||
return this.commandMap;
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kashike <kashike@vq.lc>
|
||||
Date: Thu, 3 Mar 2016 02:18:39 -0600
|
||||
Subject: [PATCH] Be a bit more informative in maxHealth exception
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
index 5ce03fa25e0a03025501a7f86a8f3c64f3fd7c77..ff2118fb463168e061ca9152183e19d593b476e9 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -103,7 +103,12 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
@Override
|
||||
public void setHealth(double health) {
|
||||
health = (float) health;
|
||||
- Preconditions.checkArgument(health >= 0 && health <= this.getMaxHealth(), "Health value (%s) must be between 0 and %s", health, this.getMaxHealth());
|
||||
+ // Paper start - Be more informative
|
||||
+ Preconditions.checkArgument(health >= 0 && health <= this.getMaxHealth(),
|
||||
+ "Health value (%s) must be between 0 and %s. (attribute base value: %s%s)",
|
||||
+ health, this.getMaxHealth(), this.getHandle().getAttribute(Attributes.MAX_HEALTH).getBaseValue(), this instanceof CraftPlayer ? ", player: " + this.getName() : ""
|
||||
+ );
|
||||
+ // Paper end
|
||||
|
||||
// during world generation, we don't want to run logic for dropping items and xp
|
||||
if (this.getHandle().generation && health == 0) {
|
|
@ -1,109 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Techcable <Techcable@outlook.com>
|
||||
Date: Thu, 3 Mar 2016 02:32:10 -0600
|
||||
Subject: [PATCH] Player Tab List and Title APIs
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 9751cace64d9ad2b8b55080b13834e8ccb056b42..951b89ced33b2a12dff90e32201643bee64962e1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -388,6 +388,98 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void setPlayerListHeaderFooter(BaseComponent[] header, BaseComponent[] footer) {
|
||||
+ if (header != null) {
|
||||
+ String headerJson = net.md_5.bungee.chat.ComponentSerializer.toString(header);
|
||||
+ playerListHeader = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(headerJson);
|
||||
+ } else {
|
||||
+ playerListHeader = null;
|
||||
+ }
|
||||
+
|
||||
+ if (footer != null) {
|
||||
+ String footerJson = net.md_5.bungee.chat.ComponentSerializer.toString(footer);
|
||||
+ playerListFooter = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(footerJson);
|
||||
+ } else {
|
||||
+ playerListFooter = null;
|
||||
+ }
|
||||
+
|
||||
+ updatePlayerListHeaderFooter();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setPlayerListHeaderFooter(BaseComponent header, BaseComponent footer) {
|
||||
+ this.setPlayerListHeaderFooter(header == null ? null : new BaseComponent[]{header},
|
||||
+ footer == null ? null : new BaseComponent[]{footer});
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ @Override
|
||||
+ public void setTitleTimes(int fadeInTicks, int stayTicks, int fadeOutTicks) {
|
||||
+ getHandle().connection.send(new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSubtitle(BaseComponent[] subtitle) {
|
||||
+ final ClientboundSetSubtitleTextPacket packet = new ClientboundSetSubtitleTextPacket(org.bukkit.craftbukkit.util.CraftChatMessage.fromJSON(net.md_5.bungee.chat.ComponentSerializer.toString(subtitle)));
|
||||
+ getHandle().connection.send(packet);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSubtitle(BaseComponent subtitle) {
|
||||
+ setSubtitle(new BaseComponent[]{subtitle});
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void showTitle(BaseComponent[] title) {
|
||||
+ final ClientboundSetTitleTextPacket packet = new ClientboundSetTitleTextPacket(org.bukkit.craftbukkit.util.CraftChatMessage.fromJSON(net.md_5.bungee.chat.ComponentSerializer.toString(title)));
|
||||
+ getHandle().connection.send(packet);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void showTitle(BaseComponent title) {
|
||||
+ showTitle(new BaseComponent[]{title});
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void showTitle(BaseComponent[] title, BaseComponent[] subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
|
||||
+ setTitleTimes(fadeInTicks, stayTicks, fadeOutTicks);
|
||||
+ setSubtitle(subtitle);
|
||||
+ showTitle(title);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void showTitle(BaseComponent title, BaseComponent subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
|
||||
+ setTitleTimes(fadeInTicks, stayTicks, fadeOutTicks);
|
||||
+ setSubtitle(subtitle);
|
||||
+ showTitle(title);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void sendTitle(com.destroystokyo.paper.Title title) {
|
||||
+ Preconditions.checkNotNull(title, "Title is null");
|
||||
+ setTitleTimes(title.getFadeIn(), title.getStay(), title.getFadeOut());
|
||||
+ setSubtitle(title.getSubtitle() == null ? new BaseComponent[0] : title.getSubtitle());
|
||||
+ showTitle(title.getTitle());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void updateTitle(com.destroystokyo.paper.Title title) {
|
||||
+ Preconditions.checkNotNull(title, "Title is null");
|
||||
+ setTitleTimes(title.getFadeIn(), title.getStay(), title.getFadeOut());
|
||||
+ if (title.getSubtitle() != null) {
|
||||
+ setSubtitle(title.getSubtitle());
|
||||
+ }
|
||||
+ showTitle(title.getTitle());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void hideTitle() {
|
||||
+ getHandle().connection.send(new ClientboundClearTitlesPacket(false));
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
if(true) return io.papermc.paper.adventure.DisplayNames.getLegacy(this); // Paper
|
|
@ -1,38 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Joseph Hirschfeld <joe@ibj.io>
|
||||
Date: Thu, 3 Mar 2016 02:46:17 -0600
|
||||
Subject: [PATCH] Add configurable portal search radius
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
||||
index 462afb22cce2376789e44283032e63a6264cf851..8072e67f7b2f5944670159d3de1b01090bd1019d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
||||
@@ -139,8 +139,14 @@ public class NetherPortalBlock extends Block implements Portal {
|
||||
WorldBorder worldborder = worldserver1.getWorldBorder();
|
||||
double d0 = DimensionType.getTeleportationScale(world.dimensionType(), worldserver1.dimensionType());
|
||||
BlockPos blockposition1 = worldborder.clampToBounds(entity.getX() * d0, entity.getY(), entity.getZ() * d0);
|
||||
+ // Paper start - Configurable portal search radius
|
||||
+ int portalSearchRadius = worldserver1.paperConfig().environment.portalSearchRadius;
|
||||
+ if (entity.level().paperConfig().environment.portalSearchVanillaDimensionScaling && flag) { // flag = is going to nether
|
||||
+ portalSearchRadius = (int) (portalSearchRadius / worldserver1.dimensionType().coordinateScale());
|
||||
+ }
|
||||
+ // Paper end - Configurable portal search radius
|
||||
// CraftBukkit start
|
||||
- CraftPortalEvent event = entity.callPortalEvent(entity, CraftLocation.toBukkit(blockposition1, worldserver1.getWorld()), PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, flag ? 16 : 128, 16);
|
||||
+ CraftPortalEvent event = entity.callPortalEvent(entity, CraftLocation.toBukkit(blockposition1, worldserver1.getWorld()), PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, portalSearchRadius, worldserver1.paperConfig().environment.portalCreateRadius); // Paper - use custom portal search radius
|
||||
if (event == null) {
|
||||
return null;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
index aef1dd28da7e0c0a13a0a7a5b52daa27635c48ea..5c4b2a33d4007c36aef68604bca40a4eba510b4e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
@@ -42,6 +42,7 @@ public class PortalForcer {
|
||||
this.level = world;
|
||||
}
|
||||
|
||||
+ @io.papermc.paper.annotation.DoNotUse // Paper
|
||||
public Optional<BlockPos> findClosestPortalPosition(BlockPos pos, boolean destIsNether, WorldBorder worldBorder) {
|
||||
// CraftBukkit start
|
||||
return this.findClosestPortalPosition(pos, worldBorder, destIsNether ? 16 : 128); // Search Radius
|
|
@ -1,85 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Joseph Hirschfeld <joe@ibj.io>
|
||||
Date: Thu, 3 Mar 2016 02:48:12 -0600
|
||||
Subject: [PATCH] Add velocity warnings
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 4bfb836513d5194be271f4a82990ace98de69640..fd31d0e76d1a953b128e777b1bc27e24b1e03ed7 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -302,6 +302,7 @@ public final class CraftServer implements Server {
|
||||
private final List<CraftPlayer> playerView;
|
||||
public int reloadCount;
|
||||
public Set<String> activeCompatibilities = Collections.emptySet();
|
||||
+ public static Exception excessiveVelEx; // Paper - Velocity warnings
|
||||
|
||||
static {
|
||||
ConfigurationSerialization.registerClass(CraftOfflinePlayer.class);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index 7b45a1216ff824f1b528bb5759d10b70858832a1..df6da730134da754d0ff23bd1b57c82486b9ab73 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -131,10 +131,40 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
public void setVelocity(Vector velocity) {
|
||||
Preconditions.checkArgument(velocity != null, "velocity");
|
||||
velocity.checkFinite();
|
||||
+ // Paper start - Warn server owners when plugins try to set super high velocities
|
||||
+ if (!(this instanceof org.bukkit.entity.Projectile || this instanceof org.bukkit.entity.Minecart) && isUnsafeVelocity(velocity)) {
|
||||
+ CraftServer.excessiveVelEx = new Exception("Excessive velocity set detected: tried to set velocity of entity " + entity.getScoreboardName() + " id #" + getEntityId() + " to (" + velocity.getX() + "," + velocity.getY() + "," + velocity.getZ() + ").");
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.entity.setDeltaMovement(CraftVector.toNMS(velocity));
|
||||
this.entity.hurtMarked = true;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ /**
|
||||
+ * Checks if the given velocity is not necessarily safe in all situations.
|
||||
+ * This function returning true does not mean the velocity is dangerous or to be avoided, only that it may be
|
||||
+ * a detriment to performance on the server.
|
||||
+ *
|
||||
+ * It is not to be used as a hard rule of any sort.
|
||||
+ * Paper only uses it to warn server owners in watchdog crashes.
|
||||
+ *
|
||||
+ * @param vel incoming velocity to check
|
||||
+ * @return if the velocity has the potential to be a performance detriment
|
||||
+ */
|
||||
+ private static boolean isUnsafeVelocity(Vector vel) {
|
||||
+ final double x = vel.getX();
|
||||
+ final double y = vel.getY();
|
||||
+ final double z = vel.getZ();
|
||||
+
|
||||
+ if (x > 4 || x < -4 || y > 4 || y < -4 || z > 4 || z < -4) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public double getHeight() {
|
||||
return this.getHandle().getBbHeight();
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index e086765dec32241bc5a77afcf072c77a40c6d785..35c90aaee30980610d168c01cbe9abfe04331cb8 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -81,6 +81,17 @@ public class WatchdogThread extends Thread
|
||||
log.log( Level.SEVERE, "near " + net.minecraft.world.level.Level.lastPhysicsProblem );
|
||||
}
|
||||
//
|
||||
+ // Paper start - Warn in watchdog if an excessive velocity was ever set
|
||||
+ if (org.bukkit.craftbukkit.CraftServer.excessiveVelEx != null) {
|
||||
+ log.log(Level.SEVERE, "------------------------------");
|
||||
+ log.log(Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity");
|
||||
+ log.log(Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated");
|
||||
+ log.log(Level.SEVERE, org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getMessage());
|
||||
+ for (StackTraceElement stack : org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getStackTrace()) {
|
||||
+ log.log( Level.SEVERE, "\t\t" + stack );
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
||||
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
|
@ -1,207 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Joseph Hirschfeld <joe@ibj.io>
|
||||
Date: Thu, 3 Mar 2016 03:15:41 -0600
|
||||
Subject: [PATCH] Add exception reporting event
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java b/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..f699ce18ca044f813e194ef2786b7ea853ea86e7
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java
|
||||
@@ -0,0 +1,38 @@
|
||||
+package com.destroystokyo.paper;
|
||||
+
|
||||
+import com.google.common.base.Preconditions;
|
||||
+import org.bukkit.craftbukkit.scheduler.CraftTask;
|
||||
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
|
||||
+import com.destroystokyo.paper.exception.ServerSchedulerException;
|
||||
+
|
||||
+/**
|
||||
+ * Reporting wrapper to catch exceptions not natively
|
||||
+ */
|
||||
+public class ServerSchedulerReportingWrapper implements Runnable {
|
||||
+
|
||||
+ private final CraftTask internalTask;
|
||||
+
|
||||
+ public ServerSchedulerReportingWrapper(CraftTask internalTask) {
|
||||
+ this.internalTask = Preconditions.checkNotNull(internalTask, "internalTask");
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void run() {
|
||||
+ try {
|
||||
+ internalTask.run();
|
||||
+ } catch (RuntimeException e) {
|
||||
+ internalTask.getOwner().getServer().getPluginManager().callEvent(
|
||||
+ new ServerExceptionEvent(new ServerSchedulerException(e, internalTask))
|
||||
+ );
|
||||
+ throw e;
|
||||
+ } catch (Throwable t) {
|
||||
+ internalTask.getOwner().getServer().getPluginManager().callEvent(
|
||||
+ new ServerExceptionEvent(new ServerSchedulerException(t, internalTask))
|
||||
+ ); //Do not rethrow, since it is not permitted with Runnable#run
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public CraftTask getInternalTask() {
|
||||
+ return internalTask;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
index 68551947f5b7d3471f15bd74ccd86519ab34c1c1..a0b0614ac7d2009db5c6c10ab4a5f09dd447c635 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
@@ -356,7 +356,11 @@ public class OldUsersConverter {
|
||||
try {
|
||||
root = NbtIo.readCompressed(new java.io.FileInputStream(file5), NbtAccounter.unlimitedHeap());
|
||||
} catch (Exception exception) {
|
||||
- io.papermc.paper.util.TraceUtil.printStackTrace(exception); // Paper
|
||||
+ // Paper start
|
||||
+ io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception);
|
||||
+ exception.printStackTrace();
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
if (root != null) {
|
||||
@@ -369,7 +373,11 @@ public class OldUsersConverter {
|
||||
try {
|
||||
NbtIo.writeCompressed(root, new java.io.FileOutputStream(file2));
|
||||
} catch (Exception exception) {
|
||||
- io.papermc.paper.util.TraceUtil.printStackTrace(exception); // Paper
|
||||
+ // Paper start
|
||||
+ io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception);
|
||||
+ exception.printStackTrace();
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception);
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
|
||||
index 8183c26b4a5ad169a53702b8c45fd05cda934e80..36dec6cd78a0990ba3c09a4a748c259ef5c0a2ff 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
|
||||
@@ -117,6 +117,7 @@ public class VillageSiege implements CustomSpawner {
|
||||
entityzombie.finalizeSpawn(world, world.getCurrentDifficultyAt(entityzombie.blockPosition()), MobSpawnType.EVENT, (SpawnGroupData) null);
|
||||
} catch (Exception exception) {
|
||||
VillageSiege.LOGGER.warn("Failed to create zombie for village siege at {}", vec3d, exception);
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper - ServerExceptionEvent
|
||||
return;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index b4293991dddc9039c26106ac8c047e5aeec35a56..32b42d25631aecdd31db4954a8bbf38bcda98d6b 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -733,6 +733,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
// Paper start - Prevent block entity and entity crashes
|
||||
final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
|
||||
MinecraftServer.LOGGER.error(msg, throwable);
|
||||
+ getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable))); // Paper - ServerExceptionEvent
|
||||
entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
||||
// Paper end - Prevent block entity and entity crashes
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
index 6a80479554f0c860a8dd6baa1a6506858fca83e3..6324689f52363f19501143c1649f0885684cb796 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -274,6 +274,7 @@ public final class NaturalSpawner {
|
||||
NaturalSpawner.LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(type));
|
||||
} catch (Exception exception) {
|
||||
NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper - ServerExceptionEvent
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -362,6 +363,7 @@ public final class NaturalSpawner {
|
||||
entity = biomesettingsmobs_c.type.create(world.getLevel());
|
||||
} catch (Exception exception) {
|
||||
NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper - ServerExceptionEvent
|
||||
continue;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 6889991885cc2075e0936b2c480befeef30d308c..4495c5051b0c7a04d433c39d91f74cb7924d3ff2 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -471,8 +471,13 @@ public class LevelChunk extends ChunkAccess {
|
||||
BlockState iblockdata = this.getBlockState(blockposition);
|
||||
|
||||
if (!iblockdata.hasBlockEntity()) {
|
||||
- LevelChunk.LOGGER.warn("Trying to set block entity {} at position {}, but state {} does not allow it", new Object[]{blockEntity, blockposition, iblockdata});
|
||||
- new Exception().printStackTrace(); // CraftBukkit
|
||||
+ // Paper start - ServerExceptionEvent
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException e = new com.destroystokyo.paper.exception.ServerInternalException(
|
||||
+ "Trying to set block entity %s at position %s, but state %s does not allow it".formatted(blockEntity, blockposition, iblockdata)
|
||||
+ );
|
||||
+ e.printStackTrace();
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(e);
|
||||
+ // Paper end - ServerExceptionEvent
|
||||
} else {
|
||||
BlockState iblockdata1 = blockEntity.getBlockState();
|
||||
|
||||
@@ -956,6 +961,7 @@ public class LevelChunk extends ChunkAccess {
|
||||
// Paper start - Prevent block entity and entity crashes
|
||||
final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
|
||||
net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
|
||||
+ net.minecraft.world.level.chunk.LevelChunk.this.level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable))); // Paper - ServerExceptionEvent
|
||||
LevelChunk.this.removeBlockEntity(this.getPos());
|
||||
// Paper end - Prevent block entity and entity crashes
|
||||
// Spigot start
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index 15f273aa592828719de6e092d79a407dc8652dfe..b24e8255ab18eb5b2e4968aa62aa3d72ef33f0eb 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -296,6 +296,7 @@ public class RegionFile implements AutoCloseable {
|
||||
return true;
|
||||
}
|
||||
} catch (IOException ioexception) {
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(ioexception); // Paper - ServerExceptionEvent
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -377,6 +378,7 @@ public class RegionFile implements AutoCloseable {
|
||||
((java.nio.Buffer) buf).position(5); // CraftBukkit - decompile error
|
||||
filechannel.write(buf);
|
||||
} catch (Throwable throwable) {
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(throwable); // Paper - ServerExceptionEvent
|
||||
if (filechannel != null) {
|
||||
try {
|
||||
filechannel.close();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
index 6c0debe3f3b693ed90dd2a39f481cccd8e4f7634..cf9f04e005940f5dd7baf50435f3703fa7c2d4f0 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
@@ -416,20 +416,25 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
try {
|
||||
task.run();
|
||||
} catch (final Throwable throwable) {
|
||||
+ // Paper start
|
||||
+ final String logMessage = String.format(
|
||||
+ "Task #%s for %s generated an exception",
|
||||
+ task.getTaskId(),
|
||||
+ task.getOwner().getDescription().getFullName());
|
||||
task.getOwner().getLogger().log(
|
||||
Level.WARNING,
|
||||
- String.format(
|
||||
- "Task #%s for %s generated an exception",
|
||||
- task.getTaskId(),
|
||||
- task.getOwner().getDescription().getFullName()),
|
||||
+ logMessage,
|
||||
throwable);
|
||||
+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(
|
||||
+ new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerSchedulerException(logMessage, throwable, task)));
|
||||
+ // Paper end
|
||||
} finally {
|
||||
this.currentTask = null;
|
||||
}
|
||||
this.parsePending();
|
||||
} else {
|
||||
this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass()));
|
||||
- this.executor.execute(task);
|
||||
+ this.executor.execute(new com.destroystokyo.paper.ServerSchedulerReportingWrapper(task)); // Paper
|
||||
// We don't need to parse pending
|
||||
// (async tasks must live with race-conditions if they attempt to cancel between these few lines of code)
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 8 Mar 2016 23:25:45 -0500
|
||||
Subject: [PATCH] Disable Scoreboards for non players by default
|
||||
|
||||
Entities collision is checking for scoreboards setting.
|
||||
This is very heavy to do map lookups for every collision to check
|
||||
this setting.
|
||||
|
||||
So avoid looking up scoreboards and short circuit to the "not on a team"
|
||||
logic which is most likely to be true.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index d5f5864b7c1ad4c30f37b360b317b63c129e3a3f..82e57978b79b5275b98a1fa7731c6a23ee861a2f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2934,6 +2934,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
||||
@Nullable
|
||||
public PlayerTeam getTeam() {
|
||||
+ if (!this.level().paperConfig().scoreboards.allowNonPlayerEntitiesOnScoreboards && !(this instanceof Player)) { return null; } // Paper - Perf: Disable Scoreboards for non players by default
|
||||
return this.level().getScoreboard().getPlayersTeam(this.getScoreboardName());
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 97ad63aad3c559feb1e762af1e00fd550aa5b251..ba194f42217f1176ac08123d3bb5cb24e1a6c119 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -848,6 +848,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
String s = nbt.getString("Team");
|
||||
Scoreboard scoreboard = this.level().getScoreboard();
|
||||
PlayerTeam scoreboardteam = scoreboard.getPlayerTeam(s);
|
||||
+ if (!this.level().paperConfig().scoreboards.allowNonPlayerEntitiesOnScoreboards && !(this instanceof net.minecraft.world.entity.player.Player)) { scoreboardteam = null; } // Paper - Perf: Disable Scoreboards for non players by default
|
||||
boolean flag = scoreboardteam != null && scoreboard.addPlayerToTeam(this.getStringUUID(), scoreboardteam);
|
||||
|
||||
if (!flag) {
|
|
@ -1,60 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: mrapple <tony@oc.tc>
|
||||
Date: Sun, 25 Nov 2012 13:43:39 -0600
|
||||
Subject: [PATCH] Add methods for working with arrows stuck in living entities
|
||||
|
||||
Upstream added methods for this, original methods are now
|
||||
deprecated
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
index ff2118fb463168e061ca9152183e19d593b476e9..5ba4105356e4a4808293e86c679d08a3c4cdd245 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -284,10 +284,29 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void setArrowsInBody(int count) {
|
||||
+ public void setArrowsInBody(final int count, final boolean fireEvent) { // Paper
|
||||
Preconditions.checkArgument(count >= 0, "New arrow amount must be >= 0");
|
||||
+ if (!fireEvent) { // Paper
|
||||
this.getHandle().getEntityData().set(net.minecraft.world.entity.LivingEntity.DATA_ARROW_COUNT_ID, count);
|
||||
+ // Paper start
|
||||
+ } else {
|
||||
+ this.getHandle().setArrowCount(count);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+ }
|
||||
+
|
||||
+ // Paper start - Add methods for working with arrows stuck in living entities
|
||||
+ @Override
|
||||
+ public void setNextArrowRemoval(final int ticks) {
|
||||
+ Preconditions.checkArgument(ticks >= 0, "New amount of ticks before next arrow removal must be >= 0");
|
||||
+ this.getHandle().removeArrowTime = ticks;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getNextArrowRemoval() {
|
||||
+ return this.getHandle().removeArrowTime;
|
||||
}
|
||||
+ // Paper end - Add methods for working with arrows stuck in living entities
|
||||
|
||||
@Override
|
||||
public void damage(double amount) {
|
||||
@@ -813,4 +832,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
this.getHandle().persistentInvisibility = invisible;
|
||||
this.getHandle().setSharedFlag(5, invisible);
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public int getArrowsStuck() {
|
||||
+ return this.getHandle().getArrowCount();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setArrowsStuck(final int arrows) {
|
||||
+ this.getHandle().setArrowCount(arrows);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 4 Mar 2013 23:46:10 -0500
|
||||
Subject: [PATCH] Chunk Save Reattempt
|
||||
|
||||
We commonly have "Stream Closed" errors on chunk saving, so this code should re-try to save the chunk in the event of failure and hopefully prevent rollbacks.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index b24e8255ab18eb5b2e4968aa62aa3d72ef33f0eb..12b7d50f49a2184aaf220a4a50a137b217c57124 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -296,7 +296,7 @@ public class RegionFile implements AutoCloseable {
|
||||
return true;
|
||||
}
|
||||
} catch (IOException ioexception) {
|
||||
- com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(ioexception); // Paper - ServerExceptionEvent
|
||||
+ com.destroystokyo.paper.util.SneakyThrow.sneaky(ioexception); // Paper - Chunk save reattempt; we want the upper try/catch to retry this
|
||||
return false;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 40f2f4d052add3b4270d29c843e49fb621e1bc8d..df099d4c7f101f50d40dae99b45c271b02712434 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -134,6 +134,11 @@ public final class RegionFileStorage implements AutoCloseable {
|
||||
|
||||
protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException {
|
||||
RegionFile regionfile = this.getRegionFile(pos, false); // CraftBukkit
|
||||
+ // Paper start - Chunk save reattempt
|
||||
+ int attempts = 0;
|
||||
+ Exception lastException = null;
|
||||
+ while (attempts++ < 5) { try {
|
||||
+ // Paper end - Chunk save reattempt
|
||||
|
||||
if (nbt == null) {
|
||||
regionfile.clear(pos);
|
||||
@@ -158,7 +163,18 @@ public final class RegionFileStorage implements AutoCloseable {
|
||||
dataoutputstream.close();
|
||||
}
|
||||
}
|
||||
+ // Paper start - Chunk save reattempt
|
||||
+ return;
|
||||
+ } catch (Exception ex) {
|
||||
+ lastException = ex;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
+ if (lastException != null) {
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(lastException);
|
||||
+ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to save chunk {}", pos, lastException);
|
||||
+ }
|
||||
+ // Paper end - Chunk save reattempt
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
|
@ -1,49 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jedediah Smith <jedediah@silencegreys.com>
|
||||
Date: Sat, 4 Apr 2015 23:17:52 -0400
|
||||
Subject: [PATCH] Complete resource pack API
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
index b2bddc6183204b9f519549073e38741e1a9322c4..9bfdcdf427f7c0689d346d17942b5902a9138a4e 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
@@ -207,7 +207,11 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
callback.packEventReceived(packet.id(), net.kyori.adventure.resource.ResourcePackStatus.valueOf(packet.action().name()), this.getCraftPlayer());
|
||||
}
|
||||
// Paper end
|
||||
- this.cserver.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(this.getCraftPlayer(), packet.id(), PlayerResourcePackStatusEvent.Status.values()[packet.action().ordinal()])); // CraftBukkit
|
||||
+ // Paper start - store last pack status
|
||||
+ PlayerResourcePackStatusEvent.Status packStatus = PlayerResourcePackStatusEvent.Status.values()[packet.action().ordinal()];
|
||||
+ player.getBukkitEntity().resourcePackStatus = packStatus;
|
||||
+ this.cserver.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(this.getCraftPlayer(), packet.id(), packStatus)); // CraftBukkit
|
||||
+ // Paper end - store last pack status
|
||||
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 951b89ced33b2a12dff90e32201643bee64962e1..a19e1c7821c6abfa4288d8a16e30b2160be742f5 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -208,6 +208,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
private double healthScale = 20;
|
||||
private CraftWorldBorder clientWorldBorder = null;
|
||||
private BorderChangeListener clientWorldBorderListener = this.createWorldBorderListener();
|
||||
+ public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus; // Paper - more resource pack API
|
||||
|
||||
public CraftPlayer(CraftServer server, ServerPlayer entity) {
|
||||
super(server, entity);
|
||||
@@ -2094,6 +2095,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
}
|
||||
// Paper end - adventure
|
||||
|
||||
+ // Paper start - more resource pack API
|
||||
+ @Override
|
||||
+ public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status getResourcePackStatus() {
|
||||
+ return this.resourcePackStatus;
|
||||
+ }
|
||||
+ // Paper end - more resource pack API
|
||||
+
|
||||
@Override
|
||||
public void removeResourcePack(UUID id) {
|
||||
Preconditions.checkArgument(id != null, "Resource pack id cannot be null");
|
|
@ -1,38 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 18 Mar 2016 13:17:38 -0400
|
||||
Subject: [PATCH] Default loading permissions.yml before plugins
|
||||
|
||||
Under previous behavior, plugins were not able to check if a player had a permission
|
||||
if it was defined in permissions.yml. there is no clean way for a plugin to fix that either.
|
||||
|
||||
This will change the order so that by default, permissions.yml loads BEFORE plugins instead of after.
|
||||
|
||||
This gives plugins expected permission checks.
|
||||
|
||||
It also helps improve the expected logic, as servers should set the initial defaults, and then let plugins
|
||||
modify that. Under the previous logic, plugins were unable (cleanly) override permissions.yml.
|
||||
|
||||
A config option has been added for those who depend on the previous behavior, but I don't expect that.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 3043ec179592606050deede2874b0e251b859892..dfd8776ff6cd8be750e77dc4c30f59c28ff1732a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -488,6 +488,7 @@ public final class CraftServer implements Server {
|
||||
if (type == PluginLoadOrder.STARTUP) {
|
||||
this.helpMap.clear();
|
||||
this.helpMap.initializeGeneralTopics();
|
||||
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) loadCustomPermissions(); // Paper
|
||||
}
|
||||
|
||||
Plugin[] plugins = this.pluginManager.getPlugins();
|
||||
@@ -507,7 +508,7 @@ public final class CraftServer implements Server {
|
||||
this.commandMap.registerServerAliases();
|
||||
DefaultPermissions.registerCorePermissions();
|
||||
CraftDefaultPermissions.registerCorePermissions();
|
||||
- this.loadCustomPermissions();
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) this.loadCustomPermissions(); // Paper
|
||||
this.helpMap.initializeCommands();
|
||||
this.syncCommands();
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William <admin@domnian.com>
|
||||
Date: Fri, 18 Mar 2016 03:30:17 -0400
|
||||
Subject: [PATCH] Allow Reloading of Custom Permissions
|
||||
|
||||
https://github.com/PaperMC/Paper/issues/49
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index dfd8776ff6cd8be750e77dc4c30f59c28ff1732a..2b0f69b89d69258a1e9a6a81db5c9d4497417cd7 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2792,5 +2792,23 @@ public final class CraftServer implements Server {
|
||||
}
|
||||
return this.adventure$audiences;
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public void reloadPermissions() {
|
||||
+ pluginManager.clearPermissions();
|
||||
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) loadCustomPermissions();
|
||||
+ for (Plugin plugin : pluginManager.getPlugins()) {
|
||||
+ for (Permission perm : plugin.getDescription().getPermissions()) {
|
||||
+ try {
|
||||
+ pluginManager.addPermission(perm);
|
||||
+ } catch (IllegalArgumentException ex) {
|
||||
+ getLogger().log(Level.WARNING, "Plugin " + plugin.getDescription().getFullName() + " tried to register permission '" + perm.getName() + "' but it's already registered", ex);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) loadCustomPermissions();
|
||||
+ DefaultPermissions.registerCorePermissions();
|
||||
+ CraftDefaultPermissions.registerCorePermissions();
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 18 Mar 2016 13:50:14 -0400
|
||||
Subject: [PATCH] Remove Metadata on reload
|
||||
|
||||
Metadata is not meant to persist reload as things break badly with non primitive types
|
||||
This will remove metadata on reload so it does not crash everything if a plugin uses it.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 2b0f69b89d69258a1e9a6a81db5c9d4497417cd7..b7539a5f7bc20f20f3cd7fb30d87ab7ffc1133c3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1003,8 +1003,16 @@ public final class CraftServer implements Server {
|
||||
world.spigotConfig.init(); // Spigot
|
||||
}
|
||||
|
||||
+ Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
|
||||
this.pluginManager.clearPlugins();
|
||||
this.commandMap.clearCommands();
|
||||
+ // Paper start
|
||||
+ for (Plugin plugin : pluginClone) {
|
||||
+ entityMetadata.removeAll(plugin);
|
||||
+ worldMetadata.removeAll(plugin);
|
||||
+ playerMetadata.removeAll(plugin);
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.reloadData();
|
||||
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
|
||||
io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper
|
|
@ -1,303 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 28 May 2015 23:00:19 -0400
|
||||
Subject: [PATCH] Handle Item Meta Inconsistencies
|
||||
|
||||
First, Enchantment order would blow away seeing 2 items as the same,
|
||||
however the Client forces enchantment list in a certain order, as well
|
||||
as does the /enchant command. Anvils can insert it into forced order,
|
||||
causing 2 same items to be considered different.
|
||||
|
||||
This change makes unhandled NBT Tags and Enchantments use a sorted tree map,
|
||||
so they will always be in a consistent order.
|
||||
|
||||
Additionally, the old enchantment API was never updated when ItemMeta
|
||||
was added, resulting in 2 different ways to modify an items enchantments.
|
||||
|
||||
For consistency, the old API methods now forward to use the
|
||||
ItemMeta API equivalents, and should deprecate the old API's.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java b/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java
|
||||
index a4f8cb2c9dc464e94483f5574cddab85ef407048..8ac485d82c2d2b32f4d54e02c18c2cb2c3df4fa4 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java
|
||||
@@ -26,12 +26,25 @@ import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.component.TooltipProvider;
|
||||
+// Paper start
|
||||
+import it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap;
|
||||
+// Paper end
|
||||
|
||||
public class ItemEnchantments implements TooltipProvider {
|
||||
- public static final ItemEnchantments EMPTY = new ItemEnchantments(new Object2IntOpenHashMap<>(), true);
|
||||
+ // Paper start
|
||||
+ private static final java.util.Comparator<Holder<Enchantment>> ENCHANTMENT_ORDER = java.util.Comparator.comparing(Holder::getRegisteredName);
|
||||
+ public static final ItemEnchantments EMPTY = new ItemEnchantments(new Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), true);
|
||||
+ // Paper end
|
||||
private static final Codec<Integer> LEVEL_CODEC = Codec.intRange(0, 255);
|
||||
- private static final Codec<Object2IntOpenHashMap<Holder<Enchantment>>> LEVELS_CODEC = Codec.unboundedMap(Enchantment.CODEC, LEVEL_CODEC)
|
||||
- .xmap(Object2IntOpenHashMap::new, Function.identity());
|
||||
+ private static final Codec<Object2IntAVLTreeMap<Holder<Enchantment>>> LEVELS_CODEC = Codec.unboundedMap(
|
||||
+ Enchantment.CODEC, LEVEL_CODEC
|
||||
+ )// Paper start - sort enchantments
|
||||
+ .xmap(m -> {
|
||||
+ final Object2IntAVLTreeMap<Holder<Enchantment>> map = new Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER);
|
||||
+ map.putAll(m);
|
||||
+ return map;
|
||||
+ }, Function.identity());
|
||||
+ // Paper end - sort enchantments
|
||||
private static final Codec<ItemEnchantments> FULL_CODEC = RecordCodecBuilder.create(
|
||||
instance -> instance.group(
|
||||
LEVELS_CODEC.fieldOf("levels").forGetter(component -> component.enchantments),
|
||||
@@ -41,16 +54,16 @@ public class ItemEnchantments implements TooltipProvider {
|
||||
);
|
||||
public static final Codec<ItemEnchantments> CODEC = Codec.withAlternative(FULL_CODEC, LEVELS_CODEC, map -> new ItemEnchantments(map, true));
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, ItemEnchantments> STREAM_CODEC = StreamCodec.composite(
|
||||
- ByteBufCodecs.map(Object2IntOpenHashMap::new, Enchantment.STREAM_CODEC, ByteBufCodecs.VAR_INT),
|
||||
+ ByteBufCodecs.map((v) -> new Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), Enchantment.STREAM_CODEC, ByteBufCodecs.VAR_INT),
|
||||
component -> component.enchantments,
|
||||
ByteBufCodecs.BOOL,
|
||||
component -> component.showInTooltip,
|
||||
ItemEnchantments::new
|
||||
);
|
||||
- final Object2IntOpenHashMap<Holder<Enchantment>> enchantments;
|
||||
+ final Object2IntAVLTreeMap<Holder<Enchantment>> enchantments; // Paper
|
||||
public final boolean showInTooltip;
|
||||
|
||||
- ItemEnchantments(Object2IntOpenHashMap<Holder<Enchantment>> enchantments, boolean showInTooltip) {
|
||||
+ ItemEnchantments(Object2IntAVLTreeMap<Holder<Enchantment>> enchantments, boolean showInTooltip) { // Paper
|
||||
this.enchantments = enchantments;
|
||||
this.showInTooltip = showInTooltip;
|
||||
|
||||
@@ -141,7 +154,7 @@ public class ItemEnchantments implements TooltipProvider {
|
||||
}
|
||||
|
||||
public static class Mutable {
|
||||
- private final Object2IntOpenHashMap<Holder<Enchantment>> enchantments = new Object2IntOpenHashMap<>();
|
||||
+ private final Object2IntAVLTreeMap<Holder<Enchantment>> enchantments = new Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER); // Paper
|
||||
public boolean showInTooltip;
|
||||
|
||||
public Mutable(ItemEnchantments enchantmentsComponent) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||
index 17fa2d3db112762bcb8b941b69b8ddcc53f47224..6c76aeddb34239a5acc204a17b2aa2d80e6b2c88 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||
@@ -214,16 +214,13 @@ public final class CraftItemStack extends ItemStack {
|
||||
public void addUnsafeEnchantment(Enchantment ench, int level) {
|
||||
Preconditions.checkArgument(ench != null, "Enchantment cannot be null");
|
||||
|
||||
- if (!CraftItemStack.makeTag(this.handle)) {
|
||||
- return;
|
||||
- }
|
||||
- ItemEnchantments list = CraftItemStack.getEnchantmentList(this.handle);
|
||||
- if (list == null) {
|
||||
- list = ItemEnchantments.EMPTY;
|
||||
+ // Paper start - Replace whole method
|
||||
+ final ItemMeta itemMeta = this.getItemMeta();
|
||||
+ if (itemMeta != null) {
|
||||
+ itemMeta.addEnchant(ench, level, true);
|
||||
+ this.setItemMeta(itemMeta);
|
||||
}
|
||||
- ItemEnchantments.Mutable listCopy = new ItemEnchantments.Mutable(list);
|
||||
- listCopy.set(CraftEnchantment.bukkitToMinecraftHolder(ench), level);
|
||||
- this.handle.set(DataComponents.ENCHANTMENTS, listCopy.toImmutable());
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
static boolean makeTag(net.minecraft.world.item.ItemStack item) {
|
||||
@@ -252,24 +249,15 @@ public final class CraftItemStack extends ItemStack {
|
||||
public int removeEnchantment(Enchantment ench) {
|
||||
Preconditions.checkArgument(ench != null, "Enchantment cannot be null");
|
||||
|
||||
- ItemEnchantments list = CraftItemStack.getEnchantmentList(this.handle);
|
||||
- if (list == null) {
|
||||
- return 0;
|
||||
- }
|
||||
- int level = this.getEnchantmentLevel(ench);
|
||||
- if (level <= 0) {
|
||||
- return 0;
|
||||
- }
|
||||
- int size = list.size();
|
||||
-
|
||||
- if (size == 1) {
|
||||
- this.handle.remove(DataComponents.ENCHANTMENTS);
|
||||
- return level;
|
||||
+ // Paper start - replace entire method
|
||||
+ int level = getEnchantmentLevel(ench);
|
||||
+ if (level > 0) {
|
||||
+ final ItemMeta itemMeta = this.getItemMeta();
|
||||
+ if (itemMeta == null) return 0;
|
||||
+ itemMeta.removeEnchant(ench);
|
||||
+ this.setItemMeta(itemMeta);
|
||||
}
|
||||
-
|
||||
- ItemEnchantments.Mutable listCopy = new ItemEnchantments.Mutable(list);
|
||||
- listCopy.set(CraftEnchantment.bukkitToMinecraftHolder(ench), -1); // Negative to remove
|
||||
- this.handle.set(DataComponents.ENCHANTMENTS, listCopy.toImmutable());
|
||||
+ // Paper end
|
||||
|
||||
return level;
|
||||
}
|
||||
@@ -281,7 +269,7 @@ public final class CraftItemStack extends ItemStack {
|
||||
|
||||
@Override
|
||||
public Map<Enchantment, Integer> getEnchantments() {
|
||||
- return CraftItemStack.getEnchantments(this.handle);
|
||||
+ return this.hasItemMeta() ? this.getItemMeta().getEnchants() : ImmutableMap.<Enchantment, Integer>of(); // Paper - use Item Meta
|
||||
}
|
||||
|
||||
static Map<Enchantment, Integer> getEnchantments(net.minecraft.world.item.ItemStack item) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
index f6ac13f91f08498a8adda7d34518a5cfe34c15b2..9ab1abd4414a0a40284e12dfebff37e21e7f150f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
@@ -6,6 +6,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
+import com.google.common.collect.ImmutableSortedMap; // Paper
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
@@ -23,6 +24,7 @@ import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
+import java.util.Comparator; // Paper
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
@@ -250,7 +252,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
private List<Component> lore; // null and empty are two different states internally
|
||||
private Integer customModelData;
|
||||
private Map<String, String> blockData;
|
||||
- private Map<Enchantment, Integer> enchantments;
|
||||
+ private EnchantmentMap enchantments; // Paper
|
||||
private Multimap<Attribute, AttributeModifier> attributeModifiers;
|
||||
private int repairCost;
|
||||
private int hideFlag;
|
||||
@@ -292,7 +294,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
this.blockData = meta.blockData;
|
||||
|
||||
if (meta.enchantments != null) {
|
||||
- this.enchantments = new LinkedHashMap<Enchantment, Integer>(meta.enchantments);
|
||||
+ this.enchantments = new EnchantmentMap(meta.enchantments); // Paper
|
||||
}
|
||||
|
||||
if (meta.hasAttributeModifiers()) {
|
||||
@@ -438,8 +440,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
}
|
||||
}
|
||||
|
||||
- static Map<Enchantment, Integer> buildEnchantments(ItemEnchantments tag) {
|
||||
- Map<Enchantment, Integer> enchantments = new LinkedHashMap<Enchantment, Integer>(tag.size());
|
||||
+ static EnchantmentMap buildEnchantments(ItemEnchantments tag) { // Paper
|
||||
+ EnchantmentMap enchantments = new EnchantmentMap(); // Paper
|
||||
|
||||
tag.entrySet().forEach((entry) -> {
|
||||
Holder<net.minecraft.world.item.enchantment.Enchantment> id = entry.getKey();
|
||||
@@ -736,13 +738,13 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
- static Map<Enchantment, Integer> buildEnchantments(Map<String, Object> map, ItemMetaKey key) {
|
||||
+ static EnchantmentMap buildEnchantments(Map<String, Object> map, ItemMetaKey key) { // Paper
|
||||
Map<?, ?> ench = SerializableMeta.getObject(Map.class, map, key.BUKKIT, true);
|
||||
if (ench == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
- Map<Enchantment, Integer> enchantments = new LinkedHashMap<Enchantment, Integer>(ench.size());
|
||||
+ EnchantmentMap enchantments = new EnchantmentMap(); // Paper
|
||||
for (Map.Entry<?, ?> entry : ench.entrySet()) {
|
||||
Enchantment enchantment = CraftEnchantment.stringToBukkit(entry.getKey().toString());
|
||||
if ((enchantment != null) && (entry.getValue() instanceof Integer)) {
|
||||
@@ -1081,14 +1083,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
|
||||
@Override
|
||||
public Map<Enchantment, Integer> getEnchants() {
|
||||
- return this.hasEnchants() ? ImmutableMap.copyOf(this.enchantments) : ImmutableMap.<Enchantment, Integer>of();
|
||||
+ return this.hasEnchants() ? ImmutableSortedMap.copyOfSorted(this.enchantments) : ImmutableMap.<Enchantment, Integer>of(); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addEnchant(Enchantment ench, int level, boolean ignoreRestrictions) {
|
||||
Preconditions.checkArgument(ench != null, "Enchantment cannot be null");
|
||||
if (this.enchantments == null) {
|
||||
- this.enchantments = new LinkedHashMap<Enchantment, Integer>(4);
|
||||
+ this.enchantments = new EnchantmentMap(); // Paper
|
||||
}
|
||||
|
||||
if (ignoreRestrictions || level >= ench.getStartLevel() && level <= ench.getMaxLevel()) {
|
||||
@@ -1688,7 +1690,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
clone.customModelData = this.customModelData;
|
||||
clone.blockData = this.blockData;
|
||||
if (this.enchantments != null) {
|
||||
- clone.enchantments = new LinkedHashMap<Enchantment, Integer>(this.enchantments);
|
||||
+ clone.enchantments = new EnchantmentMap(this.enchantments); // Paper
|
||||
}
|
||||
if (this.hasAttributeModifiers()) {
|
||||
clone.attributeModifiers = LinkedHashMultimap.create(this.attributeModifiers);
|
||||
@@ -2038,4 +2040,22 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
|
||||
return (result != null) ? result : Optional.empty();
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ private static class EnchantmentMap extends java.util.TreeMap<org.bukkit.enchantments.Enchantment, Integer> {
|
||||
+ private EnchantmentMap(Map<Enchantment, Integer> enchantments) {
|
||||
+ this();
|
||||
+ putAll(enchantments);
|
||||
+ }
|
||||
+
|
||||
+ private EnchantmentMap() {
|
||||
+ super(Comparator.comparing(o -> o.getKey().toString()));
|
||||
+ }
|
||||
+
|
||||
+ public EnchantmentMap clone() {
|
||||
+ return (EnchantmentMap) super.clone();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java
|
||||
index e7deba518b8a3df9e642a1bcd7b6642c3dc7583b..26a7c2d37e6a8284ab444a9edad967bdcad1e5a3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java
|
||||
@@ -40,6 +40,17 @@ public final class CraftPlayerProfile implements PlayerProfile {
|
||||
boolean isValidSkullProfile = (gameProfile.getName() != null)
|
||||
|| gameProfile.getProperties().containsKey(CraftPlayerTextures.PROPERTY_NAME);
|
||||
Preconditions.checkArgument(isValidSkullProfile, "The skull profile is missing a name or textures!");
|
||||
+ // Paper start - Validate
|
||||
+ Preconditions.checkArgument(gameProfile.getName().length() <= 16, "The name of the profile is longer than 16 characters");
|
||||
+ Preconditions.checkArgument(net.minecraft.util.StringUtil.isValidPlayerName(gameProfile.getName()), "The name of the profile contains invalid characters: %s", gameProfile.getName());
|
||||
+ final PropertyMap properties = gameProfile.getProperties();
|
||||
+ Preconditions.checkArgument(properties.size() <= 16, "The profile contains more than 16 properties");
|
||||
+ for (final Property property : properties.values()) {
|
||||
+ Preconditions.checkArgument(property.name().length() <= 64, "The name of a property is longer than 64 characters");
|
||||
+ Preconditions.checkArgument(property.value().length() <= Short.MAX_VALUE, "The value of a property is longer than 32767 characters");
|
||||
+ Preconditions.checkArgument(property.signature() == null || property.signature().length() <= 1024, "The signature of a property is longer than 1024 characters");
|
||||
+ }
|
||||
+ // Paper end - Validate
|
||||
return gameProfile;
|
||||
}
|
||||
|
||||
@@ -67,6 +78,8 @@ public final class CraftPlayerProfile implements PlayerProfile {
|
||||
if (applyPreconditions) {
|
||||
Preconditions.checkArgument((uniqueId != null) || !StringUtils.isBlank(name), "uniqueId is null or name is blank");
|
||||
}
|
||||
+ Preconditions.checkArgument(name == null || name.length() <= 16, "The name of the profile is longer than 16 characters"); // Paper - Validate
|
||||
+ Preconditions.checkArgument(name == null || net.minecraft.util.StringUtil.isValidPlayerName(name), "The name of the profile contains invalid characters: %s", name); // Paper - Validate
|
||||
this.uniqueId = uniqueId;
|
||||
this.name = name;
|
||||
}
|
||||
@@ -114,6 +127,7 @@ public final class CraftPlayerProfile implements PlayerProfile {
|
||||
// Assert: (property == null) || property.getName().equals(propertyName)
|
||||
this.removeProperty(propertyName);
|
||||
if (property != null) {
|
||||
+ Preconditions.checkArgument(this.properties.size() < 16, "The profile contains more than 16 properties"); // Paper - Validate
|
||||
this.properties.put(property.name(), property);
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 18 Mar 2016 15:12:22 -0400
|
||||
Subject: [PATCH] Configurable Non Player Arrow Despawn Rate
|
||||
|
||||
Can set a much shorter despawn rate for arrows that players can not pick up.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
|
||||
index 89eebea583550fe703005e5a7020fa4063778a4a..230040bef7d2cf9a463cfd9cb3b1b1aa208a7119 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
|
||||
@@ -356,7 +356,7 @@ public abstract class AbstractArrow extends Projectile {
|
||||
|
||||
protected void tickDespawn() {
|
||||
++this.life;
|
||||
- if (this.life >= ((this instanceof ThrownTrident) ? this.level().spigotConfig.tridentDespawnRate : this.level().spigotConfig.arrowDespawnRate)) { // Spigot
|
||||
+ if (this.life >= (pickup == Pickup.CREATIVE_ONLY ? this.level().paperConfig().entities.spawning.creativeArrowDespawnRate.value() : (pickup == Pickup.DISALLOWED ? this.level().paperConfig().entities.spawning.nonPlayerArrowDespawnRate.value() : ((this instanceof ThrownTrident) ? this.level().spigotConfig.tridentDespawnRate : this.level().spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - Configurable non-player arrow despawn rate; TODO: Extract this to init?
|
||||
this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 18 Mar 2016 20:16:03 -0400
|
||||
Subject: [PATCH] Add World Util Methods
|
||||
|
||||
Methods that can be used for other patches to help improve logic.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 32b42d25631aecdd31db4954a8bbf38bcda98d6b..dfb349ed8a0fb981b3234baf040bd3297a555ebf 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -341,6 +341,22 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
return chunk == null ? null : chunk.getFluidState(blockposition);
|
||||
}
|
||||
|
||||
+ public final boolean isLoadedAndInBounds(BlockPos blockposition) { // Paper - final for inline
|
||||
+ return getWorldBorder().isWithinBounds(blockposition) && getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4) != null;
|
||||
+ }
|
||||
+
|
||||
+ public @Nullable LevelChunk getChunkIfLoaded(int x, int z) { // Overridden in WorldServer for ABI compat which has final
|
||||
+ return ((ServerLevel) this).getChunkSource().getChunkAtIfLoadedImmediately(x, z);
|
||||
+ }
|
||||
+ public final @Nullable LevelChunk getChunkIfLoaded(BlockPos blockposition) {
|
||||
+ return ((ServerLevel) this).getChunkSource().getChunkAtIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4);
|
||||
+ }
|
||||
+
|
||||
+ // reduces need to do isLoaded before getType
|
||||
+ public final @Nullable BlockState getBlockStateIfLoadedAndInBounds(BlockPos blockposition) {
|
||||
+ return getWorldBorder().isWithinBounds(blockposition) ? getBlockStateIfLoaded(blockposition) : null;
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) {
|
||||
// Paper end
|
|
@ -1,48 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jedediah Smith <jedediah@silencegreys.com>
|
||||
Date: Sun, 21 Jun 2015 15:07:20 -0400
|
||||
Subject: [PATCH] Custom replacement for eaten items
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index a5f7289158623c8fb9fd02beecc2ce9f2057a00c..b8a69688bcc69dff11e4bceb06ab435bfc6b3fc9 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3858,10 +3858,11 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
this.triggerItemUseEffects(this.useItem, 16);
|
||||
// CraftBukkit start - fire PlayerItemConsumeEvent
|
||||
ItemStack itemstack;
|
||||
+ PlayerItemConsumeEvent event = null; // Paper
|
||||
if (this instanceof ServerPlayer entityPlayer) {
|
||||
org.bukkit.inventory.ItemStack craftItem = CraftItemStack.asBukkitCopy(this.useItem);
|
||||
org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(enumhand);
|
||||
- PlayerItemConsumeEvent event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem, hand);
|
||||
+ event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem, hand); // Paper
|
||||
this.level().getCraftServer().getPluginManager().callEvent(event);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
@@ -3878,6 +3879,12 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
} else {
|
||||
itemstack = this.useItem.finishUsingItem(this.level(), this);
|
||||
}
|
||||
+ // Paper start - save the default replacement item and change it if necessary
|
||||
+ final ItemStack defaultReplacement = itemstack;
|
||||
+ if (event != null && event.getReplacement() != null) {
|
||||
+ itemstack = CraftItemStack.asNMSCopy(event.getReplacement());
|
||||
+ }
|
||||
+ // Paper end
|
||||
// CraftBukkit end
|
||||
|
||||
if (itemstack != this.useItem) {
|
||||
@@ -3885,6 +3892,11 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
|
||||
this.stopUsingItem();
|
||||
+ // Paper start - if the replacement is anything but the default, update the client inventory
|
||||
+ if (this instanceof ServerPlayer && !com.google.common.base.Objects.equal(defaultReplacement, itemstack)) {
|
||||
+ ((ServerPlayer) this).getBukkitEntity().updateInventory();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 27 Sep 2015 01:18:02 -0400
|
||||
Subject: [PATCH] handle NaN health/absorb values and repair bad data
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index e7b308ba4a253b270aebebd19e2671514c5357ca..fae7c493c9be741f019fc49f45a59976e6b01ed7 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -808,7 +808,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
|
||||
@Override
|
||||
public void readAdditionalSaveData(CompoundTag nbt) {
|
||||
- this.internalSetAbsorptionAmount(nbt.getFloat("AbsorptionAmount"));
|
||||
+ // Paper start - Check for NaN
|
||||
+ float absorptionAmount = nbt.getFloat("AbsorptionAmount");
|
||||
+ if (Float.isNaN(absorptionAmount)) {
|
||||
+ absorptionAmount = 0;
|
||||
+ }
|
||||
+ this.internalSetAbsorptionAmount(absorptionAmount);
|
||||
+ // Paper end - Check for NaN
|
||||
if (nbt.contains("attributes", 9) && this.level() != null && !this.level().isClientSide) {
|
||||
this.getAttributes().load(nbt.getList("attributes", 10));
|
||||
}
|
||||
@@ -1342,6 +1348,10 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
|
||||
public void setHealth(float health) {
|
||||
+ // Paper start - Check for NaN
|
||||
+ if (Float.isNaN(health)) { health = getMaxHealth(); if (this.valid) {
|
||||
+ System.err.println("[NAN-HEALTH] " + getScoreboardName() + " had NaN health set");
|
||||
+ } } // Paper end - Check for NaN
|
||||
// CraftBukkit start - Handle scaled health
|
||||
if (this instanceof ServerPlayer) {
|
||||
org.bukkit.craftbukkit.entity.CraftPlayer player = ((ServerPlayer) this).getBukkitEntity();
|
||||
@@ -3688,7 +3698,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
|
||||
public final void setAbsorptionAmount(float absorptionAmount) {
|
||||
- this.internalSetAbsorptionAmount(Mth.clamp(absorptionAmount, 0.0F, this.getMaxAbsorption()));
|
||||
+ this.internalSetAbsorptionAmount(!Float.isNaN(absorptionAmount) ? Mth.clamp(absorptionAmount, 0.0F, this.getMaxAbsorption()) : 0.0F); // Paper - Check for NaN
|
||||
}
|
||||
|
||||
protected void internalSetAbsorptionAmount(float absorptionAmount) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 174c86a7213ecf3c8dc03aeaf55c56a4c4ce55ad..c399264ccffe646be10b3f13ebe0c0103d97f62c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -2338,6 +2338,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
}
|
||||
|
||||
public void setRealHealth(double health) {
|
||||
+ if (Double.isNaN(health)) {return;} // Paper - Check for NaN
|
||||
this.health = health;
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 22 Mar 2016 00:33:47 -0400
|
||||
Subject: [PATCH] Use a Shared Random for Entities
|
||||
|
||||
Reduces memory usage and provides ensures more randomness, Especially since a lot of garbage entity objects get created.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 82e57978b79b5275b98a1fa7731c6a23ee861a2f..bd17157631a74f80e3b5ce50bb1f681abe1dd6a7 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -175,6 +175,79 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return tag.contains("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level;
|
||||
}
|
||||
|
||||
+ // Paper start - Share random for entities to make them more random
|
||||
+ public static RandomSource SHARED_RANDOM = new RandomRandomSource();
|
||||
+ private static final class RandomRandomSource extends java.util.Random implements net.minecraft.world.level.levelgen.BitRandomSource {
|
||||
+ private boolean locked = false;
|
||||
+
|
||||
+ @Override
|
||||
+ public synchronized void setSeed(long seed) {
|
||||
+ if (locked) {
|
||||
+ LOGGER.error("Ignoring setSeed on Entity.SHARED_RANDOM", new Throwable());
|
||||
+ } else {
|
||||
+ super.setSeed(seed);
|
||||
+ locked = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public RandomSource fork() {
|
||||
+ return new net.minecraft.world.level.levelgen.LegacyRandomSource(this.nextLong());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.minecraft.world.level.levelgen.PositionalRandomFactory forkPositional() {
|
||||
+ return new net.minecraft.world.level.levelgen.LegacyRandomSource.LegacyPositionalRandomFactory(this.nextLong());
|
||||
+ }
|
||||
+
|
||||
+ // these below are added to fix reobf issues that I don't wanna deal with right now
|
||||
+ @Override
|
||||
+ public int next(int bits) {
|
||||
+ return super.next(bits);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int nextInt(int origin, int bound) {
|
||||
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt(origin, bound);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public long nextLong() {
|
||||
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextLong();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int nextInt() {
|
||||
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int nextInt(int bound) {
|
||||
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt(bound);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean nextBoolean() {
|
||||
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextBoolean();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public float nextFloat() {
|
||||
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextFloat();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public double nextDouble() {
|
||||
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextDouble();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public double nextGaussian() {
|
||||
+ return super.nextGaussian();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Share random for entities to make them more random
|
||||
+
|
||||
private CraftEntity bukkitEntity;
|
||||
|
||||
public CraftEntity getBukkitEntity() {
|
||||
@@ -370,7 +443,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
this.bb = Entity.INITIAL_AABB;
|
||||
this.stuckSpeedMultiplier = Vec3.ZERO;
|
||||
this.nextStep = 1.0F;
|
||||
- this.random = RandomSource.create();
|
||||
+ this.random = SHARED_RANDOM; // Paper - Share random for entities to make them more random
|
||||
this.remainingFireTicks = -this.getFireImmuneTicks();
|
||||
this.fluidHeight = new Object2DoubleArrayMap(2);
|
||||
this.fluidOnEyes = new HashSet();
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java
|
||||
index 97d5bc9bab95c21afb3b95d2a7eb7df0b64698ed..42f4e544fe7fbc342f15eacb5e38d40849e3c419 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Squid.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java
|
||||
@@ -41,7 +41,7 @@ public class Squid extends WaterAnimal {
|
||||
|
||||
public Squid(EntityType<? extends Squid> type, Level world) {
|
||||
super(type, world);
|
||||
- this.random.setSeed((long)this.getId());
|
||||
+ //this.random.setSeed((long)this.getId()); // Paper - Share random for entities to make them more random
|
||||
this.tentacleSpeed = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F;
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Tue, 22 Mar 2016 12:04:28 -0500
|
||||
Subject: [PATCH] Configurable spawn chances for skeleton horses
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 6d89dc22e28a9c3557d9972be0935d75719e7f7d..de1708e5d39561115d2825eea4a5f6e1f1f4e5b8 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -621,7 +621,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
if (this.isRainingAt(blockposition)) {
|
||||
DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);
|
||||
- boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * 0.01D && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD);
|
||||
+ boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01D) && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper - Configurable spawn chances for skeleton horses
|
||||
|
||||
if (flag1) {
|
||||
SkeletonHorse entityhorseskeleton = (SkeletonHorse) EntityType.SKELETON_HORSE.create(this);
|
|
@ -1,70 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 28 Mar 2016 19:55:45 -0400
|
||||
Subject: [PATCH] Only process BlockPhysicsEvent if a plugin has a listener
|
||||
|
||||
Saves on some object allocation and processing when no plugin listens to this
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 1ba2b1aaf0936963aca73a43632f978c95bf95e6..639dd562b7eda25004ea10d6c481173afb214773 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1542,6 +1542,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ServerLevel worldserver = (ServerLevel) iterator.next();
|
||||
+ worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
|
||||
|
||||
this.profiler.push(() -> {
|
||||
String s = String.valueOf(worldserver);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index de1708e5d39561115d2825eea4a5f6e1f1f4e5b8..1e5b42fc3903b14537d232c8adbbaf79078d8d8e 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -227,6 +227,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
// CraftBukkit start
|
||||
public final LevelStorageSource.LevelStorageAccess convertable;
|
||||
public final UUID uuid;
|
||||
+ public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent
|
||||
|
||||
public LevelChunk getChunkIfLoaded(int x, int z) {
|
||||
return this.chunkSource.getChunk(x, z, false);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index dfb349ed8a0fb981b3234baf040bd3297a555ebf..024da1029baecae639d7c05b5f7c30dbaa67b006 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -491,7 +491,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
// CraftBukkit start
|
||||
iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam
|
||||
CraftWorld world = ((ServerLevel) this).getWorld();
|
||||
- if (world != null) {
|
||||
+ if (world != null && ((ServerLevel)this).hasPhysicsEvent) { // Paper - BlockPhysicsEvent
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata));
|
||||
this.getCraftServer().getPluginManager().callEvent(event);
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/BushBlock.java b/src/main/java/net/minecraft/world/level/block/BushBlock.java
|
||||
index 75109c79daa724340268438725bbf6d39b955691..a7b4b5600e3c889c69ac22294899713d50b5fe5c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/BushBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/BushBlock.java
|
||||
@@ -28,7 +28,7 @@ public abstract class BushBlock extends Block {
|
||||
protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||
// CraftBukkit start
|
||||
if (!state.canSurvive(world, pos)) {
|
||||
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) {
|
||||
+ if (!(world instanceof net.minecraft.server.level.ServerLevel && ((net.minecraft.server.level.ServerLevel) world).hasPhysicsEvent) || !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) { // Paper
|
||||
return Blocks.AIR.defaultBlockState();
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
|
||||
index cb76568cd1f97024c7a40328d9d72dd8a3e72e8b..7fdf744a2be55313cc75c1322f6534f55cf463f5 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
|
||||
@@ -102,7 +102,7 @@ public class DoublePlantBlock extends BushBlock {
|
||||
|
||||
protected static void preventDropFromBottomPart(Level world, BlockPos pos, BlockState state, Player player) {
|
||||
// CraftBukkit start
|
||||
- if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) {
|
||||
+ if (((net.minecraft.server.level.ServerLevel)world).hasPhysicsEvent && org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) { // Paper
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
|
@ -1,26 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 28 Mar 2016 20:32:58 -0400
|
||||
Subject: [PATCH] Entity AddTo/RemoveFrom World Events
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 1e5b42fc3903b14537d232c8adbbaf79078d8d8e..e6cf145fa7a2968c70e9e467e3927fd38e199e06 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2153,6 +2153,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
entity.setOrigin(entity.getOriginVector().toLocation(getWorld()));
|
||||
}
|
||||
// Paper end - Entity origin API
|
||||
+ new com.destroystokyo.paper.event.entity.EntityAddToWorldEvent(entity.getBukkitEntity(), ServerLevel.this.getWorld()).callEvent(); // Paper - fire while valid
|
||||
}
|
||||
|
||||
public void onTrackingEnd(Entity entity) {
|
||||
@@ -2223,6 +2224,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ new com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent(entity.getBukkitEntity(), ServerLevel.this.getWorld()).callEvent(); // Paper - fire while valid
|
||||
}
|
||||
|
||||
public void onSectionChange(Entity entity) {
|
|
@ -1,30 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 28 Mar 2016 20:46:14 -0400
|
||||
Subject: [PATCH] Configurable Chunk Inhabited Time
|
||||
|
||||
Vanilla stores how long a chunk has been active on a server, and dynamically scales some
|
||||
aspects of vanilla gameplay to this factor.
|
||||
|
||||
For people who want all chunks to be treated equally, you can chose a fixed value.
|
||||
|
||||
This allows to fine-tune vanilla gameplay.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index fb953b2172c322e8abf5aa50060adbc00fe92832..a0f9fb2ac15f2fa51a3bbe915550155ac2e76649 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -172,6 +172,13 @@ public class LevelChunk extends ChunkAccess {
|
||||
return new ChunkAccess.TicksToSave(this.blockTicks, this.fluidTicks);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public long getInhabitedTime() {
|
||||
+ return this.level.paperConfig().chunks.fixedChunkInhabitedTime < 0 ? super.getInhabitedTime() : this.level.paperConfig().chunks.fixedChunkInhabitedTime;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public GameEventListenerRegistry getListenerRegistry(int ySectionCoord) {
|
||||
Level world = this.level;
|
|
@ -1,154 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 28 Mar 2016 21:22:26 -0400
|
||||
Subject: [PATCH] EntityPathfindEvent
|
||||
|
||||
Fires when an Entity decides to start moving to a location.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
|
||||
index d3a279a1a14f99aee8dd516552e5c60de92b4969..a3e0c5af4cc9323c02e88e768cbda9e46854aea1 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
|
||||
@@ -40,7 +40,7 @@ public class FlyingPathNavigation extends PathNavigation {
|
||||
|
||||
@Override
|
||||
public Path createPath(Entity entity, int distance) {
|
||||
- return this.createPath(entity.blockPosition(), distance);
|
||||
+ return this.createPath(entity.blockPosition(), entity, distance); // Paper - EntityPathfindEvent
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
|
||||
index f1a63db8dac13efcfd73b59c7074f6817cc5dbde..62634bedd97c5be9ecce24ab0cff205715a68da8 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
|
||||
@@ -41,7 +41,7 @@ public class GroundPathNavigation extends PathNavigation {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public Path createPath(BlockPos target, int distance) {
|
||||
+ public Path createPath(BlockPos target, @javax.annotation.Nullable Entity entity, int distance) { // Paper - EntityPathfindEvent
|
||||
LevelChunk levelChunk = this.level
|
||||
.getChunkSource()
|
||||
.getChunkNow(SectionPos.blockToSectionCoord(target.getX()), SectionPos.blockToSectionCoord(target.getZ()));
|
||||
@@ -56,7 +56,7 @@ public class GroundPathNavigation extends PathNavigation {
|
||||
}
|
||||
|
||||
if (blockPos.getY() > this.level.getMinBuildHeight()) {
|
||||
- return super.createPath(blockPos.above(), distance);
|
||||
+ return super.createPath(blockPos.above(), entity, distance); // Paper - EntityPathfindEvent
|
||||
}
|
||||
|
||||
while (blockPos.getY() < this.level.getMaxBuildHeight() && levelChunk.getBlockState(blockPos).isAir()) {
|
||||
@@ -67,7 +67,7 @@ public class GroundPathNavigation extends PathNavigation {
|
||||
}
|
||||
|
||||
if (!levelChunk.getBlockState(target).isSolid()) {
|
||||
- return super.createPath(target, distance);
|
||||
+ return super.createPath(target, entity, distance); // Paper - EntityPathfindEvent
|
||||
} else {
|
||||
BlockPos blockPos2 = target.above();
|
||||
|
||||
@@ -75,14 +75,14 @@ public class GroundPathNavigation extends PathNavigation {
|
||||
blockPos2 = blockPos2.above();
|
||||
}
|
||||
|
||||
- return super.createPath(blockPos2, distance);
|
||||
+ return super.createPath(blockPos2, entity, distance); // Paper - EntityPathfindEvent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path createPath(Entity entity, int distance) {
|
||||
- return this.createPath(entity.blockPosition(), distance);
|
||||
+ return this.createPath(entity.blockPosition(), entity, distance); // Paper - EntityPathfindEvent
|
||||
}
|
||||
|
||||
private int getSurfaceY() {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
index 92addc1d3e7d0630c5db76e2a00d61b95b1430cc..21bbc98b26b270b3ad6a3b34d6e50dfb796c3d5a 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
@@ -109,7 +109,13 @@ public abstract class PathNavigation {
|
||||
|
||||
@Nullable
|
||||
public Path createPath(BlockPos target, int distance) {
|
||||
- return this.createPath(ImmutableSet.of(target), 8, false, distance);
|
||||
+ // Paper start - EntityPathfindEvent
|
||||
+ return this.createPath(target, null, distance);
|
||||
+ }
|
||||
+ @Nullable
|
||||
+ public Path createPath(BlockPos target, @Nullable Entity entity, int distance) {
|
||||
+ return this.createPath(ImmutableSet.of(target), entity, 8, false, distance);
|
||||
+ // Paper end - EntityPathfindEvent
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -119,7 +125,7 @@ public abstract class PathNavigation {
|
||||
|
||||
@Nullable
|
||||
public Path createPath(Entity entity, int distance) {
|
||||
- return this.createPath(ImmutableSet.of(entity.blockPosition()), 16, true, distance);
|
||||
+ return this.createPath(ImmutableSet.of(entity.blockPosition()), entity, 16, true, distance); // Paper - EntityPathfindEvent
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -129,6 +135,17 @@ public abstract class PathNavigation {
|
||||
|
||||
@Nullable
|
||||
protected Path createPath(Set<BlockPos> positions, int range, boolean useHeadPos, int distance, float followRange) {
|
||||
+ // Paper start - EntityPathfindEvent
|
||||
+ return this.createPath(positions, null, range, useHeadPos, distance, followRange);
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ protected Path createPath(Set<BlockPos> positions, @Nullable Entity target, int range, boolean useHeadPos, int distance) {
|
||||
+ return this.createPath(positions, target, range, useHeadPos, distance, (float) this.mob.getAttributeValue(Attributes.FOLLOW_RANGE));
|
||||
+ }
|
||||
+
|
||||
+ @Nullable protected Path createPath(Set<BlockPos> positions, @Nullable Entity target, int range, boolean useHeadPos, int distance, float followRange) {
|
||||
+ // Paper end - EntityPathfindEvent
|
||||
if (positions.isEmpty()) {
|
||||
return null;
|
||||
} else if (this.mob.getY() < (double)this.level.getMinBuildHeight()) {
|
||||
@@ -138,6 +155,23 @@ public abstract class PathNavigation {
|
||||
} else if (this.path != null && !this.path.isDone() && positions.contains(this.targetPos)) {
|
||||
return this.path;
|
||||
} else {
|
||||
+ // Paper start - EntityPathfindEvent
|
||||
+ boolean copiedSet = false;
|
||||
+ for (BlockPos possibleTarget : positions) {
|
||||
+ if (!new com.destroystokyo.paper.event.entity.EntityPathfindEvent(this.mob.getBukkitEntity(),
|
||||
+ io.papermc.paper.util.MCUtil.toLocation(this.mob.level(), possibleTarget), target == null ? null : target.getBukkitEntity()).callEvent()) {
|
||||
+ if (!copiedSet) {
|
||||
+ copiedSet = true;
|
||||
+ positions = new java.util.HashSet<>(positions);
|
||||
+ }
|
||||
+ // note: since we copy the set this remove call is safe, since we're iterating over the old copy
|
||||
+ positions.remove(possibleTarget);
|
||||
+ if (positions.isEmpty()) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - EntityPathfindEvent
|
||||
this.level.getProfiler().push("pathfind");
|
||||
BlockPos blockPos = useHeadPos ? this.mob.blockPosition().above() : this.mob.blockPosition();
|
||||
int i = (int)(followRange + (float)range);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java
|
||||
index 1a1bc30b425858d82dbfb84b4a94d7793cab7125..5bbfa43d1e97970f035fcb101c3252c01ffead0d 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java
|
||||
@@ -16,9 +16,9 @@ public class WallClimberNavigation extends GroundPathNavigation {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public Path createPath(BlockPos target, int distance) {
|
||||
+ public Path createPath(BlockPos target, @Nullable Entity entity, int distance) { // Paper - EntityPathfindEvent
|
||||
this.pathToPosition = target;
|
||||
- return super.createPath(target, distance);
|
||||
+ return super.createPath(target, entity, distance); // Paper - EntityPathfindEvent
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,25 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antony Riley <antony@cyberiantiger.org>
|
||||
Date: Tue, 29 Mar 2016 08:22:55 +0300
|
||||
Subject: [PATCH] Sanitise RegionFileCache and make configurable
|
||||
|
||||
RegionFileCache prior to this patch would close every single open region
|
||||
file upon reaching a size of 256.
|
||||
This patch modifies that behaviour so it closes the the least recently
|
||||
used RegionFile.
|
||||
The implementation uses a LinkedHashMap as an LRU cache (modified from HashMap).
|
||||
The maximum size of the RegionFileCache is also made configurable.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index df099d4c7f101f50d40dae99b45c271b02712434..491035aaefff4ee96435ec5d3f9417e28eae0796 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -39,7 +39,7 @@ public final class RegionFileStorage implements AutoCloseable {
|
||||
if (regionfile != null) {
|
||||
return regionfile;
|
||||
} else {
|
||||
- if (this.regionCache.size() >= 256) {
|
||||
+ if (this.regionCache.size() >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize) { // Paper - Sanitise RegionFileCache and make configurable
|
||||
((RegionFile) this.regionCache.removeLast()).close();
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 31 Mar 2016 19:17:58 -0400
|
||||
Subject: [PATCH] Do not load chunks for Pathfinding
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
||||
index 6a8f44600a426041e3974aa52bdec0cc35e26591..d5004290e40a1ff5e0fcfe75f8da34ae15962359 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
||||
@@ -478,7 +478,12 @@ public class WalkNodeEvaluator extends NodeEvaluator {
|
||||
}
|
||||
|
||||
protected static PathType getPathTypeFromState(BlockGetter world, BlockPos pos) {
|
||||
- BlockState blockState = world.getBlockState(pos);
|
||||
+ // Paper start - Do not load chunks during pathfinding
|
||||
+ BlockState blockState = world.getBlockStateIfLoaded(pos);
|
||||
+ if (blockState == null) {
|
||||
+ return PathType.BLOCKED;
|
||||
+ }
|
||||
+ // Paper end
|
||||
Block block = blockState.getBlock();
|
||||
if (blockState.isAir()) {
|
||||
return PathType.OPEN;
|
|
@ -1,78 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jedediah Smith <jedediah@silencegreys.com>
|
||||
Date: Sat, 2 Apr 2016 05:09:16 -0400
|
||||
Subject: [PATCH] Add PlayerUseUnknownEntityEvent
|
||||
|
||||
Adds the PlayerUseUnknownEntityEvent to be used by plugins dealing with
|
||||
virtual entities/entities that are not actually known to the server.
|
||||
|
||||
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java
|
||||
index 1e9c68cd1868d083e6a790d56006dd4aa432010a..8a0ee9564fc36a2badf1357f7e6c47b5f1500f6c 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java
|
||||
@@ -176,4 +176,14 @@ public class ServerboundInteractPacket implements Packet<ServerGamePacketListene
|
||||
buf.writeEnum(this.hand);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Paper start - PlayerUseUnknownEntityEvent
|
||||
+ public int getEntityId() {
|
||||
+ return this.entityId;
|
||||
+ }
|
||||
+
|
||||
+ public boolean isAttack() {
|
||||
+ return this.action.getType() == ActionType.ATTACK;
|
||||
+ }
|
||||
+ // Paper end - PlayerUseUnknownEntityEvent
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 02b9e1ed57f5d65698c461387ff7d48450e6a70f..0d18b12d0755c14bd041e0f98177469612262fde 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2493,7 +2493,26 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
});
|
||||
}
|
||||
}
|
||||
+ // Paper start - PlayerUseUnknownEntityEvent
|
||||
+ else {
|
||||
+ packet.dispatch(new net.minecraft.network.protocol.game.ServerboundInteractPacket.Handler() {
|
||||
+ @Override
|
||||
+ public void onInteraction(net.minecraft.world.InteractionHand hand) {
|
||||
+ CraftEventFactory.callPlayerUseUnknownEntityEvent(ServerGamePacketListenerImpl.this.player, packet, hand, null);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onInteraction(net.minecraft.world.InteractionHand hand, net.minecraft.world.phys.Vec3 pos) {
|
||||
+ CraftEventFactory.callPlayerUseUnknownEntityEvent(ServerGamePacketListenerImpl.this.player, packet, hand, pos);
|
||||
+ }
|
||||
|
||||
+ @Override
|
||||
+ public void onAttack() {
|
||||
+ CraftEventFactory.callPlayerUseUnknownEntityEvent(ServerGamePacketListenerImpl.this.player, packet, net.minecraft.world.InteractionHand.MAIN_HAND, null);
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+ // Paper end - PlayerUseUnknownEntityEvent
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index 8f468a3bfa8ef381eabb45ebb3dd9a4942e98dd5..96e0fc5c8a018fd579f24529175decdac634cfa1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -1931,4 +1931,13 @@ public class CraftEventFactory {
|
||||
|
||||
Bukkit.getPluginManager().callEvent(new EntityRemoveEvent(entity.getBukkitEntity(), cause));
|
||||
}
|
||||
+ // Paper start - PlayerUseUnknownEntityEvent
|
||||
+ public static void callPlayerUseUnknownEntityEvent(net.minecraft.world.entity.player.Player player, net.minecraft.network.protocol.game.ServerboundInteractPacket packet, InteractionHand hand, @Nullable net.minecraft.world.phys.Vec3 vector) {
|
||||
+ new com.destroystokyo.paper.event.player.PlayerUseUnknownEntityEvent(
|
||||
+ (Player) player.getBukkitEntity(), packet.getEntityId(), packet.isAttack(),
|
||||
+ CraftEquipmentSlot.getHand(hand),
|
||||
+ vector != null ? CraftVector.toBukkit(vector) : null
|
||||
+ ).callEvent();
|
||||
+ }
|
||||
+ // Paper end - PlayerUseUnknownEntityEvent
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 3 Apr 2016 16:28:17 -0400
|
||||
Subject: [PATCH] Configurable random tick rates for blocks
|
||||
|
||||
A general purpose patch that includes config options for the tick rate
|
||||
of a variety of blocks that are random ticked.
|
||||
|
||||
Co-authored-by: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
||||
index a88aa3150552cea020589dd9fabf0535cec816bc..529f9f57249bd1ffa2698da76ffa9d4a284088db 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
||||
@@ -93,6 +93,8 @@ public class FarmBlock extends Block {
|
||||
@Override
|
||||
protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
||||
int i = (Integer) state.getValue(FarmBlock.MOISTURE);
|
||||
+ if (i > 0 && world.paperConfig().tickRates.wetFarmland != 1 && (world.paperConfig().tickRates.wetFarmland < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.wetFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks
|
||||
+ if (i == 0 && world.paperConfig().tickRates.dryFarmland != 1 && (world.paperConfig().tickRates.dryFarmland < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.dryFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks
|
||||
|
||||
if (!FarmBlock.isNearWater(world, pos) && !world.isRainingAt(pos.above())) {
|
||||
if (i > 0) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||
index 7a47a3c9a56bcd3c1e817c6a7db8db8465c484e1..5a39e8d359dc13383711e49ffb2d1294dad26192 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||
@@ -43,6 +43,7 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
|
||||
|
||||
@Override
|
||||
protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
||||
+ if (this instanceof GrassBlock && world.paperConfig().tickRates.grassSpread != 1 && (world.paperConfig().tickRates.grassSpread < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks
|
||||
if (!SpreadingSnowyDirtBlock.canBeGrass(state, world, pos)) {
|
||||
// CraftBukkit start
|
||||
if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) {
|
|
@ -1,18 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 3 Apr 2016 17:48:50 -0400
|
||||
Subject: [PATCH] Fix Cancelling BlockPlaceEvent triggering physics
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index e6cf145fa7a2968c70e9e467e3927fd38e199e06..223f8d9be5d73e296f5815db7123b95c3b345162 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1389,6 +1389,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
@Override
|
||||
public void updateNeighborsAt(BlockPos pos, Block sourceBlock) {
|
||||
+ if (captureBlockStates) { return; } // Paper - Cancel all physics during placement
|
||||
this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, (Direction) null);
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 5 Apr 2016 21:38:58 -0400
|
||||
Subject: [PATCH] Optimize DataBits
|
||||
|
||||
Remove Debug checks as these are super hot and causing noticeable hits
|
||||
|
||||
Before: http://i.imgur.com/nQsMzAE.png
|
||||
After: http://i.imgur.com/nJ46crB.png
|
||||
|
||||
Optimize redundant converting of static fields into an unsigned long each call by precomputing it in ctor
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/util/SimpleBitStorage.java b/src/main/java/net/minecraft/util/SimpleBitStorage.java
|
||||
index dea4f322f750a0a09407fdb48d5d6e809dfe8ed4..9f438d9c6eb05e43d24e4af68188a3d4c46a938c 100644
|
||||
--- a/src/main/java/net/minecraft/util/SimpleBitStorage.java
|
||||
+++ b/src/main/java/net/minecraft/util/SimpleBitStorage.java
|
||||
@@ -204,8 +204,8 @@ public class SimpleBitStorage implements BitStorage {
|
||||
private final long mask;
|
||||
private final int size;
|
||||
private final int valuesPerLong;
|
||||
- private final int divideMul;
|
||||
- private final int divideAdd;
|
||||
+ private final int divideMul; private final long divideMulUnsigned; // Paper - Perf: Optimize SimpleBitStorage; referenced in b(int) with 2 Integer.toUnsignedLong calls
|
||||
+ private final int divideAdd; private final long divideAddUnsigned; // Paper - Perf: Optimize SimpleBitStorage
|
||||
private final int divideShift;
|
||||
|
||||
public SimpleBitStorage(int elementBits, int size, int[] data) {
|
||||
@@ -248,8 +248,8 @@ public class SimpleBitStorage implements BitStorage {
|
||||
this.mask = (1L << elementBits) - 1L;
|
||||
this.valuesPerLong = (char)(64 / elementBits);
|
||||
int i = 3 * (this.valuesPerLong - 1);
|
||||
- this.divideMul = MAGIC[i + 0];
|
||||
- this.divideAdd = MAGIC[i + 1];
|
||||
+ this.divideMul = MAGIC[i + 0]; this.divideMulUnsigned = Integer.toUnsignedLong(this.divideMul); // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ this.divideAdd = MAGIC[i + 1]; this.divideAddUnsigned = Integer.toUnsignedLong(this.divideAdd); // Paper - Perf: Optimize SimpleBitStorage
|
||||
this.divideShift = MAGIC[i + 2];
|
||||
int j = (size + this.valuesPerLong - 1) / this.valuesPerLong;
|
||||
if (data != null) {
|
||||
@@ -264,15 +264,15 @@ public class SimpleBitStorage implements BitStorage {
|
||||
}
|
||||
|
||||
private int cellIndex(int index) {
|
||||
- long l = Integer.toUnsignedLong(this.divideMul);
|
||||
- long m = Integer.toUnsignedLong(this.divideAdd);
|
||||
- return (int)((long)index * l + m >> 32 >> this.divideShift);
|
||||
+ //long l = Integer.toUnsignedLong(this.divideMul); // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ //long m = Integer.toUnsignedLong(this.divideAdd); // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ return (int) (index * this.divideMulUnsigned + this.divideAddUnsigned >> 32 >> this.divideShift); // Paper - Perf: Optimize SimpleBitStorage
|
||||
}
|
||||
|
||||
@Override
|
||||
- public int getAndSet(int index, int value) {
|
||||
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
|
||||
- Validate.inclusiveBetween(0L, this.mask, (long)value);
|
||||
+ public final int getAndSet(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ //Validate.inclusiveBetween(0L, this.mask, (long)value); // Paper - Perf: Optimize SimpleBitStorage
|
||||
int i = this.cellIndex(index);
|
||||
long l = this.data[i];
|
||||
int j = (index - i * this.valuesPerLong) * this.bits;
|
||||
@@ -282,9 +282,9 @@ public class SimpleBitStorage implements BitStorage {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void set(int index, int value) {
|
||||
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
|
||||
- Validate.inclusiveBetween(0L, this.mask, (long)value);
|
||||
+ public final void set(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ //Validate.inclusiveBetween(0L, this.mask, (long)value); // Paper - Perf: Optimize SimpleBitStorage
|
||||
int i = this.cellIndex(index);
|
||||
long l = this.data[i];
|
||||
int j = (index - i * this.valuesPerLong) * this.bits;
|
||||
@@ -292,8 +292,8 @@ public class SimpleBitStorage implements BitStorage {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public int get(int index) {
|
||||
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
|
||||
+ public final int get(int index) { // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage
|
||||
int i = this.cellIndex(index);
|
||||
long l = this.data[i];
|
||||
int j = (index - i * this.valuesPerLong) * this.bits;
|
||||
diff --git a/src/main/java/net/minecraft/util/ZeroBitStorage.java b/src/main/java/net/minecraft/util/ZeroBitStorage.java
|
||||
index 8dd5a5899e9b5d8b3f1a6064dd7c1580313da69e..50040c497a819cd1229042ab3cb057d34a32cacc 100644
|
||||
--- a/src/main/java/net/minecraft/util/ZeroBitStorage.java
|
||||
+++ b/src/main/java/net/minecraft/util/ZeroBitStorage.java
|
||||
@@ -13,21 +13,21 @@ public class ZeroBitStorage implements BitStorage {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public int getAndSet(int index, int value) {
|
||||
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
|
||||
- Validate.inclusiveBetween(0L, 0L, (long)value);
|
||||
+ public final int getAndSet(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ //Validate.inclusiveBetween(0L, 0L, (long)value); // Paper - Perf: Optimize SimpleBitStorage
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void set(int index, int value) {
|
||||
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
|
||||
- Validate.inclusiveBetween(0L, 0L, (long)value);
|
||||
+ public final void set(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ //Validate.inclusiveBetween(0L, 0L, (long)value); // Paper - Perf: Optimize SimpleBitStorage
|
||||
}
|
||||
|
||||
@Override
|
||||
- public int get(int index) {
|
||||
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
|
||||
+ public final int get(int index) { // Paper - Perf: Optimize SimpleBitStorage
|
||||
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Wed, 6 Apr 2016 01:04:23 -0500
|
||||
Subject: [PATCH] Option to use vanilla per-world scoreboard coloring on names
|
||||
|
||||
This change is basically a bandaid to fix CB's complete and utter lack
|
||||
of support for vanilla scoreboard name modifications.
|
||||
|
||||
In the future, finding a way to merge the vanilla expectations in with
|
||||
bukkit's concept of a display name would be preferable. There was a PR
|
||||
for this on CB at one point but I can't find it. We may need to do this
|
||||
ourselves at some point in the future.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
|
||||
index b9a64a40dbb025e34a3de81df1208de45df3cfcc..14e412ebf75b0e06ab53a1c8f9dd1be6ad1e2680 100644
|
||||
--- a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
|
||||
+++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
|
||||
@@ -20,6 +20,7 @@ import net.kyori.adventure.audience.ForwardingAudience;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
+import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.Optionull;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
@@ -31,6 +32,7 @@ import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
+import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.util.LazyPlayerSet;
|
||||
import org.bukkit.craftbukkit.util.Waitable;
|
||||
@@ -329,10 +331,16 @@ public final class ChatProcessor {
|
||||
}
|
||||
|
||||
static String legacyDisplayName(final CraftPlayer player) {
|
||||
+ if (((org.bukkit.craftbukkit.CraftWorld) player.getWorld()).getHandle().paperConfig().scoreboards.useVanillaWorldScoreboardNameColoring) {
|
||||
+ return legacySection().serialize(player.teamDisplayName()) + ChatFormatting.RESET;
|
||||
+ }
|
||||
return player.getDisplayName();
|
||||
}
|
||||
|
||||
static Component displayName(final CraftPlayer player) {
|
||||
+ if (((CraftWorld) player.getWorld()).getHandle().paperConfig().scoreboards.useVanillaWorldScoreboardNameColoring) {
|
||||
+ return player.teamDisplayName();
|
||||
+ }
|
||||
return player.displayName();
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 13 Apr 2016 02:10:49 -0400
|
||||
Subject: [PATCH] Configurable Player Collision
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
|
||||
index 9a1a961eabd4362c171da78c6be82c867f3696a4..1d0c473442b5c72245c356054440323e3c5d4711 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
|
||||
@@ -200,7 +200,7 @@ public class ClientboundSetPlayerTeamPacket implements Packet<ClientGamePacketLi
|
||||
ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buf, this.displayName);
|
||||
buf.writeByte(this.options);
|
||||
buf.writeUtf(this.nametagVisibility);
|
||||
- buf.writeUtf(this.collisionRule);
|
||||
+ buf.writeUtf(!io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions ? "never" : this.collisionRule); // Paper - Configurable player collision
|
||||
buf.writeEnum(this.color);
|
||||
ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buf, this.playerPrefix);
|
||||
ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buf, this.playerSuffix);
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 639dd562b7eda25004ea10d6c481173afb214773..30fbbe053ee325f4b9f7722416fb5fb92121e2ad 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -639,6 +639,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(worldserver.getWorld()));
|
||||
}
|
||||
|
||||
+ // Paper start - Configurable player collision; Handle collideRule team for player collision toggle
|
||||
+ final ServerScoreboard scoreboard = this.getScoreboard();
|
||||
+ final java.util.Collection<String> toRemove = scoreboard.getPlayerTeams().stream().filter(team -> team.getName().startsWith("collideRule_")).map(net.minecraft.world.scores.PlayerTeam::getName).collect(java.util.stream.Collectors.toList());
|
||||
+ for (String teamName : toRemove) {
|
||||
+ scoreboard.removePlayerTeam(scoreboard.getPlayerTeam(teamName)); // Clean up after ourselves
|
||||
+ }
|
||||
+
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions) {
|
||||
+ this.getPlayerList().collideRuleTeamName = org.apache.commons.lang3.StringUtils.left("collideRule_" + java.util.concurrent.ThreadLocalRandom.current().nextInt(), 16);
|
||||
+ net.minecraft.world.scores.PlayerTeam collideTeam = scoreboard.addPlayerTeam(this.getPlayerList().collideRuleTeamName);
|
||||
+ collideTeam.setSeeFriendlyInvisibles(false); // Because we want to mimic them not being on a team at all
|
||||
+ }
|
||||
+ // Paper end - Configurable player collision
|
||||
+
|
||||
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
|
||||
if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins
|
||||
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 8a91a44e46a2d49e2f4b9e9970c2b77f2e87767e..98862db2334508ee1a783aeabfb146751552a4d9 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -159,6 +159,7 @@ public abstract class PlayerList {
|
||||
// CraftBukkit start
|
||||
private CraftServer cserver;
|
||||
private final Map<String,ServerPlayer> playersByName = new java.util.HashMap<>();
|
||||
+ public @Nullable String collideRuleTeamName; // Paper - Configurable player collision
|
||||
|
||||
public PlayerList(MinecraftServer server, LayeredRegistryAccess<RegistryLayer> registryManager, PlayerDataStorage saveHandler, int maxPlayers) {
|
||||
this.cserver = server.server = new CraftServer((DedicatedServer) server, this);
|
||||
@@ -390,6 +391,13 @@ public abstract class PlayerList {
|
||||
|
||||
player.initInventoryMenu();
|
||||
// CraftBukkit - Moved from above, added world
|
||||
+ // Paper start - Configurable player collision; Add to collideRule team if needed
|
||||
+ final net.minecraft.world.scores.Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard();
|
||||
+ final PlayerTeam collideRuleTeam = scoreboard.getPlayerTeam(this.collideRuleTeamName);
|
||||
+ if (this.collideRuleTeamName != null && collideRuleTeam != null && player.getTeam() == null) {
|
||||
+ scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
|
||||
+ }
|
||||
+ // Paper end - Configurable player collision
|
||||
PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ());
|
||||
}
|
||||
|
||||
@@ -512,6 +520,16 @@ public abstract class PlayerList {
|
||||
entityplayer.doTick(); // SPIGOT-924
|
||||
// CraftBukkit end
|
||||
|
||||
+ // Paper start - Configurable player collision; Remove from collideRule team if needed
|
||||
+ if (this.collideRuleTeamName != null) {
|
||||
+ final net.minecraft.world.scores.Scoreboard scoreBoard = this.server.getLevel(Level.OVERWORLD).getScoreboard();
|
||||
+ final PlayerTeam team = scoreBoard.getPlayersTeam(this.collideRuleTeamName);
|
||||
+ if (entityplayer.getTeam() == team && team != null) {
|
||||
+ scoreBoard.removePlayerFromTeam(entityplayer.getScoreboardName(), team);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Configurable player collision
|
||||
+
|
||||
this.save(entityplayer);
|
||||
if (entityplayer.isPassenger()) {
|
||||
Entity entity = entityplayer.getRootVehicle();
|
||||
@@ -1129,6 +1147,13 @@ public abstract class PlayerList {
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
+ // Paper start - Configurable player collision; Remove collideRule team if it exists
|
||||
+ if (this.collideRuleTeamName != null) {
|
||||
+ final net.minecraft.world.scores.Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard();
|
||||
+ final PlayerTeam team = scoreboard.getPlayersTeam(this.collideRuleTeamName);
|
||||
+ if (team != null) scoreboard.removePlayerTeam(team);
|
||||
+ }
|
||||
+ // Paper end - Configurable player collision
|
||||
}
|
||||
|
||||
// CraftBukkit start
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
index 3207166061bf9c4d7bf3f38e5a9f7aff23ccd5c1..f7014bf5faae03a04c31cbdaeb27188c47156c2d 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
@@ -51,7 +51,7 @@ public final class EntitySelector {
|
||||
return (Predicate) (scoreboardteambase_enumteampush == Team.CollisionRule.NEVER ? Predicates.alwaysFalse() : EntitySelector.NO_SPECTATORS.and((entity1) -> {
|
||||
if (!entity1.canCollideWithBukkit(entity) || !entity.canCollideWithBukkit(entity1)) { // CraftBukkit - collidable API
|
||||
return false;
|
||||
- } else if (entity.level().isClientSide && (!(entity1 instanceof Player) || !((Player) entity1).isLocalPlayer())) {
|
||||
+ } else if (entity1 instanceof Player && entity instanceof Player && !io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions) { // Paper - Configurable player collision
|
||||
return false;
|
||||
} else {
|
||||
PlayerTeam scoreboardteam1 = entity1.getTeam();
|
|
@ -1,56 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kashike <kashike@vq.lc>
|
||||
Date: Wed, 13 Apr 2016 20:21:38 -0700
|
||||
Subject: [PATCH] Add handshake event to allow plugins to handle client
|
||||
handshaking logic themselves
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||
index 64e3d3626a30d4dfe15ed1f7cb3f0480ece5edce..7ae4279768b70a4fdc8f4438898871a17c8fe402 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||
@@ -121,9 +121,43 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL
|
||||
this.connection.disconnect((Component) ichatmutablecomponent);
|
||||
} else {
|
||||
this.connection.setupInboundProtocol(LoginProtocols.SERVERBOUND, new ServerLoginPacketListenerImpl(this.server, this.connection, transfer));
|
||||
+ // Paper start - PlayerHandshakeEvent
|
||||
+ boolean proxyLogicEnabled = org.spigotmc.SpigotConfig.bungee;
|
||||
+ boolean handledByEvent = false;
|
||||
+ // Try and handle the handshake through the event
|
||||
+ if (com.destroystokyo.paper.event.player.PlayerHandshakeEvent.getHandlerList().getRegisteredListeners().length != 0) { // Hello? Can you hear me?
|
||||
+ java.net.SocketAddress socketAddress = this.connection.address;
|
||||
+ String hostnameOfRemote = socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getHostString() : InetAddress.getLoopbackAddress().getHostAddress();
|
||||
+ com.destroystokyo.paper.event.player.PlayerHandshakeEvent event = new com.destroystokyo.paper.event.player.PlayerHandshakeEvent(packet.hostName(), hostnameOfRemote, !proxyLogicEnabled);
|
||||
+ if (event.callEvent()) {
|
||||
+ // If we've failed somehow, let the client know so and go no further.
|
||||
+ if (event.isFailed()) {
|
||||
+ Component component = io.papermc.paper.adventure.PaperAdventure.asVanilla(event.failMessage());
|
||||
+ this.connection.send(new ClientboundLoginDisconnectPacket(component));
|
||||
+ this.connection.disconnect(component);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (event.getServerHostname() != null) {
|
||||
+ // change hostname
|
||||
+ packet = new ClientIntentionPacket(
|
||||
+ packet.protocolVersion(),
|
||||
+ event.getServerHostname(),
|
||||
+ packet.port(),
|
||||
+ packet.intention()
|
||||
+ );
|
||||
+ }
|
||||
+ if (event.getSocketAddressHostname() != null) this.connection.address = new java.net.InetSocketAddress(event.getSocketAddressHostname(), socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getPort() : 0);
|
||||
+ this.connection.spoofedUUID = event.getUniqueId();
|
||||
+ this.connection.spoofedProfile = gson.fromJson(event.getPropertiesJson(), com.mojang.authlib.properties.Property[].class);
|
||||
+ handledByEvent = true; // Hooray, we did it!
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
// Spigot Start
|
||||
String[] split = packet.hostName().split("\00");
|
||||
- if (org.spigotmc.SpigotConfig.bungee) {
|
||||
+ if (!handledByEvent && proxyLogicEnabled) { // Paper
|
||||
+ // if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above!
|
||||
if ( ( split.length == 3 || split.length == 4 ) && ( ServerHandshakePacketListenerImpl.HOST_PATTERN.matcher( split[1] ).matches() ) ) {
|
||||
this.connection.hostname = split[0];
|
||||
this.connection.address = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getPort());
|
|
@ -1,47 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 16 Apr 2016 00:39:33 -0400
|
||||
Subject: [PATCH] Configurable RCON IP address
|
||||
|
||||
For servers with multiple IP's, ability to bind to a specific interface.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.server.dedicated.Settings getStringRaw(Ljava/lang/String;)Ljava/lang/String;
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
index 36a0a8b5f85edad4dcfcdc75c4db2aa69261eae6..eb27ef574445e1311b763d84aa1b37128baa75f7 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
@@ -110,6 +110,8 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
||||
public final WorldOptions worldOptions;
|
||||
public boolean acceptsTransfers;
|
||||
|
||||
+ public final String rconIp; // Paper - Configurable rcon ip
|
||||
+
|
||||
// CraftBukkit start
|
||||
public DedicatedServerProperties(Properties properties, OptionSet optionset) {
|
||||
super(properties, optionset);
|
||||
@@ -170,6 +172,10 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
||||
}, WorldPresets.NORMAL.location().toString()));
|
||||
this.serverResourcePackInfo = DedicatedServerProperties.getServerPackInfo(this.get("resource-pack-id", ""), this.get("resource-pack", ""), this.get("resource-pack-sha1", ""), this.getLegacyString("resource-pack-hash"), this.get("require-resource-pack", false), this.get("resource-pack-prompt", ""));
|
||||
this.initialDataPackConfiguration = DedicatedServerProperties.getDatapackConfig(this.get("initial-enabled-packs", String.join(",", WorldDataConfiguration.DEFAULT.dataPacks().getEnabled())), this.get("initial-disabled-packs", String.join(",", WorldDataConfiguration.DEFAULT.dataPacks().getDisabled())));
|
||||
+ // Paper start - Configurable rcon ip
|
||||
+ final String rconIp = this.getStringRaw("rcon.ip");
|
||||
+ this.rconIp = rconIp == null ? this.serverIp : rconIp;
|
||||
+ // Paper end - Configurable rcon ip
|
||||
}
|
||||
|
||||
// CraftBukkit start
|
||||
diff --git a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
|
||||
index cf6ff562614e07dfdc0ae1d2d68df67d61136df0..594fbb033b63b8c9fb8752b1fcc78f8e9f7a2a83 100644
|
||||
--- a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
|
||||
+++ b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
|
||||
@@ -57,7 +57,7 @@ public class RconThread extends GenericThread {
|
||||
@Nullable
|
||||
public static RconThread create(ServerInterface server) {
|
||||
DedicatedServerProperties dedicatedServerProperties = server.getProperties();
|
||||
- String string = server.getServerIp();
|
||||
+ String string = dedicatedServerProperties.rconIp; // Paper - Configurable rcon ip
|
||||
if (string.isEmpty()) {
|
||||
string = "0.0.0.0";
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Fri, 22 Apr 2016 01:43:11 -0500
|
||||
Subject: [PATCH] EntityRegainHealthEvent isFastRegen API
|
||||
|
||||
Don't even get me started
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index fae7c493c9be741f019fc49f45a59976e6b01ed7..16d611e09cbe56525cde0e0dced93b7f09c12158 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1321,10 +1321,16 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
|
||||
public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason) {
|
||||
+ // Paper start - Forward
|
||||
+ heal(f, regainReason, false);
|
||||
+ }
|
||||
+
|
||||
+ public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason, boolean isFastRegen) {
|
||||
+ // Paper end
|
||||
float f1 = this.getHealth();
|
||||
|
||||
if (f1 > 0.0F) {
|
||||
- EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason);
|
||||
+ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason, isFastRegen); // Paper
|
||||
// Suppress during worldgen
|
||||
if (this.valid) {
|
||||
this.level().getCraftServer().getPluginManager().callEvent(event);
|
||||
diff --git a/src/main/java/net/minecraft/world/food/FoodData.java b/src/main/java/net/minecraft/world/food/FoodData.java
|
||||
index 8fad44228049eee477da81708bdf16658cb9ed7a..bd3f78e6453cfe18aa3da38176b04d734d83bb4b 100644
|
||||
--- a/src/main/java/net/minecraft/world/food/FoodData.java
|
||||
+++ b/src/main/java/net/minecraft/world/food/FoodData.java
|
||||
@@ -88,7 +88,7 @@ public class FoodData {
|
||||
if (this.tickTimer >= this.saturatedRegenRate) { // CraftBukkit
|
||||
float f = Math.min(this.saturationLevel, 6.0F);
|
||||
|
||||
- player.heal(f / 6.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED); // CraftBukkit - added RegainReason
|
||||
+ player.heal(f / 6.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED, true); // CraftBukkit - added RegainReason // Paper - This is fast regen
|
||||
// this.addExhaustion(f); CraftBukkit - EntityExhaustionEvent
|
||||
player.causeFoodExhaustion(f, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.REGEN); // CraftBukkit - EntityExhaustionEvent
|
||||
this.tickTimer = 0;
|
|
@ -1,32 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kashike <kashike@vq.lc>
|
||||
Date: Thu, 21 Apr 2016 23:51:55 -0700
|
||||
Subject: [PATCH] Add ability to configure frosted_ice properties
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java b/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
|
||||
index cdf3cc2a08c52d0e5e5efd5c798f6dc156c0df55..ae6a952e49d20b7c6ad753169608794abe720ee0 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
|
||||
@@ -40,6 +40,7 @@ public class FrostedIceBlock extends IceBlock {
|
||||
|
||||
@Override
|
||||
protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
||||
+ if (!world.paperConfig().environment.frostedIce.enabled) return; // Paper - Frosted ice options
|
||||
if ((random.nextInt(3) == 0 || this.fewerNeigboursThan(world, pos, 4))
|
||||
&& world.getMaxLocalRawBrightness(pos) > 11 - state.getValue(AGE) - state.getLightBlock(world, pos)
|
||||
&& this.slightlyMelt(state, world, pos)) {
|
||||
@@ -49,11 +50,11 @@ public class FrostedIceBlock extends IceBlock {
|
||||
mutableBlockPos.setWithOffset(pos, direction);
|
||||
BlockState blockState = world.getBlockState(mutableBlockPos);
|
||||
if (blockState.is(this) && !this.slightlyMelt(blockState, world, mutableBlockPos)) {
|
||||
- world.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, 20, 40));
|
||||
+ world.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, world.paperConfig().environment.frostedIce.delay.min, world.paperConfig().environment.frostedIce.delay.max)); // Paper - Frosted ice options
|
||||
}
|
||||
}
|
||||
} else {
|
||||
- world.scheduleTick(pos, this, Mth.nextInt(random, 20, 40));
|
||||
+ world.scheduleTick(pos, this, Mth.nextInt(random, world.paperConfig().environment.frostedIce.delay.min, world.paperConfig().environment.frostedIce.delay.max)); // Paper - Frosted ice options
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 28 Apr 2016 00:57:27 -0400
|
||||
Subject: [PATCH] remove null possibility for getServer singleton
|
||||
|
||||
to stop IDE complaining about potential NPE
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 30fbbe053ee325f4b9f7722416fb5fb92121e2ad..f16ade2019e58a9374a550f58113313c118c2f2b 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -197,6 +197,7 @@ import co.aikar.timings.MinecraftTimings; // Paper
|
||||
|
||||
public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements ServerInfo, ChunkIOErrorReporter, CommandSource, AutoCloseable {
|
||||
|
||||
+ private static MinecraftServer SERVER; // Paper
|
||||
public static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final net.kyori.adventure.text.logger.slf4j.ComponentLogger COMPONENT_LOGGER = net.kyori.adventure.text.logger.slf4j.ComponentLogger.logger(LOGGER.getName()); // Paper
|
||||
public static final String VANILLA_BRAND = "vanilla";
|
||||
@@ -330,6 +331,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
public MinecraftServer(OptionSet options, WorldLoader.DataLoadContext worldLoader, Thread thread, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PackRepository resourcepackrepository, WorldStem worldstem, Proxy proxy, DataFixer datafixer, Services services, ChunkProgressListenerFactory worldloadlistenerfactory) {
|
||||
super("Server");
|
||||
+ SERVER = this; // Paper - better singleton
|
||||
this.metricsRecorder = InactiveMetricsRecorder.INSTANCE;
|
||||
this.profiler = this.metricsRecorder.getProfiler();
|
||||
this.onMetricsRecordingStopped = (methodprofilerresults) -> {
|
||||
@@ -2546,9 +2548,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
return false;
|
||||
}
|
||||
|
||||
- @Deprecated
|
||||
public static MinecraftServer getServer() {
|
||||
- return (Bukkit.getServer() instanceof CraftServer) ? ((CraftServer) Bukkit.getServer()).getServer() : null;
|
||||
+ return SERVER; // Paper
|
||||
}
|
||||
|
||||
@Deprecated
|
|
@ -1,18 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 7 May 2016 23:33:08 -0400
|
||||
Subject: [PATCH] Don't save empty scoreboard teams to scoreboard.dat
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java b/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java
|
||||
index 4a01558a1c3d9cfcd043ad3998514311fe8f63d9..b679bbdfa307d3aa9f2f5e4c70c559695b2733de 100644
|
||||
--- a/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java
|
||||
+++ b/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java
|
||||
@@ -148,6 +148,7 @@ public class ScoreboardSaveData extends SavedData {
|
||||
ListTag listTag = new ListTag();
|
||||
|
||||
for (PlayerTeam playerTeam : this.scoreboard.getPlayerTeams()) {
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().scoreboards.saveEmptyScoreboardTeams && playerTeam.getPlayers().isEmpty()) continue; // Paper - Don't save empty scoreboard teams to scoreboard.dat
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
compoundTag.putString("Name", playerTeam.getName());
|
||||
compoundTag.putString("DisplayName", Component.Serializer.toJson(playerTeam.getDisplayName(), registries));
|
|
@ -1,963 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 1 May 2016 21:19:14 -0400
|
||||
Subject: [PATCH] LootTable API and replenishable lootables
|
||||
|
||||
Provides an API to control the loot table for an object.
|
||||
Also provides a feature that any Lootable Inventory (Chests in Structures)
|
||||
can automatically replenish after a given time.
|
||||
|
||||
This feature is good for long term worlds so that newer players
|
||||
do not suffer with "Every chest has been looted"
|
||||
|
||||
== AT ==
|
||||
public org.bukkit.craftbukkit.block.CraftBlockEntityState getTileEntity()Lnet/minecraft/world/level/block/entity/BlockEntity;
|
||||
public org.bukkit.craftbukkit.block.CraftLootable setLootTable(Lorg/bukkit/loot/LootTable;J)V
|
||||
public org.bukkit.craftbukkit.entity.CraftMinecartContainer setLootTable(Lorg/bukkit/loot/LootTable;J)V
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootable.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootable.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..a53d51be1da25b87f2bc0a29a196d8f9996dbd2b
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootable.java
|
||||
@@ -0,0 +1,21 @@
|
||||
+package com.destroystokyo.paper.loottable;
|
||||
+
|
||||
+import org.bukkit.loot.LootTable;
|
||||
+import org.bukkit.loot.Lootable;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public interface PaperLootable extends Lootable {
|
||||
+
|
||||
+ @Override
|
||||
+ default void setLootTable(final @Nullable LootTable table) {
|
||||
+ this.setLootTable(table, this.getSeed());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default void setSeed(final long seed) {
|
||||
+ this.setLootTable(this.getLootTable(), seed);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlock.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlock.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..9e9ea13234703d3e4a39eed2b007e8be69dfbd12
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlock.java
|
||||
@@ -0,0 +1,27 @@
|
||||
+package com.destroystokyo.paper.loottable;
|
||||
+
|
||||
+import net.minecraft.world.RandomizableContainer;
|
||||
+import org.bukkit.craftbukkit.CraftLootTable;
|
||||
+import org.bukkit.loot.LootTable;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+
|
||||
+public interface PaperLootableBlock extends PaperLootable {
|
||||
+
|
||||
+ RandomizableContainer getRandomizableContainer();
|
||||
+
|
||||
+ /* Lootable */
|
||||
+ @Override
|
||||
+ default @Nullable LootTable getLootTable() {
|
||||
+ return CraftLootTable.minecraftToBukkit(this.getRandomizableContainer().getLootTable());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default void setLootTable(final @Nullable LootTable table, final long seed) {
|
||||
+ this.getRandomizableContainer().setLootTable(CraftLootTable.bukkitToMinecraft(table), seed);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default long getSeed() {
|
||||
+ return this.getRandomizableContainer().getLootTableSeed();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0699c60920333ea1fec04e3c94d952244d2abeae
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java
|
||||
@@ -0,0 +1,26 @@
|
||||
+package com.destroystokyo.paper.loottable;
|
||||
+
|
||||
+import java.util.Objects;
|
||||
+import net.minecraft.core.BlockPos;
|
||||
+import org.bukkit.block.Block;
|
||||
+import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public interface PaperLootableBlockInventory extends LootableBlockInventory, PaperLootableInventory, PaperLootableBlock {
|
||||
+
|
||||
+ /* PaperLootableInventory */
|
||||
+ @Override
|
||||
+ default PaperLootableInventoryData lootableDataForAPI() {
|
||||
+ return Objects.requireNonNull(this.getRandomizableContainer().lootableData(), "Can only manage loot tables on tile entities with lootableData");
|
||||
+ }
|
||||
+
|
||||
+ /* LootableBlockInventory */
|
||||
+ @Override
|
||||
+ default Block getBlock() {
|
||||
+ final BlockPos position = this.getRandomizableContainer().getBlockPos();
|
||||
+ return CraftBlock.at(this.getNMSWorld(), position);
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntity.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntity.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..de528b8bafd75b6f14b1384157f3a8a27e06b4a2
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntity.java
|
||||
@@ -0,0 +1,29 @@
|
||||
+package com.destroystokyo.paper.loottable;
|
||||
+
|
||||
+import net.minecraft.world.entity.vehicle.ContainerEntity;
|
||||
+import org.bukkit.craftbukkit.CraftLootTable;
|
||||
+import org.bukkit.loot.LootTable;
|
||||
+import org.bukkit.loot.Lootable;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+
|
||||
+public interface PaperLootableEntity extends Lootable {
|
||||
+
|
||||
+ ContainerEntity getHandle();
|
||||
+
|
||||
+ /* Lootable */
|
||||
+ @Override
|
||||
+ default @Nullable LootTable getLootTable() {
|
||||
+ return CraftLootTable.minecraftToBukkit(this.getHandle().getLootTable());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default void setLootTable(final @Nullable LootTable table, final long seed) {
|
||||
+ this.getHandle().setLootTable(CraftLootTable.bukkitToMinecraft(table));
|
||||
+ this.getHandle().setLootTableSeed(seed);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default long getSeed() {
|
||||
+ return this.getHandle().getLootTableSeed();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..5c57acc95f638a8bcb351ae44e9434a056835470
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java
|
||||
@@ -0,0 +1,26 @@
|
||||
+package com.destroystokyo.paper.loottable;
|
||||
+
|
||||
+import net.minecraft.world.level.Level;
|
||||
+import org.bukkit.entity.Entity;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public interface PaperLootableEntityInventory extends LootableEntityInventory, PaperLootableInventory, PaperLootableEntity {
|
||||
+
|
||||
+ /* PaperLootableInventory */
|
||||
+ @Override
|
||||
+ default Level getNMSWorld() {
|
||||
+ return this.getHandle().level();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default PaperLootableInventoryData lootableDataForAPI() {
|
||||
+ return this.getHandle().lootableData();
|
||||
+ }
|
||||
+
|
||||
+ /* LootableEntityInventory */
|
||||
+ default Entity getEntity() {
|
||||
+ return ((net.minecraft.world.entity.Entity) this.getHandle()).getBukkitEntity();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..9e7c22ef49f1699df298f7121d50d27b4cb0923f
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java
|
||||
@@ -0,0 +1,79 @@
|
||||
+package com.destroystokyo.paper.loottable;
|
||||
+
|
||||
+import java.util.UUID;
|
||||
+import net.minecraft.world.level.Level;
|
||||
+import org.bukkit.World;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public interface PaperLootableInventory extends PaperLootable, LootableInventory {
|
||||
+
|
||||
+ /* impl */
|
||||
+ PaperLootableInventoryData lootableDataForAPI();
|
||||
+
|
||||
+ Level getNMSWorld();
|
||||
+
|
||||
+ default World getBukkitWorld() {
|
||||
+ return this.getNMSWorld().getWorld();
|
||||
+ }
|
||||
+
|
||||
+ /* LootableInventory */
|
||||
+ @Override
|
||||
+ default boolean isRefillEnabled() {
|
||||
+ return this.getNMSWorld().paperConfig().lootables.autoReplenish;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default boolean hasBeenFilled() {
|
||||
+ return this.getLastFilled() != -1;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default boolean hasPlayerLooted(final UUID player) {
|
||||
+ return this.lootableDataForAPI().hasPlayerLooted(player);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default boolean canPlayerLoot(final UUID player) {
|
||||
+ return this.lootableDataForAPI().canPlayerLoot(player, this.getNMSWorld().paperConfig());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default Long getLastLooted(final UUID player) {
|
||||
+ return this.lootableDataForAPI().getLastLooted(player);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default boolean setHasPlayerLooted(final UUID player, final boolean looted) {
|
||||
+ final boolean hasLooted = this.hasPlayerLooted(player);
|
||||
+ if (hasLooted != looted) {
|
||||
+ this.lootableDataForAPI().setPlayerLootedState(player, looted);
|
||||
+ }
|
||||
+ return hasLooted;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default boolean hasPendingRefill() {
|
||||
+ final long nextRefill = this.lootableDataForAPI().getNextRefill();
|
||||
+ return nextRefill != -1 && nextRefill > this.lootableDataForAPI().getLastFill();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default long getLastFilled() {
|
||||
+ return this.lootableDataForAPI().getLastFill();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default long getNextRefill() {
|
||||
+ return this.lootableDataForAPI().getNextRefill();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ default long setNextRefill(long refillAt) {
|
||||
+ if (refillAt < -1) {
|
||||
+ refillAt = -1;
|
||||
+ }
|
||||
+ return this.lootableDataForAPI().setNextRefill(refillAt);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..cd61276a45894a02cbefc41a63c27e2cf6361d1e
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
|
||||
@@ -0,0 +1,249 @@
|
||||
+package com.destroystokyo.paper.loottable;
|
||||
+
|
||||
+import io.papermc.paper.configuration.WorldConfiguration;
|
||||
+import io.papermc.paper.configuration.type.DurationOrDisabled;
|
||||
+import java.util.HashMap;
|
||||
+import java.util.Map;
|
||||
+import java.util.Objects;
|
||||
+import java.util.Random;
|
||||
+import java.util.UUID;
|
||||
+import java.util.concurrent.TimeUnit;
|
||||
+import net.minecraft.nbt.CompoundTag;
|
||||
+import net.minecraft.nbt.ListTag;
|
||||
+import net.minecraft.nbt.Tag;
|
||||
+import net.minecraft.world.RandomizableContainer;
|
||||
+import net.minecraft.world.entity.vehicle.ContainerEntity;
|
||||
+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;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public class PaperLootableInventoryData {
|
||||
+
|
||||
+ private static final Random RANDOM = new Random();
|
||||
+
|
||||
+ private long lastFill = -1;
|
||||
+ private long nextRefill = -1;
|
||||
+ private int numRefills = 0;
|
||||
+ private @Nullable Map<UUID, Long> lootedPlayers;
|
||||
+
|
||||
+ public long getLastFill() {
|
||||
+ return this.lastFill;
|
||||
+ }
|
||||
+
|
||||
+ long getNextRefill() {
|
||||
+ return this.nextRefill;
|
||||
+ }
|
||||
+
|
||||
+ long setNextRefill(final long nextRefill) {
|
||||
+ final long prev = this.nextRefill;
|
||||
+ this.nextRefill = nextRefill;
|
||||
+ return prev;
|
||||
+ }
|
||||
+
|
||||
+ public <T> boolean shouldReplenish(final T lootTableHolder, final LootTableInterface<T> holderInterface, final net.minecraft.world.entity.player.@Nullable Player player) {
|
||||
+
|
||||
+ // No Loot Table associated
|
||||
+ if (!holderInterface.hasLootTable(lootTableHolder)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ // ALWAYS process the first fill or if the feature is disabled
|
||||
+ if (this.lastFill == -1 || !holderInterface.paperConfig(lootTableHolder).lootables.autoReplenish) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ // Only process refills when a player is set
|
||||
+ if (player == null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ // Chest is not scheduled for refill
|
||||
+ if (this.nextRefill == -1) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ final WorldConfiguration paperConfig = holderInterface.paperConfig(lootTableHolder);
|
||||
+
|
||||
+ // Check if max refills has been hit
|
||||
+ if (paperConfig.lootables.maxRefills != -1 && this.numRefills >= paperConfig.lootables.maxRefills) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ // Refill has not been reached
|
||||
+ if (this.nextRefill > System.currentTimeMillis()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ final Player bukkitPlayer = (Player) player.getBukkitEntity();
|
||||
+ final LootableInventoryReplenishEvent event = new LootableInventoryReplenishEvent(bukkitPlayer, holderInterface.getInventoryForEvent(lootTableHolder));
|
||||
+ event.setCancelled(!this.canPlayerLoot(player.getUUID(), paperConfig));
|
||||
+ return event.callEvent();
|
||||
+ }
|
||||
+
|
||||
+ public interface LootTableInterface<T> {
|
||||
+
|
||||
+ WorldConfiguration paperConfig(T holder);
|
||||
+
|
||||
+ void setSeed(T holder, long seed);
|
||||
+
|
||||
+ boolean hasLootTable(T holder);
|
||||
+
|
||||
+ LootableInventory getInventoryForEvent(T holder);
|
||||
+ }
|
||||
+
|
||||
+ public static final LootTableInterface<RandomizableContainer> CONTAINER = new LootTableInterface<>() {
|
||||
+ @Override
|
||||
+ public WorldConfiguration paperConfig(final RandomizableContainer holder) {
|
||||
+ return Objects.requireNonNull(holder.getLevel(), "Can only manager loot replenishment on block entities in a world").paperConfig();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSeed(final RandomizableContainer holder, final long seed) {
|
||||
+ holder.setLootTableSeed(seed);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasLootTable(final RandomizableContainer holder) {
|
||||
+ return holder.getLootTable() != null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public LootableInventory getInventoryForEvent(final RandomizableContainer holder) {
|
||||
+ return holder.getLootableInventory();
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ public static final LootTableInterface<ContainerEntity> ENTITY = new LootTableInterface<>() {
|
||||
+ @Override
|
||||
+ public WorldConfiguration paperConfig(final ContainerEntity holder) {
|
||||
+ return holder.level().paperConfig();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSeed(final ContainerEntity holder, final long seed) {
|
||||
+ holder.setLootTableSeed(seed);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasLootTable(final ContainerEntity holder) {
|
||||
+ return holder.getLootTable() != null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public LootableInventory getInventoryForEvent(final ContainerEntity holder) {
|
||||
+ return holder.getLootableInventory();
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ public <T> boolean shouldClearLootTable(final T lootTableHolder, final LootTableInterface<T> holderInterface, final net.minecraft.world.entity.player.@Nullable Player player) {
|
||||
+ this.lastFill = System.currentTimeMillis();
|
||||
+ final WorldConfiguration paperConfig = holderInterface.paperConfig(lootTableHolder);
|
||||
+ if (paperConfig.lootables.autoReplenish) {
|
||||
+ final long min = paperConfig.lootables.refreshMin.seconds();
|
||||
+ final long max = paperConfig.lootables.refreshMax.seconds();
|
||||
+ this.nextRefill = this.lastFill + (min + RANDOM.nextLong(max - min + 1)) * 1000L;
|
||||
+ this.numRefills++;
|
||||
+ if (paperConfig.lootables.resetSeedOnFill) {
|
||||
+ holderInterface.setSeed(lootTableHolder, 0);
|
||||
+ }
|
||||
+ if (player != null) { // This means that numRefills can be incremented without a player being in the lootedPlayers list - Seems to be EntityMinecartChest specific
|
||||
+ this.setPlayerLootedState(player.getUUID(), true);
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ private static final String ROOT = "Paper.LootableData";
|
||||
+ private static final String LAST_FILL = "lastFill";
|
||||
+ private static final String NEXT_REFILL = "nextRefill";
|
||||
+ private static final String NUM_REFILLS = "numRefills";
|
||||
+ private static final String LOOTED_PLAYERS = "lootedPlayers";
|
||||
+
|
||||
+ public void loadNbt(final CompoundTag base) {
|
||||
+ if (!base.contains(ROOT, Tag.TAG_COMPOUND)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ final CompoundTag comp = base.getCompound(ROOT);
|
||||
+ if (comp.contains(LAST_FILL)) {
|
||||
+ this.lastFill = comp.getLong(LAST_FILL);
|
||||
+ }
|
||||
+ if (comp.contains(NEXT_REFILL)) {
|
||||
+ this.nextRefill = comp.getLong(NEXT_REFILL);
|
||||
+ }
|
||||
+
|
||||
+ if (comp.contains(NUM_REFILLS)) {
|
||||
+ this.numRefills = comp.getInt(NUM_REFILLS);
|
||||
+ }
|
||||
+ if (comp.contains(LOOTED_PLAYERS, Tag.TAG_LIST)) {
|
||||
+ final ListTag list = comp.getList(LOOTED_PLAYERS, Tag.TAG_COMPOUND);
|
||||
+ final int size = list.size();
|
||||
+ if (size > 0) {
|
||||
+ this.lootedPlayers = new HashMap<>(list.size());
|
||||
+ }
|
||||
+ for (int i = 0; i < size; i++) {
|
||||
+ final CompoundTag cmp = list.getCompound(i);
|
||||
+ this.lootedPlayers.put(cmp.getUUID("UUID"), cmp.getLong("Time"));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void saveNbt(final CompoundTag base) {
|
||||
+ final CompoundTag comp = new CompoundTag();
|
||||
+ if (this.nextRefill != -1) {
|
||||
+ comp.putLong(NEXT_REFILL, this.nextRefill);
|
||||
+ }
|
||||
+ if (this.lastFill != -1) {
|
||||
+ comp.putLong(LAST_FILL, this.lastFill);
|
||||
+ }
|
||||
+ if (this.numRefills != 0) {
|
||||
+ comp.putInt(NUM_REFILLS, this.numRefills);
|
||||
+ }
|
||||
+ if (this.lootedPlayers != null && !this.lootedPlayers.isEmpty()) {
|
||||
+ final ListTag list = new ListTag();
|
||||
+ for (final Map.Entry<UUID, Long> entry : this.lootedPlayers.entrySet()) {
|
||||
+ final CompoundTag cmp = new CompoundTag();
|
||||
+ cmp.putUUID("UUID", entry.getKey());
|
||||
+ cmp.putLong("Time", entry.getValue());
|
||||
+ list.add(cmp);
|
||||
+ }
|
||||
+ comp.put(LOOTED_PLAYERS, list);
|
||||
+ }
|
||||
+
|
||||
+ if (!comp.isEmpty()) {
|
||||
+ base.put(ROOT, comp);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ void setPlayerLootedState(final UUID player, final boolean looted) {
|
||||
+ if (looted && this.lootedPlayers == null) {
|
||||
+ this.lootedPlayers = new HashMap<>();
|
||||
+ }
|
||||
+ if (looted) {
|
||||
+ this.lootedPlayers.put(player, System.currentTimeMillis());
|
||||
+ } else if (this.lootedPlayers != null) {
|
||||
+ this.lootedPlayers.remove(player);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ boolean canPlayerLoot(final UUID player, final WorldConfiguration worldConfiguration) {
|
||||
+ final @Nullable Long lastLooted = this.getLastLooted(player);
|
||||
+ if (!worldConfiguration.lootables.restrictPlayerReloot || lastLooted == null) return true;
|
||||
+
|
||||
+ final DurationOrDisabled restrictPlayerRelootTime = worldConfiguration.lootables.restrictPlayerRelootTime;
|
||||
+ if (restrictPlayerRelootTime.value().isEmpty()) return false;
|
||||
+
|
||||
+ return TimeUnit.SECONDS.toMillis(restrictPlayerRelootTime.value().get().seconds()) + lastLooted < System.currentTimeMillis();
|
||||
+ }
|
||||
+
|
||||
+ boolean hasPlayerLooted(final UUID player) {
|
||||
+ return this.lootedPlayers != null && this.lootedPlayers.containsKey(player);
|
||||
+ }
|
||||
+
|
||||
+ @Nullable Long getLastLooted(final UUID player) {
|
||||
+ return this.lootedPlayers != null ? this.lootedPlayers.get(player) : null;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/RandomizableContainer.java b/src/main/java/net/minecraft/world/RandomizableContainer.java
|
||||
index 9715f1b63aeea39bde9258275f51e3e8508ca6e4..084935138b1484f3d96e99f4e5655a6c04931907 100644
|
||||
--- a/src/main/java/net/minecraft/world/RandomizableContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/RandomizableContainer.java
|
||||
@@ -28,7 +28,7 @@ public interface RandomizableContainer extends Container {
|
||||
|
||||
void setLootTable(@Nullable ResourceKey<LootTable> lootTable);
|
||||
|
||||
- default void setLootTable(ResourceKey<LootTable> lootTableId, long lootTableSeed) {
|
||||
+ default void setLootTable(@Nullable ResourceKey<LootTable> lootTableId, long lootTableSeed) { // Paper - add nullable
|
||||
this.setLootTable(lootTableId);
|
||||
this.setLootTableSeed(lootTableSeed);
|
||||
}
|
||||
@@ -51,13 +51,14 @@ public interface RandomizableContainer extends Container {
|
||||
default boolean tryLoadLootTable(CompoundTag nbt) {
|
||||
if (nbt.contains("LootTable", 8)) {
|
||||
this.setLootTable(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable"))));
|
||||
+ if (this.lootableData() != null && this.getLootTable() != null) this.lootableData().loadNbt(nbt); // Paper - LootTable API
|
||||
if (nbt.contains("LootTableSeed", 4)) {
|
||||
this.setLootTableSeed(nbt.getLong("LootTableSeed"));
|
||||
} else {
|
||||
this.setLootTableSeed(0L);
|
||||
}
|
||||
|
||||
- return true;
|
||||
+ return this.lootableData() == null; // Paper - only track the loot table if there is chance for replenish
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -69,26 +70,44 @@ public interface RandomizableContainer extends Container {
|
||||
return false;
|
||||
} else {
|
||||
nbt.putString("LootTable", resourceKey.location().toString());
|
||||
+ if (this.lootableData() != null) this.lootableData().saveNbt(nbt); // Paper - LootTable API
|
||||
long l = this.getLootTableSeed();
|
||||
if (l != 0L) {
|
||||
nbt.putLong("LootTableSeed", l);
|
||||
}
|
||||
|
||||
- return true;
|
||||
+ return this.lootableData() == null; // Paper - only track the loot table if there is chance for replenish
|
||||
}
|
||||
}
|
||||
|
||||
default void unpackLootTable(@Nullable Player player) {
|
||||
+ // Paper start - LootTable API
|
||||
+ this.unpackLootTable(player, false);
|
||||
+ }
|
||||
+ default void unpackLootTable(@Nullable final Player player, final boolean forceClearLootTable) {
|
||||
+ // Paper end - LootTable API
|
||||
Level level = this.getLevel();
|
||||
BlockPos blockPos = this.getBlockPos();
|
||||
ResourceKey<LootTable> resourceKey = this.getLootTable();
|
||||
- if (resourceKey != null && level != null && level.getServer() != null) {
|
||||
+ // Paper start - LootTable API
|
||||
+ lootReplenish: if (resourceKey != null && level != null && level.getServer() != null) {
|
||||
+ if (this.lootableData() != null && !this.lootableData().shouldReplenish(this, com.destroystokyo.paper.loottable.PaperLootableInventoryData.CONTAINER, player)) {
|
||||
+ if (forceClearLootTable) {
|
||||
+ this.setLootTable(null);
|
||||
+ }
|
||||
+ break lootReplenish;
|
||||
+ }
|
||||
+ // Paper end - LootTable API
|
||||
LootTable lootTable = level.getServer().reloadableRegistries().getLootTable(resourceKey);
|
||||
if (player instanceof ServerPlayer) {
|
||||
CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer)player, resourceKey);
|
||||
}
|
||||
|
||||
- this.setLootTable(null);
|
||||
+ // Paper start - LootTable API
|
||||
+ if (forceClearLootTable || this.lootableData() == null || this.lootableData().shouldClearLootTable(this, com.destroystokyo.paper.loottable.PaperLootableInventoryData.CONTAINER, player)) {
|
||||
+ this.setLootTable(null);
|
||||
+ }
|
||||
+ // Paper end - LootTable API
|
||||
LootParams.Builder builder = new LootParams.Builder((ServerLevel)level).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(blockPos));
|
||||
if (player != null) {
|
||||
builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player);
|
||||
@@ -97,4 +116,16 @@ public interface RandomizableContainer extends Container {
|
||||
lootTable.fill(this, builder.create(LootContextParamSets.CHEST), this.getLootTableSeed());
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Paper start - LootTable API
|
||||
+ @Nullable @org.jetbrains.annotations.Contract(pure = true)
|
||||
+ default com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData() {
|
||||
+ return null; // some containers don't really have a "replenish" ability like decorated pots
|
||||
+ }
|
||||
+
|
||||
+ default com.destroystokyo.paper.loottable.PaperLootableInventory getLootableInventory() {
|
||||
+ final org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(java.util.Objects.requireNonNull(this.getLevel(), "Cannot manage loot tables on block entities not in world"), this.getBlockPos());
|
||||
+ return (com.destroystokyo.paper.loottable.PaperLootableInventory) block.getState(false);
|
||||
+ }
|
||||
+ // Paper end - LootTable API
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
|
||||
index 67840327e934b631a85cf2d64911f5cfab4402b1..9549eee0d92f322bd5232abd7e695213660c2e22 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
|
||||
@@ -35,6 +35,14 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
|
||||
public ResourceKey<LootTable> lootTable;
|
||||
public long lootTableSeed;
|
||||
|
||||
+ // Paper start - LootTable API
|
||||
+ final com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData();
|
||||
+
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData() {
|
||||
+ return this.lootableData;
|
||||
+ }
|
||||
+ // Paper end - LootTable API
|
||||
// CraftBukkit start
|
||||
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
||||
private int maxStack = MAX_STACK;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
|
||||
index 42f8e2d961f83c3e9ce384158b9dfc4014eb0a5f..4cdf3b54187ebcb1f5ddfa6114386127a2846f01 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
|
||||
@@ -217,7 +217,7 @@ public class ChestBoat extends Boat implements HasCustomInventoryScreen, Contain
|
||||
@Nullable
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu(int syncId, Inventory playerInventory, Player player) {
|
||||
- if (this.lootTable != null && player.isSpectator()) {
|
||||
+ if (this.lootTable != null && player.isSpectator()) { // Paper - LootTable API (TODO spectators can open chests that aren't ready to be re-generated but this doesn't support that)
|
||||
return null;
|
||||
} else {
|
||||
this.unpackLootTable(playerInventory.player);
|
||||
@@ -265,6 +265,14 @@ public class ChestBoat extends Boat implements HasCustomInventoryScreen, Contain
|
||||
this.level().gameEvent((Holder) GameEvent.CONTAINER_CLOSE, this.position(), GameEvent.Context.of((Entity) player));
|
||||
}
|
||||
|
||||
+ // Paper start - LootTable API
|
||||
+ final com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData();
|
||||
+
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData() {
|
||||
+ return this.lootableData;
|
||||
+ }
|
||||
+ // Paper end - LootTable API
|
||||
// CraftBukkit start
|
||||
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
||||
private int maxStack = MAX_STACK;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
|
||||
index 3ee99193de5deb6a38d6ded561fe8f2fbf711327..ccc7367ab2740bea0f2b907223a0920b11665092 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
|
||||
@@ -62,22 +62,26 @@ public interface ContainerEntity extends Container, MenuProvider {
|
||||
default void addChestVehicleSaveData(CompoundTag nbt, HolderLookup.Provider registriesLookup) {
|
||||
if (this.getLootTable() != null) {
|
||||
nbt.putString("LootTable", this.getLootTable().location().toString());
|
||||
+ this.lootableData().saveNbt(nbt); // Paper
|
||||
if (this.getLootTableSeed() != 0L) {
|
||||
nbt.putLong("LootTableSeed", this.getLootTableSeed());
|
||||
}
|
||||
- } else {
|
||||
- ContainerHelper.saveAllItems(nbt, this.getItemStacks(), registriesLookup);
|
||||
}
|
||||
+ ContainerHelper.saveAllItems(nbt, this.getItemStacks(), registriesLookup); // Paper - always save the items, table may still remain
|
||||
}
|
||||
|
||||
default void readChestVehicleSaveData(CompoundTag nbt, HolderLookup.Provider registriesLookup) {
|
||||
this.clearItemStacks();
|
||||
if (nbt.contains("LootTable", 8)) {
|
||||
this.setLootTable(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable"))));
|
||||
+ // Paper start - LootTable API
|
||||
+ if (this.getLootTable() != null) {
|
||||
+ this.lootableData().loadNbt(nbt);
|
||||
+ }
|
||||
+ // Paper end - LootTable API
|
||||
this.setLootTableSeed(nbt.getLong("LootTableSeed"));
|
||||
- } else {
|
||||
- ContainerHelper.loadAllItems(nbt, this.getItemStacks(), registriesLookup);
|
||||
}
|
||||
+ ContainerHelper.loadAllItems(nbt, this.getItemStacks(), registriesLookup); // Paper - always save the items, table may still remain
|
||||
}
|
||||
|
||||
default void chestVehicleDestroyed(DamageSource source, Level world, Entity vehicle) {
|
||||
@@ -99,13 +103,17 @@ public interface ContainerEntity extends Container, MenuProvider {
|
||||
|
||||
default void unpackChestVehicleLootTable(@Nullable Player player) {
|
||||
MinecraftServer minecraftServer = this.level().getServer();
|
||||
- if (this.getLootTable() != null && minecraftServer != null) {
|
||||
+ if (minecraftServer != null && this.lootableData().shouldReplenish(this, com.destroystokyo.paper.loottable.PaperLootableInventoryData.ENTITY, player)) { // Paper - LootTable API
|
||||
LootTable lootTable = minecraftServer.reloadableRegistries().getLootTable(this.getLootTable());
|
||||
if (player != null) {
|
||||
CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer)player, this.getLootTable());
|
||||
}
|
||||
|
||||
- this.setLootTable(null);
|
||||
+ // Paper start - LootTable API
|
||||
+ if (this.lootableData().shouldClearLootTable(this, com.destroystokyo.paper.loottable.PaperLootableInventoryData.ENTITY, player)) {
|
||||
+ this.setLootTable(null);
|
||||
+ }
|
||||
+ // Paper end - LootTable API
|
||||
LootParams.Builder builder = new LootParams.Builder((ServerLevel)this.level()).withParameter(LootContextParams.ORIGIN, this.position());
|
||||
if (player != null) {
|
||||
builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player);
|
||||
@@ -175,4 +183,14 @@ public interface ContainerEntity extends Container, MenuProvider {
|
||||
default boolean isChestVehicleStillValid(Player player) {
|
||||
return !this.isRemoved() && player.canInteractWithEntity(this.getBoundingBox(), 4.0);
|
||||
}
|
||||
+
|
||||
+ // Paper start - LootTable API
|
||||
+ default com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData() {
|
||||
+ throw new UnsupportedOperationException("Implement this method");
|
||||
+ }
|
||||
+
|
||||
+ default com.destroystokyo.paper.loottable.PaperLootableInventory getLootableInventory() {
|
||||
+ return ((com.destroystokyo.paper.loottable.PaperLootableInventory) ((net.minecraft.world.entity.Entity) this).getBukkitEntity());
|
||||
+ }
|
||||
+ // Paper end - LootTable API
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/ShulkerBoxBlock.java b/src/main/java/net/minecraft/world/level/block/ShulkerBoxBlock.java
|
||||
index d85da0661096a3587917c6636728bfd2e3eb90a2..6323c96d9b0cd14f89609b38da37d7fcc12d211b 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/ShulkerBoxBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/ShulkerBoxBlock.java
|
||||
@@ -148,7 +148,7 @@ public class ShulkerBoxBlock extends BaseEntityBlock {
|
||||
itemEntity.setDefaultPickUpDelay();
|
||||
world.addFreshEntity(itemEntity);
|
||||
} else {
|
||||
- shulkerBoxBlockEntity.unpackLootTable(player);
|
||||
+ shulkerBoxBlockEntity.unpackLootTable(player, true); // Paper - force clear loot table so replenish data isn't persisted in the stack
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,15 @@ public class ShulkerBoxBlock extends BaseEntityBlock {
|
||||
@Override
|
||||
protected List<ItemStack> getDrops(BlockState state, LootParams.Builder builder) {
|
||||
BlockEntity blockEntity = builder.getOptionalParameter(LootContextParams.BLOCK_ENTITY);
|
||||
+ Runnable reAdd = null; // Paper
|
||||
if (blockEntity instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity) {
|
||||
+ // Paper start - clear loot table if it was already used
|
||||
+ if (shulkerBoxBlockEntity.lootableData().getLastFill() != -1 || !builder.getLevel().paperConfig().lootables.retainUnlootedShulkerBoxLootTableOnNonPlayerBreak) {
|
||||
+ net.minecraft.resources.ResourceKey<net.minecraft.world.level.storage.loot.LootTable> lootTableResourceKey = shulkerBoxBlockEntity.getLootTable();
|
||||
+ reAdd = () -> shulkerBoxBlockEntity.setLootTable(lootTableResourceKey);
|
||||
+ shulkerBoxBlockEntity.setLootTable(null);
|
||||
+ }
|
||||
+ // Paper end
|
||||
builder = builder.withDynamicDrop(CONTENTS, lootConsumer -> {
|
||||
for (int i = 0; i < shulkerBoxBlockEntity.getContainerSize(); i++) {
|
||||
lootConsumer.accept(shulkerBoxBlockEntity.getItem(i));
|
||||
@@ -166,7 +174,13 @@ public class ShulkerBoxBlock extends BaseEntityBlock {
|
||||
});
|
||||
}
|
||||
|
||||
+ // Paper start - re-set loot table if it was cleared
|
||||
+ try {
|
||||
return super.getDrops(state, builder);
|
||||
+ } finally {
|
||||
+ if (reAdd != null) reAdd.run();
|
||||
+ }
|
||||
+ // Paper end - re-set loot table if it was cleared
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
index c2493c15d8fe4587d6ee2db100cc13303b66b39b..13c9a68b604d4c7c6e09e72b3cea7ab2214b06ab 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
@@ -115,4 +115,13 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
|
||||
nbt.remove("LootTable");
|
||||
nbt.remove("LootTableSeed");
|
||||
}
|
||||
+
|
||||
+ // Paper start - LootTable API
|
||||
+ final com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(); // Paper
|
||||
+
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData() {
|
||||
+ return this.lootableData;
|
||||
+ }
|
||||
+ // Paper end - LootTable API
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java
|
||||
index 949e074a32b6593bd8b7405499e686a074e283e5..1f084b73f2ec67dd2022feafc5ab5dac02c338f6 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java
|
||||
@@ -58,7 +58,8 @@ public class CraftBrushableBlock extends CraftBlockEntityState<BrushableBlockEnt
|
||||
this.setLootTable(this.getLootTable(), seed);
|
||||
}
|
||||
|
||||
- private void setLootTable(LootTable table, long seed) {
|
||||
+ @Override // Paper - this is now an override
|
||||
+ public void setLootTable(LootTable table, long seed) { // Paper - make public since it overrides a public method
|
||||
this.getSnapshot().setLootTable(CraftLootTable.bukkitToMinecraft(table), seed);
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
|
||||
index 74315a46f6101775321b1cf4944c124c69aed182..f23fbb8ed39a754b36d2eb162358877ef6dacb17 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
|
||||
@@ -8,7 +8,7 @@ import org.bukkit.craftbukkit.CraftLootTable;
|
||||
import org.bukkit.loot.LootTable;
|
||||
import org.bukkit.loot.Lootable;
|
||||
|
||||
-public abstract class CraftLootable<T extends RandomizableContainerBlockEntity> extends CraftContainer<T> implements Nameable, Lootable {
|
||||
+public abstract class CraftLootable<T extends RandomizableContainerBlockEntity> extends CraftContainer<T> implements Nameable, Lootable, com.destroystokyo.paper.loottable.PaperLootableBlockInventory { // Paper
|
||||
|
||||
public CraftLootable(World world, T tileEntity) {
|
||||
super(world, tileEntity);
|
||||
@@ -27,29 +27,17 @@ public abstract class CraftLootable<T extends RandomizableContainerBlockEntity>
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - move to PaperLootableBlockInventory
|
||||
@Override
|
||||
- public LootTable getLootTable() {
|
||||
- return CraftLootTable.minecraftToBukkit(this.getSnapshot().lootTable);
|
||||
+ public net.minecraft.world.level.Level getNMSWorld() {
|
||||
+ return ((org.bukkit.craftbukkit.CraftWorld) this.getWorld()).getHandle();
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void setLootTable(LootTable table) {
|
||||
- this.setLootTable(table, this.getSeed());
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public long getSeed() {
|
||||
- return this.getSnapshot().lootTableSeed;
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public void setSeed(long seed) {
|
||||
- this.setLootTable(this.getLootTable(), seed);
|
||||
- }
|
||||
-
|
||||
- public void setLootTable(LootTable table, long seed) {
|
||||
- this.getSnapshot().setLootTable(CraftLootTable.bukkitToMinecraft(table), seed);
|
||||
+ public net.minecraft.world.RandomizableContainer getRandomizableContainer() {
|
||||
+ return this.getSnapshot();
|
||||
}
|
||||
+ // Paper end - move to PaperLootableBlockInventory
|
||||
|
||||
@Override
|
||||
public abstract CraftLootable<T> copy();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
|
||||
index cfde210ea9d4b62fe514d3ab0dbab2f43eda0c7a..e4f899a6a1d055b3ea17d1114ed0228fbba53352 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
|
||||
@@ -7,8 +7,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventory;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.loot.LootTable;
|
||||
|
||||
-public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.ChestBoat {
|
||||
-
|
||||
+public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.ChestBoat, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
|
||||
private final Inventory inventory;
|
||||
|
||||
public CraftChestBoat(CraftServer server, ChestBoat entity) {
|
||||
@@ -31,28 +30,5 @@ public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.Chest
|
||||
return this.inventory;
|
||||
}
|
||||
|
||||
- @Override
|
||||
- public void setLootTable(LootTable table) {
|
||||
- this.setLootTable(table, this.getSeed());
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public LootTable getLootTable() {
|
||||
- return CraftLootTable.minecraftToBukkit(this.getHandle().getLootTable());
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public void setSeed(long seed) {
|
||||
- this.setLootTable(this.getLootTable(), seed);
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public long getSeed() {
|
||||
- return this.getHandle().getLootTableSeed();
|
||||
- }
|
||||
-
|
||||
- private void setLootTable(LootTable table, long seed) {
|
||||
- this.getHandle().setLootTable(CraftLootTable.bukkitToMinecraft(table));
|
||||
- this.getHandle().setLootTableSeed(seed);
|
||||
- }
|
||||
+ // Paper - moved loot table logic to PaperLootableEntityInventory
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
|
||||
index fd42f0b20132d08039ca7735d31a61806a6b07dc..b1a708de6790bbe336202b13ab862ced78de084f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
|
||||
@@ -7,7 +7,7 @@ import org.bukkit.entity.minecart.StorageMinecart;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
-public class CraftMinecartChest extends CraftMinecartContainer implements StorageMinecart {
|
||||
+public class CraftMinecartChest extends CraftMinecartContainer implements StorageMinecart, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
|
||||
private final CraftInventory inventory;
|
||||
|
||||
public CraftMinecartChest(CraftServer server, MinecartChest entity) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartContainer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartContainer.java
|
||||
index 4388cd0303b45faf21631e7644baebb63baaba10..451f3a6f0b47493da3af3f5d6baced6a8c97f350 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartContainer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartContainer.java
|
||||
@@ -7,7 +7,7 @@ import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.loot.LootTable;
|
||||
import org.bukkit.loot.Lootable;
|
||||
|
||||
-public abstract class CraftMinecartContainer extends CraftMinecart implements Lootable {
|
||||
+public abstract class CraftMinecartContainer extends CraftMinecart implements com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
|
||||
|
||||
public CraftMinecartContainer(CraftServer server, AbstractMinecart entity) {
|
||||
super(server, entity);
|
||||
@@ -18,27 +18,5 @@ public abstract class CraftMinecartContainer extends CraftMinecart implements Lo
|
||||
return (AbstractMinecartContainer) this.entity;
|
||||
}
|
||||
|
||||
- @Override
|
||||
- public void setLootTable(LootTable table) {
|
||||
- this.setLootTable(table, this.getSeed());
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public LootTable getLootTable() {
|
||||
- return CraftLootTable.minecraftToBukkit(this.getHandle().lootTable);
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public void setSeed(long seed) {
|
||||
- this.setLootTable(this.getLootTable(), seed);
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public long getSeed() {
|
||||
- return this.getHandle().lootTableSeed;
|
||||
- }
|
||||
-
|
||||
- public void setLootTable(LootTable table, long seed) {
|
||||
- this.getHandle().setLootTable(CraftLootTable.bukkitToMinecraft(table), seed);
|
||||
- }
|
||||
+ // Paper - moved loot table logic to PaperLootableEntityInventory
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
|
||||
index 39427b4f284e9402663be2b160ccb5f03f8b91da..17f5684cba9d3ed22d9925d1951520cc4751dfe2 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
|
||||
@@ -6,7 +6,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventory;
|
||||
import org.bukkit.entity.minecart.HopperMinecart;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
|
||||
-public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart {
|
||||
+public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
|
||||
private final CraftInventory inventory;
|
||||
|
||||
public CraftMinecartHopper(CraftServer server, MinecartHopper entity) {
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Thu, 12 May 2016 23:02:58 -0500
|
||||
Subject: [PATCH] System property for disabling watchdoge
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index 35c90aaee30980610d168c01cbe9abfe04331cb8..81ccbe2533e6fc5899d6c068e421e0d7f1351d34 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -61,7 +61,7 @@ public class WatchdogThread extends Thread
|
||||
while ( !this.stopping )
|
||||
{
|
||||
//
|
||||
- if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.monotonicMillis() > this.lastTick + this.timeoutTime )
|
||||
+ if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.monotonicMillis() > this.lastTick + this.timeoutTime && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
|
||||
{
|
||||
Logger log = Bukkit.getServer().getLogger();
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
|
@ -1,86 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 16 May 2016 20:47:41 -0400
|
||||
Subject: [PATCH] Async GameProfileCache saving
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index f16ade2019e58a9374a550f58113313c118c2f2b..10d69b48158460e5739d1e41a83fcaeec819fac6 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -998,7 +998,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
} catch (java.lang.InterruptedException ignored) {} // Paper
|
||||
if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) {
|
||||
MinecraftServer.LOGGER.info("Saving usercache.json");
|
||||
- this.getProfileCache().save();
|
||||
+ this.getProfileCache().save(false); // Paper - Perf: Async GameProfileCache saving
|
||||
}
|
||||
// Spigot end
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 48107f8eb50483430053b990496862d71c9f8a3e..c1f41dcf49c75c3d69485c0e1ec821205438ed1e 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -270,7 +270,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
}
|
||||
|
||||
if (this.convertOldUsers()) {
|
||||
- this.getProfileCache().save();
|
||||
+ this.getProfileCache().save(false); // Paper - Perf: Async GameProfileCache saving
|
||||
}
|
||||
|
||||
if (!OldUsersConverter.serverReadyAfterUserconversion(this)) {
|
||||
diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java
|
||||
index f6e290bf4480da51512f8a166459687dad1f6a07..5b219b5eee0c5958b80093c9223feeed0dec830b 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java
|
||||
@@ -117,7 +117,7 @@ public class GameProfileCache {
|
||||
GameProfileCache.GameProfileInfo usercache_usercacheentry = new GameProfileCache.GameProfileInfo(profile, date);
|
||||
|
||||
this.safeAdd(usercache_usercacheentry);
|
||||
- if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.save(); // Spigot - skip saving if disabled
|
||||
+ if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.save(true); // Spigot - skip saving if disabled // Paper - Perf: Async GameProfileCache saving
|
||||
}
|
||||
|
||||
private long getNextOperation() {
|
||||
@@ -150,7 +150,7 @@ public class GameProfileCache {
|
||||
}
|
||||
|
||||
if (flag && !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { // Spigot - skip saving if disabled
|
||||
- this.save();
|
||||
+ this.save(true); // Paper - Perf: Async GameProfileCache saving
|
||||
}
|
||||
|
||||
return optional;
|
||||
@@ -262,7 +262,7 @@ public class GameProfileCache {
|
||||
return list;
|
||||
}
|
||||
|
||||
- public void save() {
|
||||
+ public void save(boolean asyncSave) { // Paper - Perf: Async GameProfileCache saving
|
||||
JsonArray jsonarray = new JsonArray();
|
||||
DateFormat dateformat = GameProfileCache.createDateFormat();
|
||||
|
||||
@@ -270,6 +270,7 @@ public class GameProfileCache {
|
||||
jsonarray.add(GameProfileCache.writeGameProfile(usercache_usercacheentry, dateformat));
|
||||
});
|
||||
String s = this.gson.toJson(jsonarray);
|
||||
+ Runnable save = () -> { // Paper - Perf: Async GameProfileCache saving
|
||||
|
||||
try {
|
||||
BufferedWriter bufferedwriter = Files.newWriter(this.file, StandardCharsets.UTF_8);
|
||||
@@ -294,6 +295,14 @@ public class GameProfileCache {
|
||||
} catch (IOException ioexception) {
|
||||
;
|
||||
}
|
||||
+ // Paper start - Perf: Async GameProfileCache saving
|
||||
+ };
|
||||
+ if (asyncSave) {
|
||||
+ io.papermc.paper.util.MCUtil.scheduleAsyncTask(save);
|
||||
+ } else {
|
||||
+ save.run();
|
||||
+ }
|
||||
+ // Paper end - Perf: Async GameProfileCache saving
|
||||
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Sun, 22 May 2016 20:20:55 -0500
|
||||
Subject: [PATCH] Optional TNT doesn't move in water
|
||||
|
||||
|
||||
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 15432b512fc0d0d38bf28499e2afa5e48fec7aaa..47f2a480f6a4b15e55cedbfa8a58459d33516a97 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
@@ -128,6 +128,27 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Option to prevent TNT from moving in water
|
||||
+ if (!this.isRemoved() && this.wasTouchingWater && this.level().paperConfig().fixes.preventTntFromMovingInWater) {
|
||||
+ /*
|
||||
+ * Author: Jedediah Smith <jedediah@silencegreys.com>
|
||||
+ */
|
||||
+ // Send position and velocity updates to nearby players on every tick while the TNT is in water.
|
||||
+ // This does pretty well at keeping their clients in sync with the server.
|
||||
+ net.minecraft.server.level.ChunkMap.TrackedEntity ete = ((net.minecraft.server.level.ServerLevel)this.level()).getChunkSource().chunkMap.entityMap.get(this.getId());
|
||||
+ if (ete != null) {
|
||||
+ net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket velocityPacket = new net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket(this);
|
||||
+ net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket positionPacket = new net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket(this);
|
||||
+
|
||||
+ ete.seenBy.stream()
|
||||
+ .filter(viewer -> (viewer.getPlayer().getX() - this.getX()) * (viewer.getPlayer().getY() - this.getY()) * (viewer.getPlayer().getZ() - this.getZ()) < 16 * 16)
|
||||
+ .forEach(viewer -> {
|
||||
+ viewer.send(velocityPacket);
|
||||
+ viewer.send(positionPacket);
|
||||
+ });
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Option to prevent TNT from moving in water
|
||||
}
|
||||
|
||||
private void explode() {
|
||||
@@ -202,4 +223,11 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||
|
||||
return entity;
|
||||
}
|
||||
+
|
||||
+ // Paper start - Option to prevent TNT from moving in water
|
||||
+ @Override
|
||||
+ public boolean isPushedByFluid() {
|
||||
+ return !level().paperConfig().fixes.preventTntFromMovingInWater && super.isPushedByFluid();
|
||||
+ }
|
||||
+ // Paper end - Option to prevent TNT from moving in water
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Panzer <postremus1996@googlemail.com>
|
||||
Date: Mon, 23 May 2016 12:12:37 +0200
|
||||
Subject: [PATCH] Faster redstone torch rapid clock removal
|
||||
|
||||
Only resize the the redstone torch list once, since resizing arrays / lists is costly
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 622ecc1aeb9140d5c0d181fa472d123c42e5c5f4..4abb586f964e342425c7cf0384ab8bf8cdedaea3 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -169,6 +169,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
private org.spigotmc.TickLimiter tileLimiter;
|
||||
private int tileTickPosition;
|
||||
public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
|
||||
+ public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> redstoneUpdateInfos; // Paper - Faster redstone torch rapid clock removal; Move from Map in BlockRedstoneTorch to here
|
||||
|
||||
public CraftWorld getWorld() {
|
||||
return this.world;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java b/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java
|
||||
index 20d20db2639030c103e9d1b3c8da0f51344b81c2..ceba9617748a8b4f3a9bd459475952c9c6c9ed7c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java
|
||||
@@ -24,7 +24,7 @@ public class RedstoneTorchBlock extends BaseTorchBlock {
|
||||
|
||||
public static final MapCodec<RedstoneTorchBlock> CODEC = simpleCodec(RedstoneTorchBlock::new);
|
||||
public static final BooleanProperty LIT = BlockStateProperties.LIT;
|
||||
- private static final Map<BlockGetter, List<RedstoneTorchBlock.Toggle>> RECENT_TOGGLES = new WeakHashMap();
|
||||
+ // Paper - Faster redstone torch rapid clock removal; Move the mapped list to World
|
||||
public static final int RECENT_TOGGLE_TIMER = 60;
|
||||
public static final int MAX_RECENT_TOGGLES = 8;
|
||||
public static final int RESTART_DELAY = 160;
|
||||
@@ -80,11 +80,15 @@ public class RedstoneTorchBlock extends BaseTorchBlock {
|
||||
@Override
|
||||
protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
||||
boolean flag = this.hasNeighborSignal(world, pos, state);
|
||||
- List<RedstoneTorchBlock.Toggle> list = (List) RedstoneTorchBlock.RECENT_TOGGLES.get(world);
|
||||
-
|
||||
- while (list != null && !list.isEmpty() && world.getGameTime() - ((RedstoneTorchBlock.Toggle) list.get(0)).when > 60L) {
|
||||
- list.remove(0);
|
||||
+ // Paper start - Faster redstone torch rapid clock removal
|
||||
+ java.util.ArrayDeque<RedstoneTorchBlock.Toggle> redstoneUpdateInfos = world.redstoneUpdateInfos;
|
||||
+ if (redstoneUpdateInfos != null) {
|
||||
+ RedstoneTorchBlock.Toggle curr;
|
||||
+ while ((curr = redstoneUpdateInfos.peek()) != null && world.getGameTime() - curr.when > 60L) {
|
||||
+ redstoneUpdateInfos.poll();
|
||||
+ }
|
||||
}
|
||||
+ // Paper end - Faster redstone torch rapid clock removal
|
||||
|
||||
// CraftBukkit start
|
||||
org.bukkit.plugin.PluginManager manager = world.getCraftServer().getPluginManager();
|
||||
@@ -160,9 +164,12 @@ public class RedstoneTorchBlock extends BaseTorchBlock {
|
||||
}
|
||||
|
||||
private static boolean isToggledTooFrequently(Level world, BlockPos pos, boolean addNew) {
|
||||
- List<RedstoneTorchBlock.Toggle> list = (List) RedstoneTorchBlock.RECENT_TOGGLES.computeIfAbsent(world, (iblockaccess) -> {
|
||||
- return Lists.newArrayList();
|
||||
- });
|
||||
+ // Paper start - Faster redstone torch rapid clock removal
|
||||
+ java.util.ArrayDeque<RedstoneTorchBlock.Toggle> list = world.redstoneUpdateInfos;
|
||||
+ if (list == null) {
|
||||
+ list = world.redstoneUpdateInfos = new java.util.ArrayDeque<>();
|
||||
+ }
|
||||
+ // Paper end - Faster redstone torch rapid clock removal
|
||||
|
||||
if (addNew) {
|
||||
list.add(new RedstoneTorchBlock.Toggle(pos.immutable(), world.getGameTime()));
|
|
@ -1,25 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Panzer <postremus1996@googlemail.com>
|
||||
Date: Sat, 28 May 2016 16:54:03 +0200
|
||||
Subject: [PATCH] Add server-name parameter
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index 14f63c179428bee61d3b931ea309f4c94b89a6cc..75a3c7ed5500f0451c9c1efdfc3cb809445c8acf 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -168,6 +168,14 @@ public class Main {
|
||||
.defaultsTo(new File[] {})
|
||||
.describedAs("Jar file");
|
||||
// Paper end
|
||||
+
|
||||
+ // Paper start
|
||||
+ acceptsAll(asList("server-name"), "Name of the server")
|
||||
+ .withRequiredArg()
|
||||
+ .ofType(String.class)
|
||||
+ .defaultsTo("Unknown Server")
|
||||
+ .describedAs("Name");
|
||||
+ // Paper end
|
||||
}
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue