301
This commit is contained in:
parent
309ebc13fc
commit
1d7d7e92f2
52 changed files with 333 additions and 310 deletions
|
@ -1,397 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
|
||||
Date: Wed, 12 Sep 2018 18:53:55 +0300
|
||||
Subject: [PATCH] Add API for CanPlaceOn and CanDestroy NBT values
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
index 1920cf7ad846f57cd278cb9a72dce03f3d014fbb..7cf1153ae532a9d53ee85b05f77ed74b94cf5fbc 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
@@ -85,6 +85,12 @@ import org.bukkit.persistence.PersistentDataContainer;
|
||||
import static org.spigotmc.ValidateUtils.*;
|
||||
// Spigot end
|
||||
|
||||
+// Paper start
|
||||
+import com.destroystokyo.paper.Namespaced;
|
||||
+import com.destroystokyo.paper.NamespacedTag;
|
||||
+import java.util.Collections;
|
||||
+// Paper end
|
||||
+
|
||||
/**
|
||||
* Children must include the following:
|
||||
*
|
||||
@@ -273,6 +279,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
@Specific(Specific.To.NBT)
|
||||
static final ItemMetaKey BLOCK_DATA = new ItemMetaKey("BlockStateTag");
|
||||
static final ItemMetaKey BUKKIT_CUSTOM_TAG = new ItemMetaKey("PublicBukkitValues");
|
||||
+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
+ static final ItemMetaKey CAN_DESTROY = new ItemMetaKey("CanDestroy");
|
||||
+ static final ItemMetaKey CAN_PLACE_ON = new ItemMetaKey("CanPlaceOn");
|
||||
+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
|
||||
// We store the raw original JSON representation of all text data. See SPIGOT-5063, SPIGOT-5656, SPIGOT-5304
|
||||
private String displayName;
|
||||
@@ -286,6 +296,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
private int hideFlag;
|
||||
private boolean unbreakable;
|
||||
private int damage;
|
||||
+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
+ private Set<Namespaced> placeableKeys = Sets.newHashSet();
|
||||
+ private Set<Namespaced> destroyableKeys = Sets.newHashSet();
|
||||
+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
|
||||
private static final Set<String> HANDLED_TAGS = Sets.newHashSet();
|
||||
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
|
||||
@@ -323,6 +337,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
this.hideFlag = meta.hideFlag;
|
||||
this.unbreakable = meta.unbreakable;
|
||||
this.damage = meta.damage;
|
||||
+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
+ if (meta.hasPlaceableKeys()) {
|
||||
+ this.placeableKeys = new java.util.HashSet<>(meta.placeableKeys);
|
||||
+ }
|
||||
+
|
||||
+ if (meta.hasDestroyableKeys()) {
|
||||
+ this.destroyableKeys = new java.util.HashSet<>(meta.destroyableKeys);
|
||||
+ }
|
||||
+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
this.unhandledTags.putAll(meta.unhandledTags);
|
||||
this.persistentDataContainer.putAll(meta.persistentDataContainer.getRaw());
|
||||
|
||||
@@ -386,6 +409,31 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
this.persistentDataContainer.put(key, compound.get(key).copy());
|
||||
}
|
||||
}
|
||||
+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
+ if (tag.contains(CAN_DESTROY.NBT)) {
|
||||
+ ListTag list = tag.getList(CAN_DESTROY.NBT, CraftMagicNumbers.NBT.TAG_STRING);
|
||||
+ for (int i = 0; i < list.size(); i++) {
|
||||
+ Namespaced namespaced = this.blockKeyFromString(list.getString(i));
|
||||
+ if (namespaced == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ this.destroyableKeys.add(namespaced);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (tag.contains(CAN_PLACE_ON.NBT)) {
|
||||
+ ListTag list = tag.getList(CAN_PLACE_ON.NBT, CraftMagicNumbers.NBT.TAG_STRING);
|
||||
+ for (int i = 0; i < list.size(); i++) {
|
||||
+ Namespaced namespaced = this.blockKeyFromString(list.getString(i));
|
||||
+ if (namespaced == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ this.placeableKeys.add(namespaced);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
|
||||
Set<String> keys = tag.getAllKeys();
|
||||
for (String key : keys) {
|
||||
@@ -524,6 +572,34 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
this.setDamage(damage);
|
||||
}
|
||||
|
||||
+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
+ Iterable<?> canPlaceOnSerialized = SerializableMeta.getObject(Iterable.class, map, CAN_PLACE_ON.BUKKIT, true);
|
||||
+ if (canPlaceOnSerialized != null) {
|
||||
+ for (Object canPlaceOnElement : canPlaceOnSerialized) {
|
||||
+ String canPlaceOnRaw = (String) canPlaceOnElement;
|
||||
+ Namespaced value = this.blockKeyFromString(canPlaceOnRaw);
|
||||
+ if (value == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ this.placeableKeys.add(value);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ Iterable<?> canDestroySerialized = SerializableMeta.getObject(Iterable.class, map, CAN_DESTROY.BUKKIT, true);
|
||||
+ if (canDestroySerialized != null) {
|
||||
+ for (Object canDestroyElement : canDestroySerialized) {
|
||||
+ String canDestroyRaw = (String) canDestroyElement;
|
||||
+ Namespaced value = this.blockKeyFromString(canDestroyRaw);
|
||||
+ if (value == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ this.destroyableKeys.add(value);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
+
|
||||
String internal = SerializableMeta.getString(map, "internal", true);
|
||||
if (internal != null) {
|
||||
ByteArrayInputStream buf = new ByteArrayInputStream(Base64.getDecoder().decode(internal));
|
||||
@@ -652,6 +728,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
if (this.hasDamage()) {
|
||||
itemTag.putInt(CraftMetaItem.DAMAGE.NBT, this.damage);
|
||||
}
|
||||
+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
+ if (hasPlaceableKeys()) {
|
||||
+ List<String> items = this.placeableKeys.stream()
|
||||
+ .map(this::serializeNamespaced)
|
||||
+ .collect(java.util.stream.Collectors.toList());
|
||||
+
|
||||
+ itemTag.put(CAN_PLACE_ON.NBT, createNonComponentStringList(items));
|
||||
+ }
|
||||
+
|
||||
+ if (hasDestroyableKeys()) {
|
||||
+ List<String> items = this.destroyableKeys.stream()
|
||||
+ .map(this::serializeNamespaced)
|
||||
+ .collect(java.util.stream.Collectors.toList());
|
||||
+
|
||||
+ itemTag.put(CAN_DESTROY.NBT, createNonComponentStringList(items));
|
||||
+ }
|
||||
+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
|
||||
for (Map.Entry<String, Tag> e : this.unhandledTags.entrySet()) {
|
||||
itemTag.put(e.getKey(), e.getValue());
|
||||
@@ -668,6 +761,21 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
+ static ListTag createNonComponentStringList(List<String> list) {
|
||||
+ if (list == null || list.isEmpty()) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ ListTag tagList = new ListTag();
|
||||
+ for (String value : list) {
|
||||
+ tagList.add(StringTag.valueOf(value)); // Paper - NBTTagString.of(String str)
|
||||
+ }
|
||||
+
|
||||
+ return tagList;
|
||||
+ }
|
||||
+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
|
||||
+
|
||||
ListTag createStringList(List<String> list) {
|
||||
if (list == null) {
|
||||
return null;
|
||||
@@ -751,7 +859,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
|
||||
@Overridden
|
||||
boolean isEmpty() {
|
||||
- return !(this.hasDisplayName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isUnbreakable() || this.hasDamage() || this.hasAttributeModifiers());
|
||||
+ return !(this.hasDisplayName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isUnbreakable() || this.hasDamage() || this.hasAttributeModifiers() || this.hasPlaceableKeys() || this.hasDestroyableKeys()); // Paper - Implement an API for CanPlaceOn and CanDestroy NBT values
|
||||
}
|
||||
|
||||
// Paper start
|
||||
@@ -1223,7 +1331,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
&& (this.hideFlag == that.hideFlag)
|
||||
&& (this.isUnbreakable() == that.isUnbreakable())
|
||||
&& (this.hasDamage() ? that.hasDamage() && this.damage == that.damage : !that.hasDamage())
|
||||
- && (this.version == that.version);
|
||||
+ && (this.version == that.version)
|
||||
+ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
|
||||
+ && (this.hasPlaceableKeys() ? that.hasPlaceableKeys() && this.placeableKeys.equals(that.placeableKeys) : !that.hasPlaceableKeys())
|
||||
+ && (this.hasDestroyableKeys() ? that.hasDestroyableKeys() && this.destroyableKeys.equals(that.destroyableKeys) : !that.hasDestroyableKeys());
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1258,6 +1370,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
hash = 61 * hash + (this.hasDamage() ? this.damage : 0);
|
||||
hash = 61 * hash + (this.hasAttributeModifiers() ? this.attributeModifiers.hashCode() : 0);
|
||||
hash = 61 * hash + this.version;
|
||||
+ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
|
||||
+ hash = 61 * hash + (this.hasPlaceableKeys() ? this.placeableKeys.hashCode() : 0);
|
||||
+ hash = 61 * hash + (this.hasDestroyableKeys() ? this.destroyableKeys.hashCode() : 0);
|
||||
+ // Paper end
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -1282,6 +1398,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
clone.unbreakable = this.unbreakable;
|
||||
clone.damage = this.damage;
|
||||
clone.version = this.version;
|
||||
+ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
|
||||
+ if (this.placeableKeys != null) {
|
||||
+ clone.placeableKeys = Sets.newHashSet(this.placeableKeys);
|
||||
+ }
|
||||
+ if (this.destroyableKeys != null) {
|
||||
+ clone.destroyableKeys = Sets.newHashSet(this.destroyableKeys);
|
||||
+ }
|
||||
+ // Paper end
|
||||
return clone;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new Error(e);
|
||||
@@ -1339,6 +1463,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
builder.put(CraftMetaItem.DAMAGE.BUKKIT, this.damage);
|
||||
}
|
||||
|
||||
+ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
|
||||
+ if (this.hasPlaceableKeys()) {
|
||||
+ List<String> cerealPlaceable = this.placeableKeys.stream()
|
||||
+ .map(this::serializeNamespaced)
|
||||
+ .collect(java.util.stream.Collectors.toList());
|
||||
+
|
||||
+ builder.put(CAN_PLACE_ON.BUKKIT, cerealPlaceable);
|
||||
+ }
|
||||
+
|
||||
+ if (this.hasDestroyableKeys()) {
|
||||
+ List<String> cerealDestroyable = this.destroyableKeys.stream()
|
||||
+ .map(this::serializeNamespaced)
|
||||
+ .collect(java.util.stream.Collectors.toList());
|
||||
+
|
||||
+ builder.put(CAN_DESTROY.BUKKIT, cerealDestroyable);
|
||||
+ }
|
||||
+ // Paper end
|
||||
final Map<String, Tag> internalTags = new HashMap<String, Tag>(this.unhandledTags);
|
||||
this.serializeInternal(internalTags);
|
||||
if (!internalTags.isEmpty()) {
|
||||
@@ -1516,6 +1657,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
CraftMetaArmorStand.SHOW_ARMS.NBT,
|
||||
CraftMetaArmorStand.SMALL.NBT,
|
||||
CraftMetaArmorStand.MARKER.NBT,
|
||||
+ CAN_DESTROY.NBT,
|
||||
+ CAN_PLACE_ON.NBT,
|
||||
// Paper end
|
||||
CraftMetaCompass.LODESTONE_DIMENSION.NBT,
|
||||
CraftMetaCompass.LODESTONE_POS.NBT,
|
||||
@@ -1545,4 +1688,141 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
}
|
||||
// Paper end
|
||||
|
||||
+ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
|
||||
+ @Override
|
||||
+ @SuppressWarnings("deprecation")
|
||||
+ public Set<Material> getCanDestroy() {
|
||||
+ return !hasDestroyableKeys() ? Collections.emptySet() : legacyGetMatsFromKeys(this.destroyableKeys);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ @SuppressWarnings("deprecation")
|
||||
+ public void setCanDestroy(Set<Material> canDestroy) {
|
||||
+ Preconditions.checkArgument(canDestroy != null, "Cannot replace with null set!");
|
||||
+ legacyClearAndReplaceKeys(this.destroyableKeys, canDestroy);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ @SuppressWarnings("deprecation")
|
||||
+ public Set<Material> getCanPlaceOn() {
|
||||
+ return !hasPlaceableKeys() ? Collections.emptySet() : legacyGetMatsFromKeys(this.placeableKeys);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ @SuppressWarnings("deprecation")
|
||||
+ public void setCanPlaceOn(Set<Material> canPlaceOn) {
|
||||
+ Preconditions.checkArgument(canPlaceOn != null, "Cannot replace with null set!");
|
||||
+ legacyClearAndReplaceKeys(this.placeableKeys, canPlaceOn);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Set<Namespaced> getDestroyableKeys() {
|
||||
+ return !hasDestroyableKeys() ? Collections.emptySet() : Sets.newHashSet(this.destroyableKeys);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setDestroyableKeys(Collection<Namespaced> canDestroy) {
|
||||
+ Preconditions.checkArgument(canDestroy != null, "Cannot replace with null collection!");
|
||||
+ Preconditions.checkArgument(ofAcceptableType(canDestroy), "Can only use NamespacedKey or NamespacedTag objects!");
|
||||
+ this.destroyableKeys.clear();
|
||||
+ this.destroyableKeys.addAll(canDestroy);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Set<Namespaced> getPlaceableKeys() {
|
||||
+ return !hasPlaceableKeys() ? Collections.emptySet() : Sets.newHashSet(this.placeableKeys);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setPlaceableKeys(Collection<Namespaced> canPlaceOn) {
|
||||
+ Preconditions.checkArgument(canPlaceOn != null, "Cannot replace with null collection!");
|
||||
+ Preconditions.checkArgument(ofAcceptableType(canPlaceOn), "Can only use NamespacedKey or NamespacedTag objects!");
|
||||
+ this.placeableKeys.clear();
|
||||
+ this.placeableKeys.addAll(canPlaceOn);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasPlaceableKeys() {
|
||||
+ return this.placeableKeys != null && !this.placeableKeys.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasDestroyableKeys() {
|
||||
+ return this.destroyableKeys != null && !this.destroyableKeys.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ @Deprecated
|
||||
+ private void legacyClearAndReplaceKeys(Collection<Namespaced> toUpdate, Collection<Material> beingSet) {
|
||||
+ if (beingSet.stream().anyMatch(Material::isLegacy)) {
|
||||
+ throw new IllegalArgumentException("Set must not contain any legacy materials!");
|
||||
+ }
|
||||
+
|
||||
+ toUpdate.clear();
|
||||
+ toUpdate.addAll(beingSet.stream().map(Material::getKey).collect(java.util.stream.Collectors.toSet()));
|
||||
+ }
|
||||
+
|
||||
+ @Deprecated
|
||||
+ private Set<Material> legacyGetMatsFromKeys(Collection<Namespaced> names) {
|
||||
+ Set<Material> mats = Sets.newHashSet();
|
||||
+ for (Namespaced key : names) {
|
||||
+ if (!(key instanceof org.bukkit.NamespacedKey)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ Material material = Material.matchMaterial(key.toString(), false);
|
||||
+ if (material != null) {
|
||||
+ mats.add(material);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return mats;
|
||||
+ }
|
||||
+
|
||||
+ private @Nullable Namespaced blockKeyFromString(String raw) {
|
||||
+ boolean isTag = !raw.isEmpty() && raw.codePointAt(0) == '#';
|
||||
+ com.mojang.datafixers.util.Either<net.minecraft.commands.arguments.blocks.BlockStateParser.BlockResult, net.minecraft.commands.arguments.blocks.BlockStateParser.TagResult> result;
|
||||
+ try {
|
||||
+ result = net.minecraft.commands.arguments.blocks.BlockStateParser.parseForTesting(net.minecraft.core.registries.BuiltInRegistries.BLOCK.asLookup(), raw, false);
|
||||
+ } catch (com.mojang.brigadier.exceptions.CommandSyntaxException e) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ net.minecraft.resources.ResourceLocation key = null;
|
||||
+ if (isTag && result.right().isPresent() && result.right().get().tag() instanceof net.minecraft.core.HolderSet.Named<net.minecraft.world.level.block.Block> namedSet) {
|
||||
+ key = namedSet.key().location();
|
||||
+ } else if (result.left().isPresent()) {
|
||||
+ key = net.minecraft.core.registries.BuiltInRegistries.BLOCK.getKey(result.left().get().blockState().getBlock());
|
||||
+ }
|
||||
+
|
||||
+ if (key == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ try {
|
||||
+ if (isTag) {
|
||||
+ return new NamespacedTag(key.getNamespace(), key.getPath());
|
||||
+
|
||||
+ }
|
||||
+ return CraftNamespacedKey.fromMinecraft(key);
|
||||
+ } catch (IllegalArgumentException ignored) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private @Nonnull String serializeNamespaced(Namespaced resource) {
|
||||
+ return resource.toString();
|
||||
+ }
|
||||
+
|
||||
+ // not a fan of this
|
||||
+ private boolean ofAcceptableType(Collection<Namespaced> namespacedResources) {
|
||||
+
|
||||
+ for (Namespaced resource : namespacedResources) {
|
||||
+ if (!(resource instanceof org.bukkit.NamespacedKey || resource instanceof com.destroystokyo.paper.NamespacedTag)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 10 Sep 2018 23:56:36 -0400
|
||||
Subject: [PATCH] Prevent various interactions from causing chunk loads
|
||||
|
||||
Co-authored-by: Shane Freeder <theboyetronic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
|
||||
index e3d070d46729c023d594699619a4b3f8658edbce..5580a396a56c6e0f364a5368985ee99b9e2be0a8 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
|
||||
@@ -126,7 +126,9 @@ public class RemoveBlockGoal extends MoveToBlockGoal {
|
||||
|
||||
@Nullable
|
||||
private BlockPos getPosWithBlock(BlockPos pos, BlockGetter world) {
|
||||
- if (world.getBlockState(pos).is(this.blockToRemove)) {
|
||||
+ net.minecraft.world.level.block.state.BlockState block = world.getBlockStateIfLoaded(pos); // Paper - Prevent AI rules from loading chunks
|
||||
+ if (block == null) return null; // Paper - Prevent AI rules from loading chunks
|
||||
+ if (block.is(this.blockToRemove)) { // Paper - Prevent AI rules from loading chunks
|
||||
return pos;
|
||||
} else {
|
||||
BlockPos[] ablockposition = new BlockPos[]{pos.below(), pos.west(), pos.east(), pos.north(), pos.south(), pos.below().below()};
|
||||
@@ -136,7 +138,8 @@ public class RemoveBlockGoal extends MoveToBlockGoal {
|
||||
for (int j = 0; j < i; ++j) {
|
||||
BlockPos blockposition1 = ablockposition1[j];
|
||||
|
||||
- if (world.getBlockState(blockposition1).is(this.blockToRemove)) {
|
||||
+ net.minecraft.world.level.block.state.BlockState block2 = world.getBlockStateIfLoaded(blockposition1); // Paper - Prevent AI rules from loading chunks
|
||||
+ if (block2 != null && block2.is(this.blockToRemove)) { // Paper - Prevent AI rules from loading chunks
|
||||
return blockposition1;
|
||||
}
|
||||
}
|
||||
@@ -147,7 +150,7 @@ public class RemoveBlockGoal extends MoveToBlockGoal {
|
||||
|
||||
@Override
|
||||
protected boolean isValidTarget(LevelReader world, BlockPos pos) {
|
||||
- ChunkAccess ichunkaccess = world.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()), ChunkStatus.FULL, false);
|
||||
+ ChunkAccess ichunkaccess = world.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4); // Paper - Prevent AI rules from loading chunks
|
||||
|
||||
return ichunkaccess == null ? false : ichunkaccess.getBlockState(pos).is(this.blockToRemove) && ichunkaccess.getBlockState(pos.above()).isAir() && ichunkaccess.getBlockState(pos.above(2)).isAir();
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
||||
index 13ba764d51f941c2b0d1d2af88ffd0c1fc3982c0..9637c26a3c381869f0a4dfe9189c0095387009b4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
||||
@@ -517,7 +517,8 @@ public class EnderMan extends Monster implements NeutralMob {
|
||||
int j = Mth.floor(this.enderman.getY() + randomsource.nextDouble() * 2.0D);
|
||||
int k = Mth.floor(this.enderman.getZ() - 1.0D + randomsource.nextDouble() * 2.0D);
|
||||
BlockPos blockposition = new BlockPos(i, j, k);
|
||||
- BlockState iblockdata = world.getBlockState(blockposition);
|
||||
+ BlockState iblockdata = world.getBlockStateIfLoaded(blockposition); // Paper - Prevent endermen from loading chunks
|
||||
+ if (iblockdata == null) return; // Paper - Prevent endermen from loading chunks
|
||||
BlockPos blockposition1 = blockposition.below();
|
||||
BlockState iblockdata1 = world.getBlockState(blockposition1);
|
||||
BlockState iblockdata2 = this.enderman.getCarriedBlock();
|
||||
@@ -561,7 +562,8 @@ public class EnderMan extends Monster implements NeutralMob {
|
||||
int j = Mth.floor(this.enderman.getY() + randomsource.nextDouble() * 3.0D);
|
||||
int k = Mth.floor(this.enderman.getZ() - 2.0D + randomsource.nextDouble() * 4.0D);
|
||||
BlockPos blockposition = new BlockPos(i, j, k);
|
||||
- BlockState iblockdata = world.getBlockState(blockposition);
|
||||
+ BlockState iblockdata = world.getBlockStateIfLoaded(blockposition); // Paper - Prevent endermen from loading chunks
|
||||
+ if (iblockdata == null) return; // Paper - Prevent endermen from loading chunks
|
||||
Vec3 vec3d = new Vec3((double) this.enderman.getBlockX() + 0.5D, (double) j + 0.5D, (double) this.enderman.getBlockZ() + 0.5D);
|
||||
Vec3 vec3d1 = new Vec3((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D);
|
||||
BlockHitResult movingobjectpositionblock = world.clip(new ClipContext(vec3d, vec3d1, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, this.enderman));
|
||||
diff --git a/src/main/java/net/minecraft/world/item/CompassItem.java b/src/main/java/net/minecraft/world/item/CompassItem.java
|
||||
index b8c6ac4c254787e285f97ad15bf10ddfd9cb294f..0f3621483a6ddcaeeb25eac51dbfaad41933579a 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/CompassItem.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/CompassItem.java
|
||||
@@ -77,7 +77,7 @@ public class CompassItem extends Item implements Vanishable {
|
||||
Optional<ResourceKey<Level>> optional = getLodestoneDimension(compoundTag);
|
||||
if (optional.isPresent() && optional.get() == world.dimension() && compoundTag.contains("LodestonePos")) {
|
||||
BlockPos blockPos = NbtUtils.readBlockPos(compoundTag.getCompound("LodestonePos"));
|
||||
- if (!world.isInWorldBounds(blockPos) || !((ServerLevel)world).getPoiManager().existsAtPosition(PoiTypes.LODESTONE, blockPos)) {
|
||||
+ if (!world.isInWorldBounds(blockPos) || (world.hasChunkAt(blockPos) && !((ServerLevel)world).getPoiManager().existsAtPosition(PoiTypes.LODESTONE, blockPos))) { // Paper - Prevent compass from loading chunks
|
||||
compoundTag.remove("LodestonePos");
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
index d6d8bbc98fc71997cb52521d59ebb59d727d3c22..c3760e0c8ac0b3ea200f4e1c237e250137a78caf 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
@@ -70,7 +70,15 @@ public interface BlockGetter extends LevelHeightAccessor {
|
||||
|
||||
// CraftBukkit start - moved block handling into separate method for use by Block#rayTrace
|
||||
default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition) {
|
||||
- BlockState iblockdata = this.getBlockState(blockposition);
|
||||
+ // Paper start - Prevent raytrace from loading chunks
|
||||
+ BlockState iblockdata = this.getBlockStateIfLoaded(blockposition);
|
||||
+ if (iblockdata == null) {
|
||||
+ // copied the last function parameter (listed below)
|
||||
+ Vec3 vec3d = raytrace1.getFrom().subtract(raytrace1.getTo());
|
||||
+
|
||||
+ return BlockHitResult.miss(raytrace1.getTo(), Direction.getNearest(vec3d.x, vec3d.y, vec3d.z), BlockPos.containing(raytrace1.getTo()));
|
||||
+ }
|
||||
+ // Paper end - Prevent raytrace from loading chunks
|
||||
FluidState fluid = this.getFluidState(blockposition);
|
||||
Vec3 vec3d = raytrace1.getFrom();
|
||||
Vec3 vec3d1 = raytrace1.getTo();
|
|
@ -1,32 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 12 Sep 2018 21:12:57 -0400
|
||||
Subject: [PATCH] Prevent mob spawning from loading/generating chunks
|
||||
|
||||
also prevents if out of world border bounds
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
index 352d230b365c512a4b9831265d3a57825f80fbfd..d5ada3301429e7fec0d157d7a33d4937e0f82fbb 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -170,9 +170,9 @@ public final class NaturalSpawner {
|
||||
StructureManager structuremanager = world.structureManager();
|
||||
ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator();
|
||||
int i = pos.getY();
|
||||
- BlockState iblockdata = chunk.getBlockState(pos);
|
||||
+ BlockState iblockdata = world.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn
|
||||
|
||||
- if (!iblockdata.isRedstoneConductor(chunk, pos)) {
|
||||
+ if (iblockdata != null && !iblockdata.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn
|
||||
BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
@@ -201,7 +201,7 @@ public final class NaturalSpawner {
|
||||
if (entityhuman != null) {
|
||||
double d2 = entityhuman.distanceToSqr(d0, (double) i, d1);
|
||||
|
||||
- if (NaturalSpawner.isRightDistanceToPlayerAndSpawnPoint(world, chunk, blockposition_mutableblockposition, d2)) {
|
||||
+ if (world.isLoadedAndInBounds(blockposition_mutableblockposition) && NaturalSpawner.isRightDistanceToPlayerAndSpawnPoint(world, chunk, blockposition_mutableblockposition, d2)) { // Paper - don't load chunks for mob spawn
|
||||
if (biomesettingsmobs_c == null) {
|
||||
Optional<MobSpawnSettings.SpawnerData> optional = NaturalSpawner.getRandomSpawnMobAt(world, structuremanager, chunkgenerator, group, world.random, blockposition_mutableblockposition);
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tassu <git@tassu.me>
|
||||
Date: Thu, 13 Sep 2018 08:45:21 +0300
|
||||
Subject: [PATCH] Implement furnace cook speed multiplier API
|
||||
|
||||
Fixed an issue where a furnace's cook-speed multiplier rounds down
|
||||
to the nearest Integer when updating its current cook time.
|
||||
|
||||
Co-authored-by: Eric Su <ericsu@alumni.usc.edu>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
||||
index 7a13042631bea761952490cfd14dc20147405161..9801b777bc6ab7de91d82b29a142459292ee8605 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
||||
@@ -78,11 +78,13 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
|
||||
protected NonNullList<ItemStack> items;
|
||||
public int litTime;
|
||||
int litDuration;
|
||||
+ public double cookSpeedMultiplier = 1.0; // Paper - cook speed multiplier API
|
||||
public int cookingProgress;
|
||||
public int cookingTotalTime;
|
||||
protected final ContainerData dataAccess;
|
||||
public final Object2IntOpenHashMap<ResourceLocation> recipesUsed;
|
||||
private final RecipeManager.CachedCheck<Container, ? extends AbstractCookingRecipe> quickCheck;
|
||||
+ public final RecipeType<? extends AbstractCookingRecipe> recipeType; // Paper - cook speed multiplier API
|
||||
|
||||
protected AbstractFurnaceBlockEntity(BlockEntityType<?> blockEntityType, BlockPos pos, BlockState state, RecipeType<? extends AbstractCookingRecipe> recipeType) {
|
||||
super(blockEntityType, pos, state);
|
||||
@@ -129,6 +131,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
|
||||
};
|
||||
this.recipesUsed = new Object2IntOpenHashMap();
|
||||
this.quickCheck = RecipeManager.createCheck((RecipeType<AbstractCookingRecipe>) recipeType); // CraftBukkit - decompile error // Eclipse fail
|
||||
+ this.recipeType = recipeType; // Paper - cook speed multiplier API
|
||||
}
|
||||
|
||||
public static Map<Item, Integer> getFuel() {
|
||||
@@ -281,6 +284,11 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
|
||||
this.recipesUsed.put(new ResourceLocation(s), nbttagcompound1.getInt(s));
|
||||
}
|
||||
|
||||
+ // Paper start - cook speed multiplier API
|
||||
+ if (nbt.contains("Paper.CookSpeedMultiplier")) {
|
||||
+ this.cookSpeedMultiplier = nbt.getDouble("Paper.CookSpeedMultiplier");
|
||||
+ }
|
||||
+ // Paper end - cook speed multiplier API
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -289,6 +297,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
|
||||
nbt.putShort("BurnTime", (short) this.litTime);
|
||||
nbt.putShort("CookTime", (short) this.cookingProgress);
|
||||
nbt.putShort("CookTimeTotal", (short) this.cookingTotalTime);
|
||||
+ nbt.putDouble("Paper.CookSpeedMultiplier", this.cookSpeedMultiplier); // Paper - cook speed multiplier API
|
||||
ContainerHelper.saveAllItems(nbt, this.items);
|
||||
CompoundTag nbttagcompound1 = new CompoundTag();
|
||||
|
||||
@@ -360,7 +369,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
|
||||
CraftItemStack source = CraftItemStack.asCraftMirror(blockEntity.items.get(0));
|
||||
CookingRecipe<?> recipe = (CookingRecipe<?>) recipeholder.toBukkitRecipe();
|
||||
|
||||
- FurnaceStartSmeltEvent event = new FurnaceStartSmeltEvent(CraftBlock.at(world, pos), source, recipe);
|
||||
+ FurnaceStartSmeltEvent event = new FurnaceStartSmeltEvent(CraftBlock.at(world, pos), source, recipe, AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity.recipeType, blockEntity, blockEntity.cookSpeedMultiplier)); // Paper - cook speed multiplier API
|
||||
world.getCraftServer().getPluginManager().callEvent(event);
|
||||
|
||||
blockEntity.cookingTotalTime = event.getTotalCookTime();
|
||||
@@ -368,9 +377,9 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
|
||||
// CraftBukkit end
|
||||
|
||||
++blockEntity.cookingProgress;
|
||||
- if (blockEntity.cookingProgress == blockEntity.cookingTotalTime) {
|
||||
+ if (blockEntity.cookingProgress >= blockEntity.cookingTotalTime) { // Paper - cook speed multiplier API
|
||||
blockEntity.cookingProgress = 0;
|
||||
- blockEntity.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity);
|
||||
+ blockEntity.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity.recipeType, blockEntity, blockEntity.cookSpeedMultiplier); // Paper - cook speed multiplier API
|
||||
if (AbstractFurnaceBlockEntity.burn(blockEntity.level, blockEntity.worldPosition, world.registryAccess(), recipeholder, blockEntity.items, i)) { // CraftBukkit
|
||||
blockEntity.setRecipeUsed(recipeholder);
|
||||
}
|
||||
@@ -470,11 +479,12 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
|
||||
}
|
||||
}
|
||||
|
||||
- private static int getTotalCookTime(Level world, AbstractFurnaceBlockEntity furnace) {
|
||||
- if (world == null) return 200; // CraftBukkit - SPIGOT-4302
|
||||
- return (Integer) furnace.quickCheck.getRecipeFor(furnace, world).map((recipeholder) -> {
|
||||
- return ((AbstractCookingRecipe) recipeholder.value()).getCookingTime();
|
||||
- }).orElse(200);
|
||||
+ // Paper start - cook speed multiplier API
|
||||
+ public static int getTotalCookTime(@Nullable Level world, RecipeType<? extends AbstractCookingRecipe> recipeType, AbstractFurnaceBlockEntity furnace, double cookSpeedMultiplier) {
|
||||
+ /* Scale the recipe's cooking time to the current cookSpeedMultiplier */
|
||||
+ int cookTime = world != null ? furnace.quickCheck.getRecipeFor(furnace, world).map(holder -> holder.value().getCookingTime()).orElse(200) : (net.minecraft.server.MinecraftServer.getServer().getRecipeManager().getRecipeFor(recipeType, furnace, world /* passing a null level here is safe. world is only used for map extending recipes which won't happen here */).map(holder -> holder.value().getCookingTime()).orElse(200));
|
||||
+ return (int) Math.ceil (cookTime / cookSpeedMultiplier);
|
||||
+ // Paper end - cook speed multiplier API
|
||||
}
|
||||
|
||||
public static boolean isFuel(ItemStack stack) {
|
||||
@@ -544,7 +554,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
|
||||
}
|
||||
|
||||
if (slot == 0 && !flag) {
|
||||
- this.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.level, this);
|
||||
+ this.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.level, this.recipeType, this, this.cookSpeedMultiplier); // Paper - cook speed multiplier API
|
||||
this.cookingProgress = 0;
|
||||
this.setChanged();
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java
|
||||
index 2f25a502c5c7223101f2d8c125977e2c614cd899..f98cf44e929d326037e1089dafe4f82c6f6d8647 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java
|
||||
@@ -85,4 +85,20 @@ public abstract class CraftFurnace<T extends AbstractFurnaceBlockEntity> extends
|
||||
|
||||
@Override
|
||||
public abstract CraftFurnace<T> copy();
|
||||
+
|
||||
+ // Paper start - cook speed multiplier API
|
||||
+ @Override
|
||||
+ public double getCookSpeedMultiplier() {
|
||||
+ return this.getSnapshot().cookSpeedMultiplier;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setCookSpeedMultiplier(double multiplier) {
|
||||
+ com.google.common.base.Preconditions.checkArgument(multiplier >= 0, "Furnace speed multiplier cannot be negative");
|
||||
+ com.google.common.base.Preconditions.checkArgument(multiplier <= 200, "Furnace speed multiplier cannot more than 200");
|
||||
+ T snapshot = this.getSnapshot();
|
||||
+ snapshot.cookSpeedMultiplier = multiplier;
|
||||
+ snapshot.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.isPlaced() ? this.world.getHandle() : null, snapshot.recipeType, snapshot, snapshot.cookSpeedMultiplier); // Update the snapshot's current total cook time to scale with the newly set multiplier
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 23 Sep 2018 20:59:53 -0500
|
||||
Subject: [PATCH] Honor EntityAgeable.ageLock
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/AgeableMob.java b/src/main/java/net/minecraft/world/entity/AgeableMob.java
|
||||
index be5e603d505566feac61cc7e591d35ce483a92df..8dcdc664470fcac00c203b9499ea0a45df7d86ef 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/AgeableMob.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/AgeableMob.java
|
||||
@@ -85,6 +85,7 @@ public abstract class AgeableMob extends PathfinderMob {
|
||||
}
|
||||
|
||||
public void ageUp(int age, boolean overGrow) {
|
||||
+ if (this.ageLocked) return; // Paper - Honor ageLock
|
||||
int j = this.getAge();
|
||||
int k = j;
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
|
||||
index 70400c9d8835046523c55e3777a2f02da6168dcb..b0c57922fa6160772ba1aaf61c0e97c03a0e6e8c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
|
||||
@@ -303,6 +303,7 @@ public class BeehiveBlockEntity extends BlockEntity {
|
||||
}
|
||||
|
||||
private static void setBeeReleaseData(int ticks, Bee bee) {
|
||||
+ if (!bee.ageLocked) { // Paper - Honor ageLock
|
||||
int j = bee.getAge();
|
||||
|
||||
if (j < 0) {
|
||||
@@ -310,6 +311,7 @@ public class BeehiveBlockEntity extends BlockEntity {
|
||||
} else if (j > 0) {
|
||||
bee.setAge(Math.max(0, j - ticks));
|
||||
}
|
||||
+ } // Paper - Honor ageLock
|
||||
|
||||
bee.setInLoveTime(Math.max(0, bee.getInLoveTime() - ticks));
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Tue, 2 Oct 2018 09:57:50 +0100
|
||||
Subject: [PATCH] Configurable connection throttle kick message
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||
index 3dfec4462d85f3223071b4e78465587db6185f0d..08a7461a92ae84cac69e4bb57a099d1f35ff1c1a 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||
@@ -51,7 +51,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL
|
||||
synchronized (ServerHandshakePacketListenerImpl.throttleTracker) {
|
||||
if (ServerHandshakePacketListenerImpl.throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - ServerHandshakePacketListenerImpl.throttleTracker.get(address) < connectionThrottle) {
|
||||
ServerHandshakePacketListenerImpl.throttleTracker.put(address, currentTime);
|
||||
- MutableComponent chatmessage = Component.literal("Connection throttled! Please wait before reconnecting.");
|
||||
+ Component chatmessage = io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.connectionThrottle); // Paper - Configurable connection throttle kick message
|
||||
this.connection.send(new ClientboundLoginDisconnectPacket(chatmessage));
|
||||
this.connection.disconnect(chatmessage);
|
||||
return;
|
|
@ -1,75 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 10 Sep 2018 23:36:16 -0400
|
||||
Subject: [PATCH] Prevent chunk loading from Fluid Flowing
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
|
||||
index 818c83934a97c4b2ad4db69f4b0fcf0a500ea918..0aeb9faa1ce22359361741a591aa3d465d955970 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
|
||||
@@ -176,7 +176,8 @@ public abstract class FlowingFluid extends Fluid {
|
||||
Direction enumdirection = (Direction) entry.getKey();
|
||||
FluidState fluid1 = (FluidState) entry.getValue();
|
||||
BlockPos blockposition1 = pos.relative(enumdirection);
|
||||
- BlockState iblockdata1 = world.getBlockState(blockposition1);
|
||||
+ BlockState iblockdata1 = world.getBlockStateIfLoaded(blockposition1); // Paper - Prevent chunk loading from fluid flowing
|
||||
+ if (iblockdata1 == null) continue; // Paper - Prevent chunk loading from fluid flowing
|
||||
|
||||
if (this.canSpreadTo(world, pos, blockState, enumdirection, blockposition1, iblockdata1, world.getFluidState(blockposition1), fluid1.getType())) {
|
||||
// CraftBukkit start
|
||||
@@ -203,7 +204,8 @@ public abstract class FlowingFluid extends Fluid {
|
||||
while (iterator.hasNext()) {
|
||||
Direction enumdirection = (Direction) iterator.next();
|
||||
BlockPos blockposition1 = pos.relative(enumdirection);
|
||||
- BlockState iblockdata1 = world.getBlockState(blockposition1);
|
||||
+ BlockState iblockdata1 = world.getBlockStateIfLoaded(blockposition1); // Paper - Prevent chunk loading from fluid flowing
|
||||
+ if (iblockdata1 == null) continue; // Paper - Prevent chunk loading from fluid flowing
|
||||
FluidState fluid = iblockdata1.getFluidState();
|
||||
|
||||
if (fluid.getType().isSame(this) && this.canPassThroughWall(enumdirection, world, pos, state, blockposition1, iblockdata1)) {
|
||||
@@ -320,11 +322,18 @@ public abstract class FlowingFluid extends Fluid {
|
||||
if (enumdirection1 != direction) {
|
||||
BlockPos blockposition2 = pos.relative(enumdirection1);
|
||||
short short0 = FlowingFluid.getCacheKey(fromPos, blockposition2);
|
||||
- Pair<BlockState, FluidState> pair = (Pair) stateCache.computeIfAbsent(short0, (short1) -> {
|
||||
- BlockState iblockdata1 = world.getBlockState(blockposition2);
|
||||
+ // Paper start - Prevent chunk loading from fluid flowing
|
||||
+ Pair<BlockState, FluidState> pair = stateCache.get(short0);
|
||||
+ if (pair == null) {
|
||||
+ BlockState iblockdatax = world.getBlockStateIfLoaded(blockposition2);
|
||||
+ if (iblockdatax == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
|
||||
- return Pair.of(iblockdata1, iblockdata1.getFluidState());
|
||||
- });
|
||||
+ pair = Pair.of(iblockdatax, iblockdatax.getFluidState());
|
||||
+ stateCache.put(short0, pair);
|
||||
+ }
|
||||
+ // Paper end - Prevent chunk loading from fluid flowing
|
||||
BlockState iblockdata1 = (BlockState) pair.getFirst();
|
||||
FluidState fluid = (FluidState) pair.getSecond();
|
||||
|
||||
@@ -396,11 +405,16 @@ public abstract class FlowingFluid extends Fluid {
|
||||
Direction enumdirection = (Direction) iterator.next();
|
||||
BlockPos blockposition1 = pos.relative(enumdirection);
|
||||
short short0 = FlowingFluid.getCacheKey(pos, blockposition1);
|
||||
- Pair<BlockState, FluidState> pair = (Pair) short2objectmap.computeIfAbsent(short0, (short1) -> {
|
||||
- BlockState iblockdata1 = world.getBlockState(blockposition1);
|
||||
-
|
||||
- return Pair.of(iblockdata1, iblockdata1.getFluidState());
|
||||
- });
|
||||
+ // Paper start - Prevent chunk loading from fluid flowing
|
||||
+ Pair pair = (Pair) short2objectmap.get(short0);
|
||||
+ if (pair == null) {
|
||||
+ BlockState iblockdatax = world.getBlockStateIfLoaded(blockposition1);
|
||||
+ if (iblockdatax == null) continue;
|
||||
+
|
||||
+ pair = Pair.of(iblockdatax, iblockdatax.getFluidState());
|
||||
+ short2objectmap.put(short0, pair);
|
||||
+ }
|
||||
+ // Paper end - Prevent chunk loading from fluid flowing
|
||||
BlockState iblockdata1 = (BlockState) pair.getFirst();
|
||||
FluidState fluid = (FluidState) pair.getSecond();
|
||||
FluidState fluid1 = this.getNewLiquid(world, blockposition1, iblockdata1);
|
|
@ -1,27 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Phoenix616 <mail@moep.tv>
|
||||
Date: Tue, 18 Sep 2018 23:53:23 +0100
|
||||
Subject: [PATCH] PreSpawnerSpawnEvent
|
||||
|
||||
This adds a separate event before an entity is spawned by a spawner
|
||||
which contains the location of the spawner too similarly to how the
|
||||
SpawnerSpawnEvent gets called instead of the CreatureSpawnEvent for
|
||||
spawners.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
index 0166c5ff685490cbf67a9d26f48cb1a0be754488..cae8c508972d771ad96228ace8a7e6cbc34d5489 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -131,10 +131,10 @@ public abstract class BaseSpawner {
|
||||
continue;
|
||||
}
|
||||
// Paper start - PreCreatureSpawnEvent
|
||||
- com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
|
||||
+ com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent event = new com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent(
|
||||
io.papermc.paper.util.MCUtil.toLocation(world, d0, d1, d2),
|
||||
org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(optional.get()),
|
||||
- org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER
|
||||
+ io.papermc.paper.util.MCUtil.toLocation(world, pos)
|
||||
);
|
||||
if (!event.callEvent()) {
|
||||
flag = true;
|
|
@ -1,108 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sat, 22 Sep 2018 00:33:08 -0500
|
||||
Subject: [PATCH] Add LivingEntity#getTargetEntity
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 4b3d1c8452bd759db6fc8d3d9fcf98e2a8d25084..1a328de32b69b69814e11a5b6bc55bfccf408d6b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -115,6 +115,7 @@ import net.minecraft.world.level.storage.loot.LootTable;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
+import net.minecraft.world.phys.EntityHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.scores.PlayerTeam;
|
||||
@@ -3911,6 +3912,38 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
return this.level().clip(raytrace);
|
||||
}
|
||||
|
||||
+ public @Nullable EntityHitResult getTargetEntity(int maxDistance) {
|
||||
+ if (maxDistance < 1 || maxDistance > 120) {
|
||||
+ throw new IllegalArgumentException("maxDistance must be between 1-120");
|
||||
+ }
|
||||
+
|
||||
+ Vec3 start = this.getEyePosition(1.0F);
|
||||
+ Vec3 direction = this.getLookAngle();
|
||||
+ Vec3 end = start.add(direction.x * maxDistance, direction.y * maxDistance, direction.z * maxDistance);
|
||||
+
|
||||
+ List<Entity> entityList = this.level().getEntities(this, getBoundingBox().expandTowards(direction.x * maxDistance, direction.y * maxDistance, direction.z * maxDistance).inflate(1.0D, 1.0D, 1.0D), EntitySelector.NO_SPECTATORS.and(Entity::isPickable));
|
||||
+
|
||||
+ double distance = 0.0D;
|
||||
+ EntityHitResult result = null;
|
||||
+
|
||||
+ for (Entity entity : entityList) {
|
||||
+ final double inflationAmount = (double) entity.getPickRadius();
|
||||
+ AABB aabb = entity.getBoundingBox().inflate(inflationAmount, inflationAmount, inflationAmount);
|
||||
+ Optional<Vec3> rayTraceResult = aabb.clip(start, end);
|
||||
+
|
||||
+ if (rayTraceResult.isPresent()) {
|
||||
+ Vec3 rayTrace = rayTraceResult.get();
|
||||
+ double distanceTo = start.distanceToSqr(rayTrace);
|
||||
+ if (distanceTo < distance || distance == 0.0D) {
|
||||
+ result = new EntityHitResult(entity, rayTrace);
|
||||
+ distance = distanceTo;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return result;
|
||||
+ }
|
||||
+
|
||||
public int shieldBlockingDelay = this.level().paperConfig().misc.shieldBlockingDelay;
|
||||
|
||||
public int getShieldBlockingDelay() {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
index 8139ea88988e2e3551258b6686873753353ab9f8..5def5bccd8fce86ce015567e65fefae329819c18 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.bukkit.craftbukkit.entity;
|
||||
|
||||
+import com.destroystokyo.paper.entity.TargetEntityInfo;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.ArrayList;
|
||||
@@ -226,6 +227,39 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
+
|
||||
+ public Entity getTargetEntity(int maxDistance, boolean ignoreBlocks) {
|
||||
+ net.minecraft.world.phys.EntityHitResult rayTrace = rayTraceEntity(maxDistance, ignoreBlocks);
|
||||
+ return rayTrace == null ? null : rayTrace.getEntity().getBukkitEntity();
|
||||
+ }
|
||||
+
|
||||
+ public TargetEntityInfo getTargetEntityInfo(int maxDistance, boolean ignoreBlocks) {
|
||||
+ net.minecraft.world.phys.EntityHitResult rayTrace = rayTraceEntity(maxDistance, ignoreBlocks);
|
||||
+ return rayTrace == null ? null : new TargetEntityInfo(rayTrace.getEntity().getBukkitEntity(), new org.bukkit.util.Vector(rayTrace.getLocation().x, rayTrace.getLocation().y, rayTrace.getLocation().z));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public RayTraceResult rayTraceEntities(int maxDistance, boolean ignoreBlocks) {
|
||||
+ net.minecraft.world.phys.EntityHitResult rayTrace = this.rayTraceEntity(maxDistance, ignoreBlocks);
|
||||
+ return rayTrace == null ? null : new org.bukkit.util.RayTraceResult(org.bukkit.craftbukkit.util.CraftVector.toBukkit(rayTrace.getLocation()), rayTrace.getEntity().getBukkitEntity());
|
||||
+ }
|
||||
+
|
||||
+ public net.minecraft.world.phys.EntityHitResult rayTraceEntity(int maxDistance, boolean ignoreBlocks) {
|
||||
+ net.minecraft.world.phys.EntityHitResult rayTrace = getHandle().getTargetEntity(maxDistance);
|
||||
+ if (rayTrace == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ if (!ignoreBlocks) {
|
||||
+ net.minecraft.world.phys.HitResult rayTraceBlocks = getHandle().getRayTrace(maxDistance, net.minecraft.world.level.ClipContext.Fluid.NONE);
|
||||
+ if (rayTraceBlocks != null) {
|
||||
+ net.minecraft.world.phys.Vec3 eye = getHandle().getEyePosition(1.0F);
|
||||
+ if (eye.distanceToSqr(rayTraceBlocks.getLocation()) <= eye.distanceToSqr(rayTrace.getLocation())) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return rayTrace;
|
||||
+ }
|
||||
// Paper end
|
||||
|
||||
@Override
|
|
@ -1,42 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 7 Oct 2018 00:54:21 -0500
|
||||
Subject: [PATCH] Add sun related API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.Mob isSunBurnTick()Z
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index fd04c5c7e08b54de65ffaf58385dcc05ef22bba0..18db1aa374495a214807c5eb3ccc0213fc7c6a47 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -731,6 +731,13 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean isDayTime() {
|
||||
+ return getHandle().isDay();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public long getGameTime() {
|
||||
return this.world.levelData.getGameTime();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
|
||||
index 018884ced888fcd03d2fb17b3620f8e6125e67da..0ad9885f939bcb50026d50ed78b970a44772ceb8 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
|
||||
@@ -93,4 +93,11 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob {
|
||||
public long getSeed() {
|
||||
return this.getHandle().lootTableSeed;
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean isInDaylight() {
|
||||
+ return getHandle().isSunBurnTick();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Sat, 22 Sep 2018 15:56:59 -0400
|
||||
Subject: [PATCH] Catch JsonParseException in entity and block entity names
|
||||
|
||||
As a result, data that no longer parses correctly will not crash the server
|
||||
instead just logging the exception and continuing (and in most cases should
|
||||
fix the data)
|
||||
|
||||
Player data is fixed pretty much immediately but some block data (like
|
||||
Shulkers) may need to be changed in order for it to re-save properly
|
||||
|
||||
No more crashing though.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java
|
||||
index c57e8b6458800fe9bb27050eecc42bd3e5cf5a15..83c7b47e189a934345f6548df9b101cc8c501910 100644
|
||||
--- a/src/main/java/io/papermc/paper/util/MCUtil.java
|
||||
+++ b/src/main/java/io/papermc/paper/util/MCUtil.java
|
||||
@@ -558,4 +558,19 @@ public final class MCUtil {
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
+
|
||||
+ @Nullable
|
||||
+ public static net.minecraft.network.chat.Component getBaseComponentFromNbt(String key, net.minecraft.nbt.CompoundTag compound) {
|
||||
+ if (!compound.contains(key)) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ String string = compound.getString(key);
|
||||
+ try {
|
||||
+ return net.minecraft.network.chat.Component.Serializer.fromJson(string);
|
||||
+ } catch (com.google.gson.JsonParseException e) {
|
||||
+ org.bukkit.Bukkit.getLogger().warning("Unable to parse " + key + " from " + compound +": " + e.getMessage());
|
||||
+ }
|
||||
+
|
||||
+ return null;
|
||||
+ }
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
|
||||
index 129f0e6108366dbba1bafb04e01e5e5e6489f577..ac0aeb53176069d0835b6b08c8d871edae846763 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
|
||||
@@ -72,7 +72,7 @@ public abstract class BaseCommandBlock implements CommandSource {
|
||||
this.command = nbt.getString("Command");
|
||||
this.successCount = nbt.getInt("SuccessCount");
|
||||
if (nbt.contains("CustomName", 8)) {
|
||||
- this.setName(Component.Serializer.fromJson(nbt.getString("CustomName")));
|
||||
+ this.setName(io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt)); // Paper - Catch ParseException
|
||||
}
|
||||
|
||||
if (nbt.contains("TrackOutput", 1)) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java
|
||||
index c6194fa1611412ac119fed493d5eab5a160e593d..d89037a83ae1b6d2afa6a589c1b8098cbedf3d2d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java
|
||||
@@ -98,7 +98,7 @@ public class BannerBlockEntity extends BlockEntity implements Nameable {
|
||||
public void load(CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
if (nbt.contains("CustomName", 8)) {
|
||||
- this.name = Component.Serializer.fromJson(nbt.getString("CustomName"));
|
||||
+ this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException
|
||||
}
|
||||
|
||||
this.itemPatterns = nbt.getList("Patterns", 10);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
|
||||
index 25764076fec05b1362aa9b9b608e03bd39817d90..fce3a45d09a93ca68a3d49f2e666afa4c860d042 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
|
||||
@@ -31,7 +31,7 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co
|
||||
super.load(nbt);
|
||||
this.lockKey = LockCode.fromTag(nbt);
|
||||
if (nbt.contains("CustomName", 8)) {
|
||||
- this.name = Component.Serializer.fromJson(nbt.getString("CustomName"));
|
||||
+ this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException
|
||||
}
|
||||
|
||||
}
|
||||
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 25ec3ab534872500a2eb51cd44062e2754c404bb..a1097950766ad31393340b423ea3f98a1f555368 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
|
||||
@@ -389,7 +389,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name
|
||||
this.secondaryPower = BeaconBlockEntity.loadEffect(nbt, "secondary_effect");
|
||||
this.levels = nbt.getInt("Levels"); // CraftBukkit - SPIGOT-5053, use where available
|
||||
if (nbt.contains("CustomName", 8)) {
|
||||
- this.name = Component.Serializer.fromJson(nbt.getString("CustomName"));
|
||||
+ this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException
|
||||
}
|
||||
|
||||
this.lockKey = LockCode.fromTag(nbt);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java
|
||||
index 00de0cc29775a219a763431fd4d54b2fa2585477..4d1a895f3749bdcb132de199e81a9d93330c0ee6 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java
|
||||
@@ -41,7 +41,7 @@ public class EnchantmentTableBlockEntity extends BlockEntity implements Nameable
|
||||
public void load(CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
if (nbt.contains("CustomName", 8)) {
|
||||
- this.name = Component.Serializer.fromJson(nbt.getString("CustomName"));
|
||||
+ this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sat, 29 Sep 2018 16:08:23 -0500
|
||||
Subject: [PATCH] Turtle API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.animal.Turtle getHomePos()Lnet/minecraft/core/BlockPos;
|
||||
public net.minecraft.world.entity.animal.Turtle setHasEgg(Z)V
|
||||
public net.minecraft.world.entity.animal.Turtle isGoingHome()Z
|
||||
public net.minecraft.world.entity.animal.Turtle setGoingHome(Z)V
|
||||
public net.minecraft.world.entity.animal.Turtle isTravelling()Z
|
||||
public net.minecraft.world.entity.animal.Turtle setTravelling(Z)V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
index 11322066522a3268063bad7267ef4dd4f06d983e..cfc0cee09dfd522409bb5853fc96528bd0137475 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
@@ -489,14 +489,17 @@ public class Turtle extends Animal {
|
||||
|
||||
if (!this.turtle.isInWater() && this.isReachedTarget()) {
|
||||
if (this.turtle.layEggCounter < 1) {
|
||||
- this.turtle.setLayingEgg(true);
|
||||
+ this.turtle.setLayingEgg(new com.destroystokyo.paper.event.entity.TurtleStartDiggingEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(this.turtle.level(), this.blockPos)).callEvent()); // Paper - Turtle API
|
||||
} else if (this.turtle.layEggCounter > this.adjustedTickDelay(200)) {
|
||||
Level world = this.turtle.level();
|
||||
|
||||
- if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.turtle, this.blockPos.above(), (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1))) { // CraftBukkit
|
||||
+ // Paper start - Turtle API
|
||||
+ int eggCount = this.turtle.random.nextInt(4) + 1;
|
||||
+ com.destroystokyo.paper.event.entity.TurtleLayEggEvent layEggEvent = new com.destroystokyo.paper.event.entity.TurtleLayEggEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(this.turtle.level(), this.blockPos.above()), eggCount);
|
||||
+ if (layEggEvent.callEvent() && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.turtle, this.blockPos.above(), Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount()))) {
|
||||
world.playSound((Player) null, blockposition, SoundEvents.TURTLE_LAY_EGG, SoundSource.BLOCKS, 0.3F, 0.9F + world.random.nextFloat() * 0.2F);
|
||||
BlockPos blockposition1 = this.blockPos.above();
|
||||
- BlockState iblockdata = (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1);
|
||||
+ BlockState iblockdata = (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount()); // Paper
|
||||
|
||||
world.setBlock(blockposition1, iblockdata, 3);
|
||||
world.gameEvent(GameEvent.BLOCK_PLACE, blockposition1, GameEvent.Context.of(this.turtle, iblockdata));
|
||||
@@ -566,7 +569,7 @@ public class Turtle extends Animal {
|
||||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
- return this.turtle.isBaby() ? false : (this.turtle.hasEgg() ? true : (this.turtle.getRandom().nextInt(reducedTickDelay(700)) != 0 ? false : !this.turtle.getHomePos().closerToCenterThan(this.turtle.position(), 64.0D)));
|
||||
+ return this.turtle.isBaby() ? false : (this.turtle.hasEgg() ? true : (this.turtle.getRandom().nextInt(reducedTickDelay(700)) != 0 ? false : !this.turtle.getHomePos().closerToCenterThan(this.turtle.position(), 64.0D))) && new com.destroystokyo.paper.event.entity.TurtleGoHomeEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity()).callEvent(); // Paper - Turtle API
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTurtle.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTurtle.java
|
||||
index fac0317ff945db991e761ac8973f0d3d41ade26b..d44e6f4bb682d18c1497eee9fb2802f2bda6e840 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTurtle.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTurtle.java
|
||||
@@ -28,4 +28,31 @@ public class CraftTurtle extends CraftAnimals implements Turtle {
|
||||
public boolean isLayingEgg() {
|
||||
return this.getHandle().isLayingEgg();
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public org.bukkit.Location getHome() {
|
||||
+ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level(), this.getHandle().getHomePos());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setHome(org.bukkit.Location location) {
|
||||
+ this.getHandle().setHomePos(io.papermc.paper.util.MCUtil.toBlockPosition(location));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isGoingHome() {
|
||||
+ return this.getHandle().isGoingHome();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isDigging() {
|
||||
+ return this.getHandle().isLayingEgg();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setHasEgg(boolean hasEgg) {
|
||||
+ this.getHandle().setHasEgg(hasEgg);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Caleb Bassham <caleb.bassham@gmail.com>
|
||||
Date: Fri, 28 Sep 2018 02:32:19 -0500
|
||||
Subject: [PATCH] Call player spectator target events and improve
|
||||
implementation
|
||||
|
||||
Use a proper teleport for teleporting to entities in different
|
||||
worlds.
|
||||
|
||||
Implementation improvements authored by Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Validate that the target entity is valid and deny spectate
|
||||
requests from frozen players.
|
||||
|
||||
Also, make sure the entity is spawned to the client before
|
||||
sending the camera packet. If the entity isn't spawned clientside
|
||||
when it receives the camera packet, then the client will not
|
||||
spectate the target entity.
|
||||
|
||||
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 054057482d191d8e77bf4d179d51e32b5d9ca16e..19c3eb566552f7994ae5e60dc869c94e08590fbb 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -2041,6 +2041,21 @@ public class ServerPlayer extends Player {
|
||||
|
||||
this.camera = (Entity) (entity == null ? this : entity);
|
||||
if (entity1 != this.camera) {
|
||||
+ // Paper start - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity
|
||||
+ if (this.camera == this) {
|
||||
+ com.destroystokyo.paper.event.player.PlayerStopSpectatingEntityEvent playerStopSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStopSpectatingEntityEvent(this.getBukkitEntity(), entity1.getBukkitEntity());
|
||||
+ if (!playerStopSpectatingEntityEvent.callEvent()) {
|
||||
+ this.camera = entity1; // rollback camera entity again
|
||||
+ return;
|
||||
+ }
|
||||
+ } else {
|
||||
+ com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent playerStartSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent(this.getBukkitEntity(), entity1.getBukkitEntity(), entity.getBukkitEntity());
|
||||
+ if (!playerStartSpectatingEntityEvent.callEvent()) {
|
||||
+ this.camera = entity1; // rollback camera entity again
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity
|
||||
Level world = this.camera.level();
|
||||
|
||||
if (world instanceof ServerLevel) {
|
|
@ -1,101 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Fri, 12 Oct 2018 14:10:46 -0500
|
||||
Subject: [PATCH] Add more Witch API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.monster.Witch usingTime
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Witch.java b/src/main/java/net/minecraft/world/entity/monster/Witch.java
|
||||
index 25a1edf64602a13c07779e58b167a8471019588e..f9ffc5f4cbfdcf5c7351a883d2e5c26492175283 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Witch.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java
|
||||
@@ -160,21 +160,7 @@ public class Witch extends Raider implements RangedAttackMob {
|
||||
}
|
||||
|
||||
if (potionregistry != null) {
|
||||
- // Paper start
|
||||
- ItemStack potion = PotionUtils.setPotion(new ItemStack(Items.POTION), potionregistry);
|
||||
- potion = org.bukkit.craftbukkit.event.CraftEventFactory.handleWitchReadyPotionEvent(this, potion);
|
||||
- this.setItemSlot(EquipmentSlot.MAINHAND, potion);
|
||||
- // Paper end
|
||||
- this.usingTime = this.getMainHandItem().getUseDuration();
|
||||
- this.setUsingItem(true);
|
||||
- if (!this.isSilent()) {
|
||||
- this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.WITCH_DRINK, this.getSoundSource(), 1.0F, 0.8F + this.random.nextFloat() * 0.4F);
|
||||
- }
|
||||
-
|
||||
- AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
|
||||
-
|
||||
- attributemodifiable.removeModifier(Witch.SPEED_MODIFIER_DRINKING.getId());
|
||||
- attributemodifiable.addTransientModifier(Witch.SPEED_MODIFIER_DRINKING);
|
||||
+ this.setDrinkingPotion(PotionUtils.setPotion(new ItemStack(Items.POTION), potionregistry)); // Paper - logic moved into setDrinkingPotion, copy exact impl into the method and then comment out
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,6 +172,23 @@ public class Witch extends Raider implements RangedAttackMob {
|
||||
super.aiStep();
|
||||
}
|
||||
|
||||
+ // Paper start - moved to its own method
|
||||
+ public void setDrinkingPotion(ItemStack potion) {
|
||||
+ potion = org.bukkit.craftbukkit.event.CraftEventFactory.handleWitchReadyPotionEvent(this, potion);
|
||||
+ this.setItemSlot(EquipmentSlot.MAINHAND, potion);
|
||||
+ this.usingTime = this.getMainHandItem().getUseDuration();
|
||||
+ this.setUsingItem(true);
|
||||
+ if (!this.isSilent()) {
|
||||
+ this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.WITCH_DRINK, this.getSoundSource(), 1.0F, 0.8F + this.random.nextFloat() * 0.4F);
|
||||
+ }
|
||||
+
|
||||
+ AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
|
||||
+
|
||||
+ attributemodifiable.removeModifier(Witch.SPEED_MODIFIER_DRINKING.getId());
|
||||
+ attributemodifiable.addTransientModifier(Witch.SPEED_MODIFIER_DRINKING);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public SoundEvent getCelebrateSound() {
|
||||
return SoundEvents.WITCH_CELEBRATE;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWitch.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWitch.java
|
||||
index 524b5ba5995affc09eedf9a85d22e8b0b4efc156..4b3d783cabcb2de1a67d7fbfb6f525bfb493aed1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWitch.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWitch.java
|
||||
@@ -2,6 +2,13 @@ package org.bukkit.craftbukkit.entity;
|
||||
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.entity.Witch;
|
||||
+// Paper start
|
||||
+import com.destroystokyo.paper.entity.CraftRangedEntity;
|
||||
+import com.google.common.base.Preconditions;
|
||||
+import org.bukkit.Material;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.inventory.ItemStack;
|
||||
+// Paper end
|
||||
|
||||
public class CraftWitch extends CraftRaider implements Witch, com.destroystokyo.paper.entity.CraftRangedEntity<net.minecraft.world.entity.monster.Witch> { // Paper
|
||||
public CraftWitch(CraftServer server, net.minecraft.world.entity.monster.Witch entity) {
|
||||
@@ -22,4 +29,23 @@ public class CraftWitch extends CraftRaider implements Witch, com.destroystokyo.
|
||||
public boolean isDrinkingPotion() {
|
||||
return this.getHandle().isDrinkingPotion();
|
||||
}
|
||||
+ // Paper start
|
||||
+ public int getPotionUseTimeLeft() {
|
||||
+ return getHandle().usingTime;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setPotionUseTimeLeft(int ticks) {
|
||||
+ getHandle().usingTime = ticks;
|
||||
+ }
|
||||
+
|
||||
+ public ItemStack getDrinkingPotion() {
|
||||
+ return CraftItemStack.asCraftMirror(getHandle().getMainHandItem());
|
||||
+ }
|
||||
+
|
||||
+ public void setDrinkingPotion(ItemStack potion) {
|
||||
+ Preconditions.checkArgument(potion == null || potion.getType().isEmpty() || potion.getType() == Material.POTION, "must be potion, air, or null");
|
||||
+ getHandle().setDrinkingPotion(CraftItemStack.asNMSCopy(potion));
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Wed, 10 Oct 2018 21:22:44 -0500
|
||||
Subject: [PATCH] Check Drowned for Villager Aggression Config
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Drowned.java b/src/main/java/net/minecraft/world/entity/monster/Drowned.java
|
||||
index ee2abc0c39a76a74c151ecc8660d2037f3db0636..01897af1e6253b987734a24c052daf2ce1314092 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Drowned.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Drowned.java
|
||||
@@ -78,7 +78,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
|
||||
this.goalSelector.addGoal(7, new RandomStrollGoal(this, 1.0D));
|
||||
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Drowned.class})).setAlertOthers(ZombifiedPiglin.class));
|
||||
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::okTarget));
|
||||
- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false));
|
||||
+ if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Paper - Check drowned for villager aggression config
|
||||
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
|
||||
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Axolotl.class, true, false));
|
||||
this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR));
|
|
@ -1,67 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gabriele C <sgdc3.mail@gmail.com>
|
||||
Date: Mon, 22 Oct 2018 17:34:10 +0200
|
||||
Subject: [PATCH] Add option to prevent players from moving into unloaded
|
||||
chunks #1551
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 7663110df928ec88fc97e3b7d65671001db2d1bc..1de240ecfbe815c12fc35aee1198f8c7a44f3527 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -474,9 +474,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
double d0 = entity.getX();
|
||||
double d1 = entity.getY();
|
||||
double d2 = entity.getZ();
|
||||
- double d3 = ServerGamePacketListenerImpl.clampHorizontal(packet.getX());
|
||||
- double d4 = ServerGamePacketListenerImpl.clampVertical(packet.getY());
|
||||
- double d5 = ServerGamePacketListenerImpl.clampHorizontal(packet.getZ());
|
||||
+ double d3 = ServerGamePacketListenerImpl.clampHorizontal(packet.getX()); final double toX = d3; // Paper - OBFHELPER
|
||||
+ double d4 = ServerGamePacketListenerImpl.clampVertical(packet.getY()); final double toY = d4; // Paper - OBFHELPER
|
||||
+ double d5 = ServerGamePacketListenerImpl.clampHorizontal(packet.getZ()); final double toZ = d5; // Paper - OBFHELPER
|
||||
float f = Mth.wrapDegrees(packet.getYRot());
|
||||
float f1 = Mth.wrapDegrees(packet.getXRot());
|
||||
double d6 = d3 - this.vehicleFirstGoodX;
|
||||
@@ -510,6 +510,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
speed *= 2f; // TODO: Get the speed of the vehicle instead of the player
|
||||
|
||||
+ // Paper start - Prevent moving into unloaded chunks
|
||||
+ if (this.player.level().paperConfig().chunks.preventMovingIntoUnloadedChunks && (
|
||||
+ !worldserver.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(this.player.position()))) ||
|
||||
+ !worldserver.areChunksLoadedForMove(entity.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(entity.position())))
|
||||
+ )) {
|
||||
+ this.connection.send(new ClientboundMoveVehiclePacket(entity));
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Prevent moving into unloaded chunks
|
||||
+
|
||||
if (d10 - d9 > Math.max(100.0D, Math.pow((double) (org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed), 2)) && !this.isSingleplayerOwner()) {
|
||||
// CraftBukkit end
|
||||
ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", new Object[]{entity.getName().getString(), this.player.getName().getString(), d6, d7, d8});
|
||||
@@ -1178,9 +1188,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
} else {
|
||||
this.awaitingTeleportTime = this.tickCount;
|
||||
- double d0 = ServerGamePacketListenerImpl.clampHorizontal(packet.getX(this.player.getX()));
|
||||
- double d1 = ServerGamePacketListenerImpl.clampVertical(packet.getY(this.player.getY()));
|
||||
- double d2 = ServerGamePacketListenerImpl.clampHorizontal(packet.getZ(this.player.getZ()));
|
||||
+ double d0 = ServerGamePacketListenerImpl.clampHorizontal(packet.getX(this.player.getX())); final double toX = d0; // Paper - OBFHELPER
|
||||
+ double d1 = ServerGamePacketListenerImpl.clampVertical(packet.getY(this.player.getY())); final double toY = d1; // Paper - OBFHELPER
|
||||
+ double d2 = ServerGamePacketListenerImpl.clampHorizontal(packet.getZ(this.player.getZ())); final double toZ = d2; // Paper - OBFHELPER
|
||||
float f = Mth.wrapDegrees(packet.getYRot(this.player.getYRot()));
|
||||
float f1 = Mth.wrapDegrees(packet.getXRot(this.player.getXRot()));
|
||||
|
||||
@@ -1236,6 +1246,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
} else {
|
||||
speed = this.player.getAbilities().walkingSpeed * 10f;
|
||||
}
|
||||
+ // Paper start - Prevent moving into unloaded chunks
|
||||
+ if (this.player.level().paperConfig().chunks.preventMovingIntoUnloadedChunks && (this.player.getX() != toX || this.player.getZ() != toZ) && !worldserver.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(this.player.position())))) {
|
||||
+ this.internalTeleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot(), Collections.emptySet());
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Prevent moving into unloaded chunks
|
||||
|
||||
if (!this.player.isChangingDimension() && (!this.player.level().getGameRules().getBoolean(GameRules.RULE_DISABLE_ELYTRA_MOVEMENT_CHECK) || !this.player.isFallFlying())) {
|
||||
float f2 = this.player.isFallFlying() ? 300.0F : 100.0F;
|
|
@ -1,18 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: GreenMeanie <GreenMeanieMC@gmail.com>
|
||||
Date: Sat, 20 Oct 2018 22:34:02 -0400
|
||||
Subject: [PATCH] Reset players airTicks on respawn
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 19c3eb566552f7994ae5e60dc869c94e08590fbb..08c936288b5ac8738d7cff9fe95b1256ae32cd28 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -2516,6 +2516,7 @@ public class ServerPlayer extends Player {
|
||||
|
||||
this.setHealth(this.getMaxHealth());
|
||||
this.stopUsingItem(); // CraftBukkit - SPIGOT-6682: Clear active item on reset
|
||||
+ this.setAirSupply(this.getMaxAirSupply()); // Paper - Reset players airTicks on respawn
|
||||
this.setRemainingFireTicks(0);
|
||||
this.fallDistance = 0;
|
||||
this.foodData = new FoodData(this);
|
|
@ -1,33 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 23 Oct 2018 20:25:05 -0400
|
||||
Subject: [PATCH] Don't sleep after profile lookups if not needed
|
||||
|
||||
Mojang was sleeping even if we had no more requests to go after
|
||||
the current one finished, resulting in 100ms lost per profile lookup
|
||||
|
||||
diff --git a/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java b/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java
|
||||
index b87546f0061458b2b919a1fe00dde1f4eea6cb3e..55dac5edf694b3bf82b475a71e3524a1bce98882 100644
|
||||
--- a/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java
|
||||
+++ b/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java
|
||||
@@ -44,6 +44,7 @@ public class YggdrasilGameProfileRepository implements GameProfileRepository {
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final int page = 0;
|
||||
+ boolean hasRequested = false; // Paper - Don't sleep after profile lookups if not needed
|
||||
|
||||
for (final List<String> request : Iterables.partition(criteria, ENTRIES_PER_PAGE)) {
|
||||
final List<String> normalizedRequest = request.stream().map(YggdrasilGameProfileRepository::normalizeName).toList();
|
||||
@@ -75,6 +76,12 @@ public class YggdrasilGameProfileRepository implements GameProfileRepository {
|
||||
LOGGER.debug("Couldn't find profile {}", name);
|
||||
callback.onProfileLookupFailed(name, new ProfileNotFoundException("Server did not find the requested profile"));
|
||||
}
|
||||
+ // Paper start - Don't sleep after profile lookups if not needed
|
||||
+ if (!hasRequested) {
|
||||
+ hasRequested = true;
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Paper end - Don't sleep after profile lookups if not needed
|
||||
|
||||
try {
|
||||
Thread.sleep(DELAY_BETWEEN_PAGES);
|
|
@ -1,105 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 23 Oct 2018 23:14:38 -0400
|
||||
Subject: [PATCH] Improve Server Thread Pool and Thread Priorities
|
||||
|
||||
Use a simple executor since Fork join is a much more complex pool
|
||||
type and we are not using its capabilities.
|
||||
|
||||
Set thread priorities so main thread has above normal priority over
|
||||
server threads
|
||||
|
||||
Allow usage of a single thread executor by not using ForkJoin so single core CPU's
|
||||
and reduce worldgen thread worker count for low core count CPUs.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.Util onThreadException(Ljava/lang/Thread;Ljava/lang/Throwable;)V
|
||||
|
||||
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/ServerWorkerThread.java b/src/main/java/io/papermc/paper/util/ServerWorkerThread.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b60f59cf5cc8eb84a6055b7861857dece7f2501b
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/ServerWorkerThread.java
|
||||
@@ -0,0 +1,14 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import java.util.concurrent.atomic.AtomicInteger;
|
||||
+import net.minecraft.Util;
|
||||
+
|
||||
+public class ServerWorkerThread extends Thread {
|
||||
+ private static final AtomicInteger threadId = new AtomicInteger(1);
|
||||
+ public ServerWorkerThread(Runnable target, String poolName, int prioritityModifier) {
|
||||
+ super(target, "Worker-" + poolName + "-" + threadId.getAndIncrement());
|
||||
+ setPriority(Thread.NORM_PRIORITY+prioritityModifier); // Deprioritize over main
|
||||
+ this.setDaemon(true);
|
||||
+ this.setUncaughtExceptionHandler(Util::onThreadException);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
|
||||
index 3db6962b9f6f5da09694d57b7323c39f314b1327..722734ce612fb790ddc80488a795a85ebcd4a842 100644
|
||||
--- a/src/main/java/net/minecraft/Util.java
|
||||
+++ b/src/main/java/net/minecraft/Util.java
|
||||
@@ -88,7 +88,7 @@ public class Util {
|
||||
private static final int DEFAULT_MAX_THREADS = 255;
|
||||
private static final int DEFAULT_SAFE_FILE_OPERATION_RETRIES = 10;
|
||||
private static final String MAX_THREADS_SYSTEM_PROPERTY = "max.bg.threads";
|
||||
- private static final ExecutorService BACKGROUND_EXECUTOR = makeExecutor("Main");
|
||||
+ private static final ExecutorService BACKGROUND_EXECUTOR = makeExecutor("Main", -1); // Paper - Perf: add priority
|
||||
private static final ExecutorService IO_POOL = makeIoExecutor("IO-Worker-", false);
|
||||
private static final ExecutorService DOWNLOAD_POOL = makeIoExecutor("Download-", true);
|
||||
// Paper start - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
|
||||
@@ -154,15 +154,27 @@ public class Util {
|
||||
return FILENAME_DATE_TIME_FORMATTER.format(ZonedDateTime.now());
|
||||
}
|
||||
|
||||
- private static ExecutorService makeExecutor(String name) {
|
||||
- int i = Mth.clamp(Runtime.getRuntime().availableProcessors() - 1, 1, getMaxThreads());
|
||||
+ private static ExecutorService makeExecutor(String s, int priorityModifier) { // Paper - Perf: add priority
|
||||
+ // Paper start - Perf: use simpler thread pool that allows 1 thread and reduce worldgen thread worker count for low core count CPUs
|
||||
+ int cpus = Runtime.getRuntime().availableProcessors() / 2;
|
||||
+ int i;
|
||||
+ if (cpus <= 4) {
|
||||
+ i = cpus <= 2 ? 1 : 2;
|
||||
+ } else if (cpus <= 8) {
|
||||
+ // [5, 8]
|
||||
+ i = Math.max(3, cpus - 2);
|
||||
+ } else {
|
||||
+ i = cpus * 2 / 3;
|
||||
+ }
|
||||
+ i = Math.min(8, i);
|
||||
+ i = Integer.getInteger("Paper.WorkerThreadCount", i);
|
||||
ExecutorService executorService;
|
||||
if (i <= 0) {
|
||||
executorService = MoreExecutors.newDirectExecutorService();
|
||||
} else {
|
||||
- AtomicInteger atomicInteger = new AtomicInteger(1);
|
||||
- executorService = new ForkJoinPool(i, pool -> {
|
||||
- ForkJoinWorkerThread forkJoinWorkerThread = new ForkJoinWorkerThread(pool) {
|
||||
+ executorService = new java.util.concurrent.ThreadPoolExecutor(i, i,0L, TimeUnit.MILLISECONDS, new java.util.concurrent.LinkedBlockingQueue<>(), target -> new io.papermc.paper.util.ServerWorkerThread(target, s, priorityModifier));
|
||||
+ }
|
||||
+ /*
|
||||
@Override
|
||||
protected void onTermination(Throwable throwable) {
|
||||
if (throwable != null) {
|
||||
@@ -178,6 +190,7 @@ public class Util {
|
||||
return forkJoinWorkerThread;
|
||||
}, Util::onThreadException, true);
|
||||
}
|
||||
+ }*/ // Paper end - Perf: use simpler thread pool
|
||||
|
||||
return executorService;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 8196ecb2a7280a4f60a5fea18c484d6419953b48..dd2cbb4d3bda6776e94279513b8d58d20661a8aa 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -312,6 +312,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
thread.setUncaughtExceptionHandler((thread1, throwable) -> {
|
||||
MinecraftServer.LOGGER.error("Uncaught exception in server thread", throwable);
|
||||
});
|
||||
+ thread.setPriority(Thread.NORM_PRIORITY+2); // Paper - Perf: Boost priority
|
||||
if (Runtime.getRuntime().availableProcessors() > 4) {
|
||||
thread.setPriority(8);
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 2 Nov 2018 23:11:51 -0400
|
||||
Subject: [PATCH] Optimize World Time Updates
|
||||
|
||||
Splits time updates into incremental updates as well as does
|
||||
the updates per world, so that we can re-use the same packet
|
||||
object for every player unless they have per-player time enabled.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index dd2cbb4d3bda6776e94279513b8d58d20661a8aa..01acf93115db41212adf703d44481f50c746a8fa 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1478,12 +1478,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
MinecraftTimings.timeUpdateTimer.startTiming(); // Spigot // Paper
|
||||
// Send time updates to everyone, it will get the right time from the world the player is in.
|
||||
- if (this.tickCount % 20 == 0) {
|
||||
- for (int i = 0; i < this.getPlayerList().players.size(); ++i) {
|
||||
- ServerPlayer entityplayer = (ServerPlayer) this.getPlayerList().players.get(i);
|
||||
- entityplayer.connection.send(new ClientboundSetTimePacket(entityplayer.level().getGameTime(), entityplayer.getPlayerTime(), entityplayer.level().getGameRules().getBoolean(GameRules.RULE_DAYLIGHT))); // Add support for per player time
|
||||
+ // Paper start - Perf: Optimize time updates
|
||||
+ for (final ServerLevel level : this.getAllLevels()) {
|
||||
+ final boolean doDaylight = level.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT);
|
||||
+ final long dayTime = level.getDayTime();
|
||||
+ long worldTime = level.getGameTime();
|
||||
+ final ClientboundSetTimePacket worldPacket = new ClientboundSetTimePacket(worldTime, dayTime, doDaylight);
|
||||
+ for (Player entityhuman : level.players()) {
|
||||
+ if (!(entityhuman instanceof ServerPlayer) || (tickCount + entityhuman.getId()) % 20 != 0) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ ServerPlayer entityplayer = (ServerPlayer) entityhuman;
|
||||
+ long playerTime = entityplayer.getPlayerTime();
|
||||
+ ClientboundSetTimePacket packet = (playerTime == dayTime) ? worldPacket :
|
||||
+ new ClientboundSetTimePacket(worldTime, playerTime, doDaylight);
|
||||
+ entityplayer.connection.send(packet); // Add support for per player time
|
||||
}
|
||||
}
|
||||
+ // Paper end - Perf: Optimize time updates
|
||||
MinecraftTimings.timeUpdateTimer.stopTiming(); // Spigot // Paper
|
||||
|
||||
while (iterator.hasNext()) {
|
|
@ -1,356 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Mon, 5 Nov 2018 04:23:51 +0000
|
||||
Subject: [PATCH] Restore custom InventoryHolder support
|
||||
|
||||
Upstream removed the ability to consistently use a custom InventoryHolder,
|
||||
However, the implementation does not use an InventoryHolder in any form
|
||||
outside of custom inventories.
|
||||
|
||||
== AT ==
|
||||
public-f net.minecraft.world.inventory.AbstractContainerMenu dataSlots
|
||||
public-f net.minecraft.world.inventory.AbstractContainerMenu remoteDataSlots
|
||||
|
||||
Co-authored-by: Shane Freeder <theboyetronic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/inventory/PaperInventoryCustomHolderContainer.java b/src/main/java/io/papermc/paper/inventory/PaperInventoryCustomHolderContainer.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..224d4b2cc45b0d02230a76caee9c88573a448b4c
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/inventory/PaperInventoryCustomHolderContainer.java
|
||||
@@ -0,0 +1,141 @@
|
||||
+package io.papermc.paper.inventory;
|
||||
+
|
||||
+import io.papermc.paper.adventure.PaperAdventure;
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
+import net.minecraft.world.Container;
|
||||
+import net.minecraft.world.entity.player.Player;
|
||||
+import net.minecraft.world.item.ItemStack;
|
||||
+import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
||||
+import org.bukkit.Location;
|
||||
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
+import org.bukkit.entity.HumanEntity;
|
||||
+import org.bukkit.event.inventory.InventoryType;
|
||||
+import org.bukkit.inventory.InventoryHolder;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+import java.util.List;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class PaperInventoryCustomHolderContainer implements Container {
|
||||
+
|
||||
+ private final InventoryHolder owner;
|
||||
+ private final Container delegate;
|
||||
+ private final InventoryType type;
|
||||
+ private final String title;
|
||||
+ private final Component adventure$title;
|
||||
+
|
||||
+ public PaperInventoryCustomHolderContainer(InventoryHolder owner, Container delegate, InventoryType type) {
|
||||
+ this.owner = owner;
|
||||
+ this.delegate = delegate;
|
||||
+ this.type = type;
|
||||
+ @Nullable Component adventure$title = null;
|
||||
+ if (delegate instanceof BaseContainerBlockEntity blockEntity) {
|
||||
+ adventure$title = blockEntity.getCustomName() != null ? PaperAdventure.asAdventure(blockEntity.getCustomName()) : null;
|
||||
+ }
|
||||
+ if (adventure$title == null) {
|
||||
+ adventure$title = type.defaultTitle();
|
||||
+ }
|
||||
+ this.adventure$title = adventure$title;
|
||||
+ this.title = LegacyComponentSerializer.legacySection().serialize(this.adventure$title);
|
||||
+ }
|
||||
+
|
||||
+ public Component title() {
|
||||
+ return this.adventure$title;
|
||||
+ }
|
||||
+
|
||||
+ public String getTitle() {
|
||||
+ return this.title;
|
||||
+ }
|
||||
+
|
||||
+ public InventoryType getType() {
|
||||
+ return this.type;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getContainerSize() {
|
||||
+ return this.delegate.getContainerSize();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isEmpty() {
|
||||
+ return this.delegate.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ItemStack getItem(int slot) {
|
||||
+ return this.delegate.getItem(slot);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ItemStack removeItem(int slot, int amount) {
|
||||
+ return this.delegate.removeItem(slot, amount);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ItemStack removeItemNoUpdate(int slot) {
|
||||
+ return this.delegate.removeItemNoUpdate(slot);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setItem(int slot, ItemStack stack) {
|
||||
+ this.delegate.setItem(slot, stack);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getMaxStackSize() {
|
||||
+ return this.delegate.getMaxStackSize();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setChanged() {
|
||||
+ this.delegate.setChanged();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean stillValid(Player player) {
|
||||
+ return this.delegate.stillValid(player);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<ItemStack> getContents() {
|
||||
+ return this.delegate.getContents();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onOpen(CraftHumanEntity who) {
|
||||
+ this.delegate.onOpen(who);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onClose(CraftHumanEntity who) {
|
||||
+ this.delegate.onClose(who);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<HumanEntity> getViewers() {
|
||||
+ return this.delegate.getViewers();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public InventoryHolder getOwner() {
|
||||
+ return this.owner;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setMaxStackSize(int size) {
|
||||
+ this.delegate.setMaxStackSize(size);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Location getLocation() {
|
||||
+ return this.delegate.getLocation();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void clearContent() {
|
||||
+ this.delegate.clearContent();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
|
||||
index 39be45585835eabc8d8bcae0158c094c3dcb1aa3..977b77547f7ba62cef3640cf8d4f1c8e7cded53a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
|
||||
@@ -50,7 +50,7 @@ public class CraftContainer extends AbstractContainerMenu {
|
||||
public CraftContainer(final Inventory inventory, final Player player, int id) {
|
||||
this(new InventoryView() {
|
||||
|
||||
- private final String originalTitle = (inventory instanceof CraftInventoryCustom) ? ((CraftInventoryCustom.MinecraftInventory) ((CraftInventory) inventory).getInventory()).getTitle() : inventory.getType().getDefaultTitle();
|
||||
+ private final String originalTitle = inventory instanceof CraftInventoryCustom ? ((CraftInventoryCustom) inventory).getTitle() : inventory.getType().getDefaultTitle(); // Paper
|
||||
private String title = this.originalTitle;
|
||||
|
||||
@Override
|
||||
@@ -76,7 +76,7 @@ public class CraftContainer extends AbstractContainerMenu {
|
||||
// Paper start
|
||||
@Override
|
||||
public net.kyori.adventure.text.Component title() {
|
||||
- return inventory instanceof CraftInventoryCustom ? ((CraftInventoryCustom.MinecraftInventory) ((CraftInventory) inventory).getInventory()).title() : net.kyori.adventure.text.Component.text(inventory.getType().getDefaultTitle());
|
||||
+ return inventory instanceof CraftInventoryCustom custom ? custom.title() : inventory.getType().defaultTitle(); // Paper
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -253,6 +253,10 @@ public class CraftContainer extends AbstractContainerMenu {
|
||||
this.lastSlots = this.delegate.lastSlots;
|
||||
this.slots = this.delegate.slots;
|
||||
this.remoteSlots = this.delegate.remoteSlots;
|
||||
+ // Paper start - copy data slots for InventoryView#set/getProperty
|
||||
+ this.dataSlots = this.delegate.dataSlots;
|
||||
+ this.remoteDataSlots = this.delegate.remoteDataSlots;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
// SPIGOT-4598 - we should still delegate the shift click handler
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
index 6a47c6adb721f0c6737150d8b0ee18ab70f5f281..75eb794f796b31c0c5ef80a6d27a56711a522f5e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
@@ -497,6 +497,10 @@ public class CraftInventory implements Inventory {
|
||||
return InventoryType.BREWING;
|
||||
} else if (this.inventory instanceof CraftInventoryCustom.MinecraftInventory) {
|
||||
return ((CraftInventoryCustom.MinecraftInventory) this.inventory).getType();
|
||||
+ // Paper start
|
||||
+ } else if (this.inventory instanceof io.papermc.paper.inventory.PaperInventoryCustomHolderContainer holderContainer) {
|
||||
+ return holderContainer.getType();
|
||||
+ // Paper end
|
||||
} else if (this.inventory instanceof PlayerEnderChestContainer) {
|
||||
return InventoryType.ENDER_CHEST;
|
||||
} else if (this.inventory instanceof MerchantContainer) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java
|
||||
index fc0e1212022d1aa3506699b60ef338196eb54eba..da1c1fe0faf6819b15a81d6ad53370948e5f984f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java
|
||||
@@ -15,6 +15,11 @@ import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
|
||||
public class CraftInventoryCustom extends CraftInventory {
|
||||
+ // Paper start
|
||||
+ public CraftInventoryCustom(InventoryHolder owner, InventoryType type, Container delegate) {
|
||||
+ super(new io.papermc.paper.inventory.PaperInventoryCustomHolderContainer(owner, delegate, type));
|
||||
+ }
|
||||
+ // Paper end
|
||||
public CraftInventoryCustom(InventoryHolder owner, InventoryType type) {
|
||||
super(new MinecraftInventory(owner, type));
|
||||
}
|
||||
@@ -42,6 +47,27 @@ public class CraftInventoryCustom extends CraftInventory {
|
||||
public CraftInventoryCustom(InventoryHolder owner, int size, String title) {
|
||||
super(new MinecraftInventory(owner, size, title));
|
||||
}
|
||||
+ // Paper start
|
||||
+ public String getTitle() {
|
||||
+ if (this.inventory instanceof MinecraftInventory minecraftInventory) {
|
||||
+ return minecraftInventory.getTitle();
|
||||
+ } else if (this.inventory instanceof io.papermc.paper.inventory.PaperInventoryCustomHolderContainer customHolderContainer) {
|
||||
+ return customHolderContainer.getTitle();
|
||||
+ } else {
|
||||
+ throw new UnsupportedOperationException(this.inventory.getClass() + " isn't a recognized Container type here");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public net.kyori.adventure.text.Component title() {
|
||||
+ if (this.inventory instanceof MinecraftInventory minecraftInventory) {
|
||||
+ return minecraftInventory.title();
|
||||
+ } else if (this.inventory instanceof io.papermc.paper.inventory.PaperInventoryCustomHolderContainer customHolderContainer) {
|
||||
+ return customHolderContainer.title();
|
||||
+ } else {
|
||||
+ throw new UnsupportedOperationException(this.inventory.getClass() + " isn't a recognized Container type here");
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
static class MinecraftInventory implements Container {
|
||||
private final NonNullList<ItemStack> items;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java
|
||||
index 3aecc929c0a9ea6a770326304dacd51fc08ac894..8d3f71689087d687e6400e2ea9750a6fb3535bf1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java
|
||||
@@ -28,7 +28,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(InventoryHolder holder, InventoryType type) {
|
||||
- return this.getInventory(this.getTileEntity());
|
||||
+ return this.getInventory(holder, type, this.getTileEntity()); // Paper
|
||||
}
|
||||
|
||||
// Paper start
|
||||
@@ -39,7 +39,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
((RandomizableContainerBlockEntity) te).setCustomName(io.papermc.paper.adventure.PaperAdventure.asVanilla(title));
|
||||
}
|
||||
|
||||
- return getInventory(te);
|
||||
+ return this.getInventory(owner, type, te); // Paper
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -50,10 +50,18 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
((RandomizableContainerBlockEntity) te).setCustomName(CraftChatMessage.fromStringOrNull(title));
|
||||
}
|
||||
|
||||
- return this.getInventory(te);
|
||||
+ return this.getInventory(holder, type, te); // Paper
|
||||
}
|
||||
|
||||
+ @Deprecated // Paper - use getInventory with owner and type
|
||||
public Inventory getInventory(Container tileEntity) {
|
||||
+ // Paper start
|
||||
+ return this.getInventory(null, null, tileEntity);
|
||||
+ }
|
||||
+
|
||||
+ public Inventory getInventory(InventoryHolder owner, InventoryType type, Container tileEntity) { // Paper
|
||||
+ if (owner != null) return new org.bukkit.craftbukkit.inventory.CraftInventoryCustom(owner, type, tileEntity); // Paper
|
||||
+ // Paper end
|
||||
return new CraftInventory(tileEntity);
|
||||
}
|
||||
|
||||
@@ -70,7 +78,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
public Inventory createInventory(InventoryHolder owner, InventoryType type, net.kyori.adventure.text.Component title) {
|
||||
Container tileEntity = getTileEntity();
|
||||
((AbstractFurnaceBlockEntity) tileEntity).setCustomName(io.papermc.paper.adventure.PaperAdventure.asVanilla(title));
|
||||
- return getInventory(tileEntity);
|
||||
+ return this.getInventory(owner, type, tileEntity); // Paper
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -78,11 +86,19 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
public Inventory createInventory(InventoryHolder owner, InventoryType type, String title) {
|
||||
Container tileEntity = this.getTileEntity();
|
||||
((AbstractFurnaceBlockEntity) tileEntity).setCustomName(CraftChatMessage.fromStringOrNull(title));
|
||||
- return this.getInventory(tileEntity);
|
||||
+ return this.getInventory(owner, type, tileEntity); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getInventory(Container tileEntity) {
|
||||
+ // Paper start
|
||||
+ return getInventory(null, null, tileEntity);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Inventory getInventory(InventoryHolder owner, InventoryType type, net.minecraft.world.Container tileEntity) { // Paper
|
||||
+ if (owner != null) return new org.bukkit.craftbukkit.inventory.CraftInventoryCustom(owner, type, tileEntity); // Paper
|
||||
+ // Paper end
|
||||
return new CraftInventoryFurnace((AbstractFurnaceBlockEntity) tileEntity);
|
||||
}
|
||||
}
|
||||
@@ -102,7 +118,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
if (tileEntity instanceof BrewingStandBlockEntity) {
|
||||
((BrewingStandBlockEntity) tileEntity).setCustomName(io.papermc.paper.adventure.PaperAdventure.asVanilla(title));
|
||||
}
|
||||
- return getInventory(tileEntity);
|
||||
+ return this.getInventory(owner, type, tileEntity); // Paper
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -113,11 +129,19 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
if (tileEntity instanceof BrewingStandBlockEntity) {
|
||||
((BrewingStandBlockEntity) tileEntity).setCustomName(CraftChatMessage.fromStringOrNull(title));
|
||||
}
|
||||
- return this.getInventory(tileEntity);
|
||||
+ return this.getInventory(holder, type, tileEntity); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getInventory(Container tileEntity) {
|
||||
+ // Paper start
|
||||
+ return getInventory(null, null, tileEntity);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Inventory getInventory(InventoryHolder owner, InventoryType type, net.minecraft.world.Container tileEntity) { // Paper
|
||||
+ if (owner != null) return new org.bukkit.craftbukkit.inventory.CraftInventoryCustom(owner, type, tileEntity); // Paper
|
||||
+ // Paper end
|
||||
return new CraftInventoryBrewer(tileEntity);
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sat, 10 Nov 2018 05:15:21 +0000
|
||||
Subject: [PATCH] Fix SpongeAbsortEvent handling
|
||||
|
||||
Only process drops when the block is actually going to be removed
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/SpongeBlock.java b/src/main/java/net/minecraft/world/level/block/SpongeBlock.java
|
||||
index 1238317d3e6d968525a10c5480a7d44d56abb071..8f3cca228f8ec1ea9379fa43af4baa7b18012dd2 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/SpongeBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/SpongeBlock.java
|
||||
@@ -134,7 +134,11 @@ public class SpongeBlock extends Block {
|
||||
} else if (iblockdata.is(Blocks.KELP) || iblockdata.is(Blocks.KELP_PLANT) || iblockdata.is(Blocks.SEAGRASS) || iblockdata.is(Blocks.TALL_SEAGRASS)) {
|
||||
BlockEntity tileentity = iblockdata.hasBlockEntity() ? world.getBlockEntity(blockposition1) : null;
|
||||
|
||||
+ // Paper start - Fix SpongeAbsortEvent handling
|
||||
+ if (block.getHandle().isAir()) {
|
||||
dropResources(iblockdata, world, blockposition1, tileentity);
|
||||
+ }
|
||||
+ // Paper end - Fix SpongeAbsortEvent handling
|
||||
}
|
||||
}
|
||||
world.setBlock(blockposition1, block.getHandle(), block.getFlag());
|
|
@ -1,77 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sun, 11 Nov 2018 21:01:09 +0000
|
||||
Subject: [PATCH] Don't allow digging into unloaded chunks
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index a8d33286832786031ac57e6ce27d5181e1a3d9b1..e8b12b27e5ec74afb940f575e5ce78e5905d55f4 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -119,8 +119,8 @@ public class ServerPlayerGameMode {
|
||||
BlockState iblockdata;
|
||||
|
||||
if (this.hasDelayedDestroy) {
|
||||
- iblockdata = this.level.getBlockState(this.delayedDestroyPos);
|
||||
- if (iblockdata.isAir()) {
|
||||
+ iblockdata = this.level.getBlockStateIfLoaded(this.delayedDestroyPos); // Paper - Don't allow digging into unloaded chunks
|
||||
+ if (iblockdata == null || iblockdata.isAir()) { // Paper - Don't allow digging into unloaded chunks
|
||||
this.hasDelayedDestroy = false;
|
||||
} else {
|
||||
float f = this.incrementDestroyProgress(iblockdata, this.delayedDestroyPos, this.delayedTickStart);
|
||||
@@ -131,7 +131,13 @@ public class ServerPlayerGameMode {
|
||||
}
|
||||
}
|
||||
} else if (this.isDestroyingBlock) {
|
||||
- iblockdata = this.level.getBlockState(this.destroyPos);
|
||||
+ // Paper start - Don't allow digging into unloaded chunks; don't want to do same logic as above, return instead
|
||||
+ iblockdata = this.level.getBlockStateIfLoaded(this.destroyPos);
|
||||
+ if (iblockdata == null) {
|
||||
+ this.isDestroyingBlock = false;
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Don't allow digging into unloaded chunks
|
||||
if (iblockdata.isAir()) {
|
||||
this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1);
|
||||
this.lastSentState = -1;
|
||||
@@ -160,6 +166,7 @@ public class ServerPlayerGameMode {
|
||||
|
||||
public void handleBlockBreakAction(BlockPos pos, ServerboundPlayerActionPacket.Action action, Direction direction, int worldHeight, int sequence) {
|
||||
if (this.player.getEyePosition().distanceToSqr(Vec3.atCenterOf(pos)) > ServerGamePacketListenerImpl.MAX_INTERACTION_DISTANCE) {
|
||||
+ if (true) return; // Paper - Don't allow digging into unloaded chunks; Don't notify if unreasonably far away
|
||||
this.debugLogging(pos, false, sequence, "too far");
|
||||
} else if (pos.getY() >= worldHeight) {
|
||||
this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos)));
|
||||
@@ -299,10 +306,12 @@ public class ServerPlayerGameMode {
|
||||
this.debugLogging(pos, true, sequence, "stopped destroying");
|
||||
} else if (action == ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK) {
|
||||
this.isDestroyingBlock = false;
|
||||
- if (!Objects.equals(this.destroyPos, pos)) {
|
||||
+ if (!Objects.equals(this.destroyPos, pos) && !BlockPos.ZERO.equals(this.destroyPos)) { // Paper
|
||||
ServerPlayerGameMode.LOGGER.debug("Mismatch in destroy block pos: {} {}", this.destroyPos, pos); // CraftBukkit - SPIGOT-5457 sent by client when interact event cancelled
|
||||
- this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1);
|
||||
- this.debugLogging(pos, true, sequence, "aborted mismatched destroying");
|
||||
+ BlockState type = this.level.getBlockStateIfLoaded(this.destroyPos); // Paper - don't load unloaded chunks for stale records here
|
||||
+ if (type != null) this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1);
|
||||
+ if (type != null) this.debugLogging(pos, true, sequence, "aborted mismatched destroying");
|
||||
+ this.destroyPos = BlockPos.ZERO; // Paper
|
||||
}
|
||||
|
||||
this.level.destroyBlockProgress(this.player.getId(), pos, -1);
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 1de240ecfbe815c12fc35aee1198f8c7a44f3527..f7529016db5d6f933d8f44de07bbdb9e67040cb1 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1590,6 +1590,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
case START_DESTROY_BLOCK:
|
||||
case ABORT_DESTROY_BLOCK:
|
||||
case STOP_DESTROY_BLOCK:
|
||||
+ // Paper start - Don't allow digging into unloaded chunks
|
||||
+ if (this.player.level().getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4) == null) {
|
||||
+ this.player.connection.ackBlockChangesUpTo(packet.getSequence());
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Don't allow digging into unloaded chunks
|
||||
this.player.gameMode.handleBlockBreakAction(blockposition, packetplayinblockdig_enumplayerdigtype, packet.getDirection(), this.player.level().getMaxBuildHeight(), packet.getSequence());
|
||||
this.player.connection.ackBlockChangesUpTo(packet.getSequence());
|
||||
return;
|
|
@ -1,40 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sun, 18 Nov 2018 19:49:56 +0000
|
||||
Subject: [PATCH] Make the default permission message configurable
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
index 6d06b772ffb9d47d6a717462a4b2b494544e80ae..69ffd6ea2ce7c6d4f211c6081fcea79afd7eac6c 100644
|
||||
--- a/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
@@ -73,7 +73,7 @@ public final class PaperCommand extends Command {
|
||||
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));
|
||||
+ sender.sendMessage(Bukkit.permissionMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index abdff07588cb06f8ec4f3f2172f7dce92fa8a979..43c69ec522a2c91d47b5cea05aaf86f979c5fcb2 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2815,6 +2815,16 @@ public final class CraftServer implements Server {
|
||||
return io.papermc.paper.configuration.GlobalConfiguration.get().commands.suggestPlayerNamesWhenNullTabCompletions;
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ public String getPermissionMessage() {
|
||||
+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().serialize(io.papermc.paper.configuration.GlobalConfiguration.get().messages.noPermission);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.kyori.adventure.text.Component permissionMessage() {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().messages.noPermission;
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nonnull UUID uuid) {
|
||||
return createProfile(uuid, null);
|
|
@ -1,134 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 27 Nov 2018 21:18:06 -0500
|
||||
Subject: [PATCH] Handle Large Packets disconnecting client
|
||||
|
||||
If a players inventory is too big to send in a single packet,
|
||||
split the inventory set into multiple packets instead.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index 02b3f5c67b47a098f7fe15ddba0df6cb586a9ae5..157f055df00faf3a7870df8109e84fdb12f55964 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -156,6 +156,22 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
|
||||
public void exceptionCaught(ChannelHandlerContext channelhandlercontext, Throwable throwable) {
|
||||
+ // Paper start - Handle large packets disconnecting client
|
||||
+ if (throwable instanceof io.netty.handler.codec.EncoderException && throwable.getCause() instanceof PacketEncoder.PacketTooLargeException packetTooLargeException) {
|
||||
+ final Packet<?> packet = packetTooLargeException.getPacket();
|
||||
+ final io.netty.util.Attribute<ConnectionProtocol.CodecData<?>> codecDataAttribute = channelhandlercontext.channel().attr(packetTooLargeException.codecKey);
|
||||
+ if (packet.packetTooLarge(this)) {
|
||||
+ ProtocolSwapHandler.swapProtocolIfNeeded(codecDataAttribute, packet);
|
||||
+ return;
|
||||
+ } else if (packet.isSkippable()) {
|
||||
+ Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause());
|
||||
+ ProtocolSwapHandler.swapProtocolIfNeeded(codecDataAttribute, packet);
|
||||
+ return;
|
||||
+ } else {
|
||||
+ throwable = throwable.getCause();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Handle large packets disconnecting client
|
||||
if (throwable instanceof SkipPacketException) {
|
||||
Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause());
|
||||
} else {
|
||||
diff --git a/src/main/java/net/minecraft/network/PacketEncoder.java b/src/main/java/net/minecraft/network/PacketEncoder.java
|
||||
index 0d80fcee1831af59b06c4d00dc713bd4dad947fc..061eada043325142d33a0cec02e9e484d14a7fca 100644
|
||||
--- a/src/main/java/net/minecraft/network/PacketEncoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/PacketEncoder.java
|
||||
@@ -41,7 +41,7 @@ public class PacketEncoder extends MessageToByteEncoder<Packet<?>> {
|
||||
int j = friendlyByteBuf.writerIndex();
|
||||
packet.write(friendlyByteBuf);
|
||||
int k = friendlyByteBuf.writerIndex() - j;
|
||||
- if (k > 8388608) {
|
||||
+ if (false && k > 8388608) { // Paper - Handle large packets disconnecting client; disable
|
||||
throw new IllegalArgumentException("Packet too big (is " + k + ", should be less than 8388608): " + packet);
|
||||
}
|
||||
|
||||
@@ -54,9 +54,34 @@ public class PacketEncoder extends MessageToByteEncoder<Packet<?>> {
|
||||
|
||||
throw var13;
|
||||
} finally {
|
||||
+ // Paper start - Handle large packets disconnecting client
|
||||
+ int packetLength = friendlyByteBuf.readableBytes();
|
||||
+ if (packetLength > MAX_PACKET_SIZE) {
|
||||
+ throw new PacketTooLargeException(packet, this.codecKey, packetLength);
|
||||
+ }
|
||||
+ // Paper end - Handle large packets disconnecting client
|
||||
ProtocolSwapHandler.swapProtocolIfNeeded(attribute, packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ private static int MAX_PACKET_SIZE = 8388608;
|
||||
+
|
||||
+ public static class PacketTooLargeException extends RuntimeException {
|
||||
+ private final Packet<?> packet;
|
||||
+ public final AttributeKey<ConnectionProtocol.CodecData<?>> codecKey;
|
||||
+
|
||||
+ PacketTooLargeException(Packet<?> packet, AttributeKey<ConnectionProtocol.CodecData<?>> codecKey, int packetLength) {
|
||||
+ super("PacketTooLarge - " + packet.getClass().getSimpleName() + " is " + packetLength + ". Max is " + MAX_PACKET_SIZE);
|
||||
+ this.packet = packet;
|
||||
+ this.codecKey = codecKey;
|
||||
+ }
|
||||
+
|
||||
+ public Packet<?> getPacket() {
|
||||
+ return this.packet;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/Packet.java b/src/main/java/net/minecraft/network/protocol/Packet.java
|
||||
index 700418bb0c9fbed3f161611881b1e222248ca4eb..cc658a61065d5c0021a4b88fa58b40211b94f8ec 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/Packet.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/Packet.java
|
||||
@@ -10,6 +10,12 @@ public interface Packet<T extends PacketListener> {
|
||||
|
||||
void handle(T listener);
|
||||
|
||||
+ // Paper start
|
||||
+ default boolean packetTooLarge(net.minecraft.network.Connection manager) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
default boolean isSkippable() {
|
||||
return false;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java
|
||||
index 6206d4d71dfe95b454b22f5b3055623638e145c0..6765175c98d52e5cbc191e88e0d545a05606dfd4 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java
|
||||
@@ -31,6 +31,16 @@ public class ClientboundContainerSetContentPacket implements Packet<ClientGamePa
|
||||
this.carriedItem = buf.readItem();
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean packetTooLarge(net.minecraft.network.Connection manager) {
|
||||
+ for (int i = 0 ; i < this.items.size() ; i++) {
|
||||
+ manager.send(new ClientboundContainerSetSlotPacket(this.containerId, this.stateId, i, this.items.get(i)));
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
buf.writeByte(this.containerId);
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
index dc657312889da4fc3222a6981223a01406b77deb..a44a82d2d5ed4d675dc1a184d5b6b935fda575dd 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
@@ -49,7 +49,7 @@ public class ClientboundLevelChunkPacketData {
|
||||
throw new RuntimeException("Can't read heightmap in packet for [" + x + ", " + z + "]");
|
||||
} else {
|
||||
int i = buf.readVarInt();
|
||||
- if (i > 2097152) {
|
||||
+ if (i > 2097152) { // Paper - diff on change - if this changes, update PacketEncoder
|
||||
throw new RuntimeException("Chunk Packet trying to allocate too much memory on read.");
|
||||
} else {
|
||||
this.buffer = new byte[i];
|
|
@ -1,113 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Thu, 15 Nov 2018 13:38:37 +0000
|
||||
Subject: [PATCH] force entity dismount during teleportation
|
||||
|
||||
Entities must be dismounted before teleportation in order to avoid
|
||||
multiple issues in the server with regards to teleportation, shamefully,
|
||||
too many plugins rely on the events firing, which means that not firing
|
||||
these events caues more issues than it solves;
|
||||
|
||||
In order to counteract this, Entity dismount/exit vehicle events have
|
||||
been modified to supress cancellation (and has a method to allow plugins
|
||||
to check if this has been set), noting that cancellation will be silently
|
||||
surpressed given that plugins are not expecting this event to not be cancellable.
|
||||
|
||||
This is a far from ideal scenario, however: given the current state of this
|
||||
event and other alternatives causing issues elsewhere, I believe that
|
||||
this is going to be the best soultion all around.
|
||||
|
||||
Improvements/suggestions welcome!
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index c46ad2013439f043145fb7fc67bbcd80728e3c16..f746829f1e94ee58821e56ec4192269add00395b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2570,11 +2570,16 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
|
||||
}
|
||||
|
||||
public void removeVehicle() {
|
||||
+ // Paper start - Force entity dismount during teleportation
|
||||
+ stopRiding(false);
|
||||
+ }
|
||||
+ public void stopRiding(boolean suppressCancellation) {
|
||||
+ // Paper end - Force entity dismount during teleportation
|
||||
if (this.vehicle != null) {
|
||||
Entity entity = this.vehicle;
|
||||
|
||||
this.vehicle = null;
|
||||
- if (!entity.removePassenger(this)) this.vehicle = entity; // CraftBukkit
|
||||
+ if (!entity.removePassenger(this, suppressCancellation)) this.vehicle = entity; // CraftBukkit // Paper - Force entity dismount during teleportation
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2605,7 +2610,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
|
||||
}
|
||||
}
|
||||
|
||||
- protected boolean removePassenger(Entity entity) { // CraftBukkit
|
||||
+ // Paper start - Force entity dismount during teleportation
|
||||
+ protected boolean removePassenger(Entity entity) { return removePassenger(entity, false);}
|
||||
+ protected boolean removePassenger(Entity entity, boolean suppressCancellation) { // CraftBukkit
|
||||
+ // Paper end - Force entity dismount during teleportation
|
||||
if (entity.getVehicle() == this) {
|
||||
throw new IllegalStateException("Use x.stopRiding(y), not y.removePassenger(x)");
|
||||
} else {
|
||||
@@ -2615,7 +2623,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
|
||||
if (this.getBukkitEntity() instanceof Vehicle && entity.getBukkitEntity() instanceof LivingEntity) {
|
||||
VehicleExitEvent event = new VehicleExitEvent(
|
||||
(Vehicle) this.getBukkitEntity(),
|
||||
- (LivingEntity) entity.getBukkitEntity()
|
||||
+ (LivingEntity) entity.getBukkitEntity(), !suppressCancellation // Paper - Force entity dismount during teleportation
|
||||
);
|
||||
// Suppress during worldgen
|
||||
if (this.valid) {
|
||||
@@ -2628,7 +2636,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
|
||||
}
|
||||
}
|
||||
|
||||
- EntityDismountEvent event = new EntityDismountEvent(entity.getBukkitEntity(), this.getBukkitEntity());
|
||||
+ EntityDismountEvent event = new EntityDismountEvent(entity.getBukkitEntity(), this.getBukkitEntity(), !suppressCancellation); // Paper - Force entity dismount during teleportation
|
||||
// Suppress during worldgen
|
||||
if (this.valid) {
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 1a328de32b69b69814e11a5b6bc55bfccf408d6b..4be7b136dd2b35b0637a1455985ab99bbd3af0a5 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3492,9 +3492,15 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
|
||||
@Override
|
||||
public void stopRiding() {
|
||||
+ // Paper start - Force entity dismount during teleportation
|
||||
+ stopRiding(false);
|
||||
+ }
|
||||
+ @Override
|
||||
+ public void stopRiding(boolean suppressCancellation) {
|
||||
+ // Paper end - Force entity dismount during teleportation
|
||||
Entity entity = this.getVehicle();
|
||||
|
||||
- super.stopRiding();
|
||||
+ super.stopRiding(suppressCancellation); // Paper - Force entity dismount during teleportation
|
||||
if (entity != null && entity != this.getVehicle() && !this.level().isClientSide) {
|
||||
this.dismountVehicle(entity);
|
||||
}
|
||||
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 83c7ba56900ce40f71d98062bf15110a76597dce..3c3c953f05c18279d3245fe6bc8afef83cd62cd1 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -1141,7 +1141,13 @@ public abstract class Player extends LivingEntity {
|
||||
|
||||
@Override
|
||||
public void removeVehicle() {
|
||||
- super.removeVehicle();
|
||||
+ // Paper start - Force entity dismount during teleportation
|
||||
+ stopRiding(false);
|
||||
+ }
|
||||
+ @Override
|
||||
+ public void stopRiding(boolean suppressCancellation) {
|
||||
+ super.stopRiding(suppressCancellation);
|
||||
+ // Paper end - Force entity dismount during teleportation
|
||||
this.boardingCooldown = 0;
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 7 Oct 2018 04:29:59 -0500
|
||||
Subject: [PATCH] Add more Zombie API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.monster.Zombie isSunSensitive()Z
|
||||
|
||||
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 15ccde8ee8bac1f70c6047464595aff6db073646..2c8529540bf3644896f3c05d5f544bd848647807 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
@@ -96,6 +96,7 @@ public class Zombie extends Monster {
|
||||
private int inWaterTime;
|
||||
public int conversionTime;
|
||||
private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field
|
||||
+ private boolean shouldBurnInDay = true; // Paper - Add more Zombie API
|
||||
|
||||
public Zombie(EntityType<? extends Zombie> type, Level world) {
|
||||
super(type, world);
|
||||
@@ -264,6 +265,12 @@ public class Zombie extends Monster {
|
||||
super.aiStep();
|
||||
}
|
||||
|
||||
+ // Paper start - Add more Zombie API
|
||||
+ public void stopDrowning() {
|
||||
+ this.conversionTime = -1;
|
||||
+ this.getEntityData().set(Zombie.DATA_DROWNED_CONVERSION_ID, false);
|
||||
+ }
|
||||
+ // Paper end - Add more Zombie API
|
||||
public void startUnderWaterConversion(int ticksUntilWaterConversion) {
|
||||
this.lastTick = MinecraftServer.currentTick; // CraftBukkit
|
||||
this.conversionTime = ticksUntilWaterConversion;
|
||||
@@ -293,9 +300,15 @@ public class Zombie extends Monster {
|
||||
}
|
||||
|
||||
public boolean isSunSensitive() {
|
||||
- return true;
|
||||
+ return this.shouldBurnInDay; // Paper - Add more Zombie API
|
||||
}
|
||||
|
||||
+ // Paper start - Add more Zombie API
|
||||
+ public void setShouldBurnInDay(boolean shouldBurnInDay) {
|
||||
+ this.shouldBurnInDay = shouldBurnInDay;
|
||||
+ }
|
||||
+ // Paper end - Add more Zombie API
|
||||
+
|
||||
@Override
|
||||
public boolean hurt(DamageSource source, float amount) {
|
||||
if (!super.hurt(source, amount)) {
|
||||
@@ -415,6 +428,7 @@ public class Zombie extends Monster {
|
||||
nbt.putBoolean("CanBreakDoors", this.canBreakDoors());
|
||||
nbt.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1);
|
||||
nbt.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1);
|
||||
+ nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -426,6 +440,11 @@ public class Zombie extends Monster {
|
||||
if (nbt.contains("DrownedConversionTime", 99) && nbt.getInt("DrownedConversionTime") > -1) {
|
||||
this.startUnderWaterConversion(nbt.getInt("DrownedConversionTime"));
|
||||
}
|
||||
+ // Paper start - Add more Zombie API
|
||||
+ if (nbt.contains("Paper.ShouldBurnInDay")) {
|
||||
+ this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay");
|
||||
+ }
|
||||
+ // Paper end - Add more Zombie API
|
||||
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java
|
||||
index 99dcaa827831a40ea46453f502d8b6ccb107f0ad..4412c913123f7521f449c98b60378e8d3b1671ce 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java
|
||||
@@ -87,6 +87,42 @@ public class CraftZombie extends CraftMonster implements Zombie {
|
||||
@Override
|
||||
public void setAgeLock(boolean b) {
|
||||
}
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean isDrowning() {
|
||||
+ return getHandle().isUnderWaterConverting();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void startDrowning(int drownedConversionTime) {
|
||||
+ getHandle().startUnderWaterConversion(drownedConversionTime);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void stopDrowning() {
|
||||
+ getHandle().stopDrowning();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean shouldBurnInDay() {
|
||||
+ return getHandle().isSunSensitive();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isArmsRaised() {
|
||||
+ return getHandle().isAggressive();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setArmsRaised(final boolean raised) {
|
||||
+ getHandle().setAggressive(raised);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setShouldBurnInDay(boolean shouldBurnInDay) {
|
||||
+ getHandle().setShouldBurnInDay(shouldBurnInDay);
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
@Override
|
||||
public boolean getAgeLock() {
|
|
@ -1,57 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 16 Nov 2018 23:08:50 -0500
|
||||
Subject: [PATCH] Book Size Limits
|
||||
|
||||
Puts some limits on the size of books.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index f7529016db5d6f933d8f44de07bbdb9e67040cb1..b42b429e318b9ee784847a1824157573df99f683 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1024,6 +1024,45 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
@Override
|
||||
public void handleEditBook(ServerboundEditBookPacket packet) {
|
||||
+ // Paper start - Book size limits
|
||||
+ if (!this.cserver.isPrimaryThread()) {
|
||||
+ List<String> pageList = packet.getPages();
|
||||
+ long byteTotal = 0;
|
||||
+ int maxBookPageSize = io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.pageMax;
|
||||
+ double multiplier = Math.max(0.3D, Math.min(1D, io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.totalMultiplier));
|
||||
+ long byteAllowed = maxBookPageSize;
|
||||
+ for (String testString : pageList) {
|
||||
+ int byteLength = testString.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;
|
||||
+ if (byteLength > 256 * 4) {
|
||||
+ ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " tried to send a book with with a page too large!");
|
||||
+ server.scheduleOnMain(() -> this.disconnect("Book too large!"));
|
||||
+ return;
|
||||
+ }
|
||||
+ byteTotal += byteLength;
|
||||
+ int length = testString.length();
|
||||
+ int multibytes = 0;
|
||||
+ if (byteLength != length) {
|
||||
+ for (char c : testString.toCharArray()) {
|
||||
+ if (c > 127) {
|
||||
+ multibytes++;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ byteAllowed += (maxBookPageSize * Math.min(1, Math.max(0.1D, (double) length / 255D))) * multiplier;
|
||||
+
|
||||
+ if (multibytes > 1) {
|
||||
+ // penalize MB
|
||||
+ byteAllowed -= multibytes;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (byteTotal > byteAllowed) {
|
||||
+ ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " tried to send too large of a book. Book Size: " + byteTotal + " - Allowed: "+ byteAllowed + " - Pages: " + pageList.size());
|
||||
+ server.scheduleOnMain(() -> this.disconnect("Book too large!"));
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Book size limits
|
||||
// CraftBukkit start
|
||||
if (this.lastBookTick + 20 > MinecraftServer.currentTick) {
|
||||
this.disconnect("Book edited too quickly!");
|
|
@ -1,83 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 7 Oct 2018 12:05:28 -0700
|
||||
Subject: [PATCH] Add PlayerConnectionCloseEvent
|
||||
|
||||
This event is invoked when a player has disconnected. It is guaranteed that,
|
||||
if the server is in online-mode, that the provided uuid and username have been
|
||||
validated.
|
||||
|
||||
The event is invoked for players who have not yet logged into the world, whereas
|
||||
PlayerQuitEvent is only invoked on players who have logged into the world.
|
||||
|
||||
The event is invoked for players who have already logged into the world,
|
||||
although whether or not the player exists in the world at the time of
|
||||
firing is undefined. (That is, whether the plugin can retrieve a Player object
|
||||
using the event parameters is undefined). However, it is guaranteed that this
|
||||
event is invoked AFTER PlayerQuitEvent, if the player has already logged into
|
||||
the world.
|
||||
|
||||
This event is guaranteed to never fire unless AsyncPlayerPreLoginEvent has
|
||||
been called beforehand, and this event may not be called in parallel with
|
||||
AsyncPlayerPreLoginEvent for the same connection.
|
||||
|
||||
Cancelling the AsyncPlayerPreLoginEvent guarantees the corresponding
|
||||
PlayerConnectionCloseEvent is never called.
|
||||
|
||||
The event may be invoked asynchronously or synchronously. As it stands,
|
||||
it is never invoked asynchronously. However, plugins should check
|
||||
Event#isAsynchronous to be future-proof.
|
||||
|
||||
On purpose, the deprecated PlayerPreLoginEvent event is left out of the
|
||||
API spec for this event. Plugins should not be using that event, and
|
||||
how PlayerPreLoginEvent interacts with PlayerConnectionCloseEvent
|
||||
is undefined.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.server.network.ServerLoginPacketListenerImpl$State
|
||||
public net.minecraft.server.network.ServerLoginPacketListenerImpl state
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index 157f055df00faf3a7870df8109e84fdb12f55964..7648b889bc488197f32545e8c3671a54102c01ec 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -644,6 +644,26 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
packetlistener1.onDisconnect(ichatbasecomponent);
|
||||
}
|
||||
this.pendingActions.clear(); // Free up packet queue.
|
||||
+ // Paper start - Add PlayerConnectionCloseEvent
|
||||
+ final PacketListener packetListener = this.getPacketListener();
|
||||
+ if (packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) {
|
||||
+ /* Player was logged in, either game listener or configuration listener */
|
||||
+ final com.mojang.authlib.GameProfile profile = commonPacketListener.getOwner();
|
||||
+ new com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent(profile.getId(),
|
||||
+ profile.getName(), ((InetSocketAddress) this.address).getAddress(), false).callEvent();
|
||||
+ } else if (packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginListener) {
|
||||
+ /* Player is login stage */
|
||||
+ switch (loginListener.state) {
|
||||
+ case VERIFYING:
|
||||
+ case WAITING_FOR_DUPE_DISCONNECT:
|
||||
+ case PROTOCOL_SWITCHING:
|
||||
+ case ACCEPTED:
|
||||
+ final com.mojang.authlib.GameProfile profile = loginListener.authenticatedProfile; /* Should be non-null at this stage */
|
||||
+ new com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent(profile.getId(), profile.getName(),
|
||||
+ ((InetSocketAddress) this.address).getAddress(), false).callEvent();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Add PlayerConnectionCloseEvent
|
||||
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index e745061f3e6a4541f44ba119106915cdb7023fc6..f4ed58b03876c35f8964a8a1b8ce89961b9ee6d3 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -60,7 +60,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
@Nullable
|
||||
String requestedUsername;
|
||||
@Nullable
|
||||
- private GameProfile authenticatedProfile;
|
||||
+ public GameProfile authenticatedProfile; // Paper - public
|
||||
private final String serverId;
|
||||
private ServerPlayer player; // CraftBukkit
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach@zachbr.io>
|
||||
Date: Wed, 2 Jan 2019 00:35:43 -0600
|
||||
Subject: [PATCH] Replace OfflinePlayer#getLastPlayed
|
||||
|
||||
Currently OfflinePlayer#getLastPlayed could more accurately be described
|
||||
as "OfflinePlayer#getLastTimeTheirDataWasSaved".
|
||||
|
||||
The API doc says it should return the last time the server "witnessed"
|
||||
the player, whilst also saying it should return the last time they
|
||||
logged in. The current implementation does neither.
|
||||
|
||||
Given this interesting contradiction in the API documentation and the
|
||||
current defacto implementation, I've elected to deprecate (with no
|
||||
intent to remove) and replace it with two new methods, clearly named and
|
||||
documented as to their purpose.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 08c936288b5ac8738d7cff9fe95b1256ae32cd28..a8de1f58fffe2541478083defc18be949d0c75f1 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -248,6 +248,7 @@ public class ServerPlayer extends Player {
|
||||
private int containerCounter;
|
||||
public boolean wonGame;
|
||||
private int containerUpdateDelay; // Paper - Configurable container update tick rate
|
||||
+ public long loginTime; // Paper - Replace OfflinePlayer#getLastPlayed
|
||||
// Paper start - cancellable death event
|
||||
public boolean queueHealthUpdatePacket;
|
||||
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 7d81334b8bbfc04f1188de777b0cacd6f80131d3..2a0d3319899f0b3f38135e25306b87b1974b3d83 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -180,6 +180,7 @@ public abstract class PlayerList {
|
||||
|
||||
public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData) {
|
||||
player.isRealPlayer = true; // Paper
|
||||
+ player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed
|
||||
GameProfile gameprofile = player.getGameProfile();
|
||||
GameProfileCache usercache = this.server.getProfileCache();
|
||||
String s;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
||||
index 34925d6448e0ef1d5bb4b24359f732b67aaa4230..0c1b5f625a351905e082b2c2a63bfd737101527e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
||||
@@ -262,6 +262,61 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
|
||||
return this.getData() != null;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public long getLastLogin() {
|
||||
+ Player player = getPlayer();
|
||||
+ if (player != null) return player.getLastLogin();
|
||||
+
|
||||
+ CompoundTag data = getPaperData();
|
||||
+
|
||||
+ if (data != null) {
|
||||
+ if (data.contains("LastLogin")) {
|
||||
+ return data.getLong("LastLogin");
|
||||
+ } else {
|
||||
+ // if the player file cannot provide accurate data, this is probably the closest we can approximate
|
||||
+ File file = getDataFile();
|
||||
+ return file.lastModified();
|
||||
+ }
|
||||
+ } else {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public long getLastSeen() {
|
||||
+ Player player = getPlayer();
|
||||
+ if (player != null) return player.getLastSeen();
|
||||
+
|
||||
+ CompoundTag data = getPaperData();
|
||||
+
|
||||
+ if (data != null) {
|
||||
+ if (data.contains("LastSeen")) {
|
||||
+ return data.getLong("LastSeen");
|
||||
+ } else {
|
||||
+ // if the player file cannot provide accurate data, this is probably the closest we can approximate
|
||||
+ File file = getDataFile();
|
||||
+ return file.lastModified();
|
||||
+ }
|
||||
+ } else {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private CompoundTag getPaperData() {
|
||||
+ CompoundTag result = getData();
|
||||
+
|
||||
+ if (result != null) {
|
||||
+ if (!result.contains("Paper")) {
|
||||
+ result.put("Paper", new CompoundTag());
|
||||
+ }
|
||||
+ result = result.getCompound("Paper");
|
||||
+ }
|
||||
+
|
||||
+ return result;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public Location getLastDeathLocation() {
|
||||
if (this.getData().contains("LastDeathLocation", 10)) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 29ede2405a645499e804a2f914a2563ef443f919..0e251c385db7969398eca95e3353de4a3de6d189 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -197,6 +197,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
private BorderChangeListener clientWorldBorderListener = this.createWorldBorderListener();
|
||||
public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus; // Paper - more resource pack API
|
||||
private static final boolean DISABLE_CHANNEL_LIMIT = System.getProperty("paper.disableChannelLimit") != null; // Paper - add a flag to disable the channel limit
|
||||
+ private long lastSaveTime; // Paper - getLastPlayed replacement API
|
||||
|
||||
public CraftPlayer(CraftServer server, ServerPlayer entity) {
|
||||
super(server, entity);
|
||||
@@ -1958,6 +1959,18 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
this.firstPlayed = firstPlayed;
|
||||
}
|
||||
|
||||
+ // Paper start - getLastPlayed replacement API
|
||||
+ @Override
|
||||
+ public long getLastLogin() {
|
||||
+ return this.getHandle().loginTime;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public long getLastSeen() {
|
||||
+ return this.isOnline() ? System.currentTimeMillis() : this.lastSaveTime;
|
||||
+ }
|
||||
+ // Paper end - getLastPlayed replacement API
|
||||
+
|
||||
public void readExtraData(CompoundTag nbttagcompound) {
|
||||
this.hasPlayedBefore = true;
|
||||
if (nbttagcompound.contains("bukkit")) {
|
||||
@@ -1980,6 +1993,8 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
}
|
||||
|
||||
public void setExtraData(CompoundTag nbttagcompound) {
|
||||
+ this.lastSaveTime = System.currentTimeMillis(); // Paper
|
||||
+
|
||||
if (!nbttagcompound.contains("bukkit")) {
|
||||
nbttagcompound.put("bukkit", new CompoundTag());
|
||||
}
|
||||
@@ -1994,6 +2009,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
data.putLong("firstPlayed", this.getFirstPlayed());
|
||||
data.putLong("lastPlayed", System.currentTimeMillis());
|
||||
data.putString("lastKnownName", handle.getScoreboardName());
|
||||
+
|
||||
+ // Paper start - persist for use in offline save data
|
||||
+ if (!nbttagcompound.contains("Paper")) {
|
||||
+ nbttagcompound.put("Paper", new CompoundTag());
|
||||
+ }
|
||||
+
|
||||
+ CompoundTag paper = nbttagcompound.getCompound("Paper");
|
||||
+ paper.putLong("LastLogin", handle.loginTime);
|
||||
+ paper.putLong("LastSeen", System.currentTimeMillis());
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,24 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: connorhartley <vectrixu+gh@gmail.com>
|
||||
Date: Mon, 7 Jan 2019 14:43:48 -0600
|
||||
Subject: [PATCH] Workaround for vehicle tracking issue on disconnect
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index a8de1f58fffe2541478083defc18be949d0c75f1..7433116ee68b92c86d1588296d521e5df49e5ac2 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1705,6 +1705,13 @@ public class ServerPlayer extends Player {
|
||||
public void disconnect() {
|
||||
this.disconnected = true;
|
||||
this.ejectPassengers();
|
||||
+
|
||||
+ // Paper start - Workaround vehicle not tracking the passenger disconnection dismount
|
||||
+ if (this.isPassenger() && this.getVehicle() instanceof ServerPlayer) {
|
||||
+ this.stopRiding();
|
||||
+ }
|
||||
+ // Paper end - Workaround vehicle not tracking the passenger disconnection dismount
|
||||
+
|
||||
if (this.isSleeping()) {
|
||||
this.stopSleepInBed(true, false);
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach@zachbr.io>
|
||||
Date: Mon, 4 Feb 2019 23:33:24 -0500
|
||||
Subject: [PATCH] Dont block Player#remove if the handle is a custom player
|
||||
|
||||
Upstream throws UOE if you try to call remove on a Player.
|
||||
We just add a check to ensure that the CraftPlayer's handle
|
||||
is a ServerPlayer
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 0e251c385db7969398eca95e3353de4a3de6d189..314e01920fe0302441d2cc08a0098ff8fee263e5 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -211,8 +211,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
+ if (this.getHandle().getClass().equals(ServerPlayer.class)) { // special case for NMS plugins inheriting
|
||||
// Will lead to an inconsistent player state if we remove the player as any other entity.
|
||||
throw new UnsupportedOperationException(String.format("Cannot remove player %s, use Player#kickPlayer(String) instead.", this.getName()));
|
||||
+ } else {
|
||||
+ super.remove();
|
||||
+ }
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,53 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 6 Feb 2019 00:20:33 -0500
|
||||
Subject: [PATCH] BlockDestroyEvent
|
||||
|
||||
Adds an event for when the server is going to destroy a current block,
|
||||
potentially causing it to drop. This event can be cancelled to avoid
|
||||
the block destruction, such as preventing signs from popping when
|
||||
floating in the air.
|
||||
|
||||
This can replace many uses of BlockPhysicsEvent
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 2eb80978ffc26c6250f3a96b73ee20bfea4ecd45..12809bc84aa07e724bebbc631199f352b7d7bbcb 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -26,6 +26,7 @@ import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
+import io.papermc.paper.util.MCUtil;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.FullChunkStatus;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
@@ -582,9 +583,26 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
return false;
|
||||
} else {
|
||||
FluidState fluid = this.getFluidState(pos);
|
||||
+ // Paper start - BlockDestroyEvent; while the above setAir method is named same and looks very similar
|
||||
+ // they are NOT used with same intent and the above should not fire this event. The above method is more of a BlockSetToAirEvent,
|
||||
+ // it doesn't imply destruction of a block that plays a sound effect / drops an item.
|
||||
+ boolean playEffect = true;
|
||||
+ BlockState effectType = iblockdata;
|
||||
+ int xp = iblockdata.getBlock().getExpDrop(iblockdata, (ServerLevel) this, pos, ItemStack.EMPTY, true);
|
||||
+ if (com.destroystokyo.paper.event.block.BlockDestroyEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
+ com.destroystokyo.paper.event.block.BlockDestroyEvent event = new com.destroystokyo.paper.event.block.BlockDestroyEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), fluid.createLegacyBlock().createCraftBlockData(), effectType.createCraftBlockData(), xp, drop);
|
||||
+ if (!event.callEvent()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ effectType = ((CraftBlockData) event.getEffectBlock()).getState();
|
||||
+ playEffect = event.playEffect();
|
||||
+ drop = event.willDrop();
|
||||
+ xp = event.getExpToDrop();
|
||||
+ }
|
||||
+ // Paper end - BlockDestroyEvent
|
||||
|
||||
- if (!(iblockdata.getBlock() instanceof BaseFireBlock)) {
|
||||
- this.levelEvent(2001, pos, Block.getId(iblockdata));
|
||||
+ if (playEffect && !(effectType.getBlock() instanceof BaseFireBlock)) { // Paper - BlockDestroyEvent
|
||||
+ this.levelEvent(2001, pos, Block.getId(effectType)); // Paper - BlockDestroyEvent
|
||||
}
|
||||
|
||||
if (drop) {
|
|
@ -1,66 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Callahan <mr.callahhh@gmail.com>
|
||||
Date: Wed, 8 Apr 2020 02:42:14 -0500
|
||||
Subject: [PATCH] Async command map building
|
||||
|
||||
This adds a custom pool inorder to make sure that they are closed
|
||||
without much though, as it doesn't matter if the client is not sent
|
||||
commands if the server is restarting. Using the default async pool caused issues to arise
|
||||
due to the shutdown logic generally being much later.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
|
||||
index 15a5059994371da4850adcf726034a715b80efba..af7cb518a32a4d550eae833fdd5bb17fd4058717 100644
|
||||
--- a/src/main/java/net/minecraft/commands/Commands.java
|
||||
+++ b/src/main/java/net/minecraft/commands/Commands.java
|
||||
@@ -457,6 +457,24 @@ public class Commands {
|
||||
if ( org.spigotmc.SpigotConfig.tabComplete < 0 ) return; // Spigot
|
||||
// CraftBukkit start
|
||||
// Register Vanilla commands into builtRoot as before
|
||||
+ // Paper start - Perf: Async command map building
|
||||
+ COMMAND_SENDING_POOL.execute(() -> {
|
||||
+ this.sendAsync(player);
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ public static final java.util.concurrent.ThreadPoolExecutor COMMAND_SENDING_POOL = new java.util.concurrent.ThreadPoolExecutor(
|
||||
+ 0, 2, 60L, java.util.concurrent.TimeUnit.SECONDS,
|
||||
+ new java.util.concurrent.LinkedBlockingQueue<>(),
|
||||
+ new com.google.common.util.concurrent.ThreadFactoryBuilder()
|
||||
+ .setNameFormat("Paper Async Command Builder Thread Pool - %1$d")
|
||||
+ .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER))
|
||||
+ .build(),
|
||||
+ new java.util.concurrent.ThreadPoolExecutor.DiscardPolicy()
|
||||
+ );
|
||||
+
|
||||
+ private void sendAsync(ServerPlayer player) {
|
||||
+ // Paper end - Perf: Async command map building
|
||||
Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> map = Maps.newIdentityHashMap(); // Use identity to prevent aliasing issues
|
||||
RootCommandNode vanillaRoot = new RootCommandNode();
|
||||
|
||||
@@ -474,7 +492,14 @@ public class Commands {
|
||||
for (CommandNode node : rootcommandnode.getChildren()) {
|
||||
bukkit.add(node.getName());
|
||||
}
|
||||
+ // Paper start - Perf: Async command map building
|
||||
+ net.minecraft.server.MinecraftServer.getServer().execute(() -> {
|
||||
+ runSync(player, bukkit, rootcommandnode);
|
||||
+ });
|
||||
+ }
|
||||
|
||||
+ private void runSync(ServerPlayer player, Collection<String> bukkit, RootCommandNode<SharedSuggestionProvider> rootcommandnode) {
|
||||
+ // Paper end - Perf: Async command map building
|
||||
PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit));
|
||||
event.getPlayer().getServer().getPluginManager().callEvent(event);
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 01acf93115db41212adf703d44481f50c746a8fa..3d59c9f256f00c213af33c35cd6471a78b97c290 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -916,6 +916,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
MinecraftServer.LOGGER.info("Stopping server");
|
||||
+ Commands.COMMAND_SENDING_POOL.shutdownNow(); // Paper - Perf: Async command map building; Shutdown and don't bother finishing
|
||||
MinecraftTimings.stopServer(); // Paper
|
||||
// CraftBukkit start
|
||||
if (this.server != null) {
|
|
@ -1,210 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 19 Apr 2020 18:15:29 -0400
|
||||
Subject: [PATCH] Brigadier Mojang API
|
||||
|
||||
Adds AsyncPlayerSendCommandsEvent
|
||||
- Allows modifying on a per command basis what command data they see.
|
||||
|
||||
Adds CommandRegisteredEvent
|
||||
- Allows manipulating the CommandNode to add more children/metadata for the client
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index 470c55412e7a4f09235947adc72944b903d6543d..9cd80bc7f2b47e1044eef2592274e38d1988ff5d 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -14,6 +14,7 @@ val alsoShade: Configuration by configurations.creating
|
||||
|
||||
dependencies {
|
||||
implementation(project(":paper-api"))
|
||||
+ implementation(project(":paper-mojangapi"))
|
||||
// Paper start
|
||||
implementation("org.jline:jline-terminal-jansi:3.21.0")
|
||||
implementation("net.minecrell:terminalconsoleappender:1.3.0")
|
||||
diff --git a/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java b/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java
|
||||
index 3370731ee064d2693b972a0765c13dd4fd69f66a..09d486a05179b9d878e1c33725b4e614c3544da9 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java
|
||||
@@ -5,7 +5,7 @@ package com.mojang.brigadier.exceptions;
|
||||
|
||||
import com.mojang.brigadier.Message;
|
||||
|
||||
-public class CommandSyntaxException extends Exception {
|
||||
+public class CommandSyntaxException extends Exception implements net.kyori.adventure.util.ComponentMessageThrowable { // Paper - Brigadier API
|
||||
public static final int CONTEXT_AMOUNT = 10;
|
||||
public static boolean ENABLE_COMMAND_STACK_TRACES = true;
|
||||
public static BuiltInExceptionProvider BUILT_IN_EXCEPTIONS = new BuiltInExceptions();
|
||||
@@ -73,4 +73,11 @@ public class CommandSyntaxException extends Exception {
|
||||
public int getCursor() {
|
||||
return cursor;
|
||||
}
|
||||
+
|
||||
+ // Paper start - Brigadier API
|
||||
+ @Override
|
||||
+ public @org.jetbrains.annotations.Nullable net.kyori.adventure.text.Component componentMessage() {
|
||||
+ return io.papermc.paper.brigadier.PaperBrigadier.componentFromMessage(this.message);
|
||||
+ }
|
||||
+ // Paper end - Brigadier API
|
||||
}
|
||||
diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
index da6250df1c5f3385b683cffde47754bca4606f5e..d8142624f9f3a5909e7cc5665f1629a1a67dd302 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
@@ -34,6 +34,7 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
||||
private final RedirectModifier<S> modifier;
|
||||
private final boolean forks;
|
||||
private Command<S> command;
|
||||
+ public LiteralCommandNode<CommandSourceStack> clientNode; // Paper - Brigadier API
|
||||
// CraftBukkit start
|
||||
public void removeCommand(String name) {
|
||||
this.children.remove(name);
|
||||
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
index edf49f2d9921b4517fb98929d842f7a62c5549df..0f98345f8adc6e9bf7fb2dc9ce4eba59a33ded61 100644
|
||||
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
@@ -45,7 +45,7 @@ import net.minecraft.world.phys.Vec2;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import com.mojang.brigadier.tree.CommandNode; // CraftBukkit
|
||||
|
||||
-public class CommandSourceStack implements ExecutionCommandSource<CommandSourceStack>, SharedSuggestionProvider {
|
||||
+public class CommandSourceStack implements ExecutionCommandSource<CommandSourceStack>, SharedSuggestionProvider, com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource { // Paper - Brigadier API
|
||||
|
||||
public static final SimpleCommandExceptionType ERROR_NOT_PLAYER = new SimpleCommandExceptionType(Component.translatable("permissions.requires.player"));
|
||||
public static final SimpleCommandExceptionType ERROR_NOT_ENTITY = new SimpleCommandExceptionType(Component.translatable("permissions.requires.entity"));
|
||||
@@ -170,6 +170,26 @@ public class CommandSourceStack implements ExecutionCommandSource<CommandSourceS
|
||||
return this.textName;
|
||||
}
|
||||
|
||||
+ // Paper start - Brigadier API
|
||||
+ @Override
|
||||
+ public org.bukkit.entity.Entity getBukkitEntity() {
|
||||
+ return getEntity() != null ? getEntity().getBukkitEntity() : null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.World getBukkitWorld() {
|
||||
+ return getLevel() != null ? getLevel().getWorld() : null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.Location getBukkitLocation() {
|
||||
+ Vec3 pos = getPosition();
|
||||
+ org.bukkit.World world = getBukkitWorld();
|
||||
+ Vec2 rot = getRotation();
|
||||
+ return world != null && pos != null ? new org.bukkit.Location(world, pos.x, pos.y, pos.z, rot != null ? rot.y : 0, rot != null ? rot.x : 0) : null;
|
||||
+ }
|
||||
+ // Paper end - Brigadier API
|
||||
+
|
||||
@Override
|
||||
public boolean hasPermission(int level) {
|
||||
// CraftBukkit start
|
||||
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
|
||||
index af7cb518a32a4d550eae833fdd5bb17fd4058717..40ff3090fb17fb0f01a9b52639fb783ea57ce6b6 100644
|
||||
--- a/src/main/java/net/minecraft/commands/Commands.java
|
||||
+++ b/src/main/java/net/minecraft/commands/Commands.java
|
||||
@@ -493,6 +493,7 @@ public class Commands {
|
||||
bukkit.add(node.getName());
|
||||
}
|
||||
// Paper start - Perf: Async command map building
|
||||
+ new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent<CommandSourceStack>(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper - Brigadier API
|
||||
net.minecraft.server.MinecraftServer.getServer().execute(() -> {
|
||||
runSync(player, bukkit, rootcommandnode);
|
||||
});
|
||||
@@ -500,6 +501,7 @@ public class Commands {
|
||||
|
||||
private void runSync(ServerPlayer player, Collection<String> bukkit, RootCommandNode<SharedSuggestionProvider> rootcommandnode) {
|
||||
// Paper end - Perf: Async command map building
|
||||
+ new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent<CommandSourceStack>(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper - Brigadier API
|
||||
PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit));
|
||||
event.getPlayer().getServer().getPluginManager().callEvent(event);
|
||||
|
||||
@@ -518,6 +520,11 @@ public class Commands {
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
CommandNode<CommandSourceStack> commandnode2 = (CommandNode) iterator.next();
|
||||
+ // Paper start - Brigadier API
|
||||
+ if (commandnode2.clientNode != null) {
|
||||
+ commandnode2 = commandnode2.clientNode;
|
||||
+ }
|
||||
+ // Paper end - Brigadier API
|
||||
if ( !org.spigotmc.SpigotConfig.sendNamespaced && commandnode2.getName().contains( ":" ) ) continue; // Spigot
|
||||
|
||||
if (commandnode2.canUse(source)) {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index b42b429e318b9ee784847a1824157573df99f683..9e7598a0cc3965e382ba13d7fd700585a4884a97 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -746,7 +746,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
builder.suggest(completion.suggestion(), PaperAdventure.asVanilla(completion.tooltip()));
|
||||
}
|
||||
}
|
||||
- this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), builder.buildFuture().join()));
|
||||
+ // Paper start - Brigadier API
|
||||
+ com.mojang.brigadier.suggestion.Suggestions suggestions = builder.buildFuture().join();
|
||||
+ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, packet.getCommand());
|
||||
+ suggestEvent.setCancelled(suggestions.isEmpty());
|
||||
+ if (suggestEvent.callEvent()) {
|
||||
+ this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestEvent.getSuggestions()));
|
||||
+ }
|
||||
+ // Paper end - Brigadier API
|
||||
}
|
||||
}
|
||||
|
||||
@@ -755,8 +762,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
ParseResults<CommandSourceStack> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack());
|
||||
|
||||
this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> {
|
||||
- if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [<args>] from showing for plugins with nothing more to offer
|
||||
- this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions));
|
||||
+ // Paper start - Brigadier API
|
||||
+ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, packet.getCommand());
|
||||
+ suggestEvent.setCancelled(suggestions.isEmpty());
|
||||
+ if (suggestEvent.callEvent()) {
|
||||
+ this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestEvent.getSuggestions()));
|
||||
+ }
|
||||
+ // Paper end - Brigadier API
|
||||
});
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java
|
||||
index 83d81b9371902b0302d13e53b31c15fac4e67966..d113e54a30db16e2ad955170df6030d15de530d6 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java
|
||||
@@ -20,7 +20,7 @@ import org.bukkit.command.CommandException;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
|
||||
-public class BukkitCommandWrapper implements com.mojang.brigadier.Command<CommandSourceStack>, Predicate<CommandSourceStack>, SuggestionProvider<CommandSourceStack> {
|
||||
+public class BukkitCommandWrapper implements com.mojang.brigadier.Command<CommandSourceStack>, Predicate<CommandSourceStack>, SuggestionProvider<CommandSourceStack>, com.destroystokyo.paper.brigadier.BukkitBrigadierCommand<CommandSourceStack> { // Paper
|
||||
|
||||
private final CraftServer server;
|
||||
private final Command command;
|
||||
@@ -31,10 +31,24 @@ public class BukkitCommandWrapper implements com.mojang.brigadier.Command<Comman
|
||||
}
|
||||
|
||||
public LiteralCommandNode<CommandSourceStack> register(CommandDispatcher<CommandSourceStack> dispatcher, String label) {
|
||||
- return dispatcher.register(
|
||||
- LiteralArgumentBuilder.<CommandSourceStack>literal(label).requires(this).executes(this)
|
||||
- .then(RequiredArgumentBuilder.<CommandSourceStack, String>argument("args", StringArgumentType.greedyString()).suggests(this).executes(this))
|
||||
- );
|
||||
+ // Paper start - Expose Brigadier to Paper-MojangAPI
|
||||
+ com.mojang.brigadier.tree.RootCommandNode<CommandSourceStack> root = dispatcher.getRoot();
|
||||
+ LiteralCommandNode<CommandSourceStack> literal = LiteralArgumentBuilder.<CommandSourceStack>literal(label).requires(this).executes(this).build();
|
||||
+ LiteralCommandNode<CommandSourceStack> defaultNode = literal;
|
||||
+ com.mojang.brigadier.tree.ArgumentCommandNode<CommandSourceStack, String> defaultArgs = RequiredArgumentBuilder.<CommandSourceStack, String>argument("args", StringArgumentType.greedyString()).suggests(this).executes(this).build();
|
||||
+ literal.addChild(defaultArgs);
|
||||
+ com.destroystokyo.paper.event.brigadier.CommandRegisteredEvent<CommandSourceStack> event = new com.destroystokyo.paper.event.brigadier.CommandRegisteredEvent<>(label, this, this.command, root, literal, defaultArgs);
|
||||
+ if (!event.callEvent()) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ literal = event.getLiteral();
|
||||
+ if (event.isRawCommand()) {
|
||||
+ defaultNode.clientNode = literal;
|
||||
+ literal = defaultNode;
|
||||
+ }
|
||||
+ root.addChild(literal);
|
||||
+ return literal;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,383 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sun, 25 Jun 2023 23:10:14 -0700
|
||||
Subject: [PATCH] Improve exact choice recipe ingredients
|
||||
|
||||
Fixes exact choices not working with recipe book clicks
|
||||
and shapeless recipes.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.item.ItemStackLinkedSet TYPE_AND_TAG
|
||||
public net.minecraft.world.entity.player.StackedContents put(II)V
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/inventory/recipe/RecipeBookExactChoiceRecipe.java b/src/main/java/io/papermc/paper/inventory/recipe/RecipeBookExactChoiceRecipe.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..2a2f8327a5bd3983a3a13fd663beb98906f27312
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/inventory/recipe/RecipeBookExactChoiceRecipe.java
|
||||
@@ -0,0 +1,30 @@
|
||||
+package io.papermc.paper.inventory.recipe;
|
||||
+
|
||||
+import net.minecraft.world.Container;
|
||||
+import net.minecraft.world.item.crafting.Ingredient;
|
||||
+import net.minecraft.world.item.crafting.Recipe;
|
||||
+
|
||||
+public abstract class RecipeBookExactChoiceRecipe<C extends Container> implements Recipe<C> {
|
||||
+
|
||||
+ private boolean hasExactIngredients;
|
||||
+
|
||||
+ protected final void checkExactIngredients() {
|
||||
+ // skip any special recipes
|
||||
+ if (this.isSpecial()) {
|
||||
+ this.hasExactIngredients = false;
|
||||
+ return;
|
||||
+ }
|
||||
+ for (final Ingredient ingredient : this.getIngredients()) {
|
||||
+ if (!ingredient.isEmpty() && ingredient.exact) {
|
||||
+ this.hasExactIngredients = true;
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ this.hasExactIngredients = false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final boolean hasExactIngredients() {
|
||||
+ return this.hasExactIngredients;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtraMap.java b/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtraMap.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..63db0b843c5bd11f979e613ba6cfac9d9da956bb
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtraMap.java
|
||||
@@ -0,0 +1,79 @@
|
||||
+package io.papermc.paper.inventory.recipe;
|
||||
+
|
||||
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
+import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
+import it.unimi.dsi.fastutil.ints.IntComparators;
|
||||
+import it.unimi.dsi.fastutil.ints.IntList;
|
||||
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
+import it.unimi.dsi.fastutil.objects.Object2IntOpenCustomHashMap;
|
||||
+import java.util.IdentityHashMap;
|
||||
+import java.util.Map;
|
||||
+import java.util.concurrent.atomic.AtomicInteger;
|
||||
+import net.minecraft.core.registries.BuiltInRegistries;
|
||||
+import net.minecraft.world.entity.player.StackedContents;
|
||||
+import net.minecraft.world.item.ItemStack;
|
||||
+import net.minecraft.world.item.ItemStackLinkedSet;
|
||||
+import net.minecraft.world.item.crafting.Ingredient;
|
||||
+import net.minecraft.world.item.crafting.Recipe;
|
||||
+
|
||||
+public final class StackedContentsExtraMap {
|
||||
+
|
||||
+ private final AtomicInteger idCounter = new AtomicInteger(BuiltInRegistries.ITEM.size()); // start at max vanilla stacked contents idx
|
||||
+ private final Object2IntMap<ItemStack> exactChoiceIds = new Object2IntOpenCustomHashMap<>(ItemStackLinkedSet.TYPE_AND_TAG);
|
||||
+ private final Int2ObjectMap<ItemStack> idToExactChoice = new Int2ObjectOpenHashMap<>();
|
||||
+ private final StackedContents contents;
|
||||
+ public final Map<Ingredient, IntList> extraStackingIds = new IdentityHashMap<>();
|
||||
+
|
||||
+ public StackedContentsExtraMap(final StackedContents contents, final Recipe<?> recipe) {
|
||||
+ this.exactChoiceIds.defaultReturnValue(-1);
|
||||
+ this.contents = contents;
|
||||
+ this.initialize(recipe);
|
||||
+ }
|
||||
+
|
||||
+ private void initialize(final Recipe<?> recipe) {
|
||||
+ if (recipe.hasExactIngredients()) {
|
||||
+ for (final Ingredient ingredient : recipe.getIngredients()) {
|
||||
+ if (!ingredient.isEmpty() && ingredient.exact) {
|
||||
+ final net.minecraft.world.item.ItemStack[] items = ingredient.getItems();
|
||||
+ final IntList idList = new IntArrayList(items.length);
|
||||
+ for (final ItemStack item : items) {
|
||||
+ idList.add(this.registerExact(item)); // I think not copying the stack here is safe because cb copies the stack when creating the ingredient
|
||||
+ if (!item.hasTag()) {
|
||||
+ // add regular index if it's a plain itemstack but still registered as exact
|
||||
+ idList.add(StackedContents.getStackingIndex(item));
|
||||
+ }
|
||||
+ }
|
||||
+ idList.sort(IntComparators.NATURAL_COMPARATOR);
|
||||
+ this.extraStackingIds.put(ingredient, idList);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private int registerExact(final ItemStack exactChoice) {
|
||||
+ final int existing = this.exactChoiceIds.getInt(exactChoice);
|
||||
+ if (existing > -1) {
|
||||
+ return existing;
|
||||
+ }
|
||||
+ final int id = this.idCounter.getAndIncrement();
|
||||
+ this.exactChoiceIds.put(exactChoice, id);
|
||||
+ this.idToExactChoice.put(id, exactChoice);
|
||||
+ return id;
|
||||
+ }
|
||||
+
|
||||
+ public ItemStack getById(int id) {
|
||||
+ return this.idToExactChoice.get(id);
|
||||
+ }
|
||||
+
|
||||
+ public boolean accountStack(final ItemStack stack, final int count) {
|
||||
+ if (!this.exactChoiceIds.isEmpty()) {
|
||||
+ final int id = this.exactChoiceIds.getInt(stack);
|
||||
+ if (id >= 0) {
|
||||
+ this.contents.put(id, count);
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/inventory/recipe/package-info.java b/src/main/java/io/papermc/paper/inventory/recipe/package-info.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..413dfa52760db393ad6a8b5341200ee704a864fc
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/inventory/recipe/package-info.java
|
||||
@@ -0,0 +1,5 @@
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+package io.papermc.paper.inventory.recipe;
|
||||
+
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
diff --git a/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java b/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
index f7328e583c63b4b74664ea78110f8b71c635ce60..80f032cca3309b709a11898cbc08bce27cbd624d 100644
|
||||
--- a/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
+++ b/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
@@ -34,6 +34,7 @@ public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integ
|
||||
this.inventory = entity.getInventory();
|
||||
if (this.testClearGrid() || entity.isCreative()) {
|
||||
this.stackedContents.clear();
|
||||
+ this.stackedContents.initialize(recipe.value()); // Paper - Improve exact choice recipe ingredients
|
||||
entity.getInventory().fillStackedContents(this.stackedContents);
|
||||
this.menu.fillCraftSlotsStackedContents(this.stackedContents);
|
||||
if (this.stackedContents.canCraft((Recipe<?>)recipe.value(), null)) {
|
||||
@@ -80,7 +81,7 @@ public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integ
|
||||
int l = k;
|
||||
|
||||
for (int m : intList) {
|
||||
- int n = StackedContents.fromStackingIndex(m).getMaxStackSize();
|
||||
+ int n = StackedContents.maxStackSizeFromStackingIndex(m, this.stackedContents); // Paper - Improve exact choice recipe ingredients
|
||||
if (n < l) {
|
||||
l = n;
|
||||
}
|
||||
@@ -96,10 +97,21 @@ public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integ
|
||||
@Override
|
||||
public void addItemToSlot(Iterator<Integer> inputs, int slot, int amount, int gridX, int gridY) {
|
||||
Slot slot2 = this.menu.getSlot(slot);
|
||||
- ItemStack itemStack = StackedContents.fromStackingIndex(inputs.next());
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
+ final int itemId = inputs.next();
|
||||
+ ItemStack itemStack = null;
|
||||
+ boolean isExact = false;
|
||||
+ if (this.stackedContents.extrasMap != null && itemId >= net.minecraft.core.registries.BuiltInRegistries.ITEM.size()) {
|
||||
+ itemStack = StackedContents.fromStackingIndexExtras(itemId, this.stackedContents.extrasMap).copy();
|
||||
+ isExact = true;
|
||||
+ }
|
||||
+ if (itemStack == null) {
|
||||
+ itemStack = StackedContents.fromStackingIndex(itemId);
|
||||
+ }
|
||||
+ // Paper end - Improve exact choice recipe ingredients
|
||||
if (!itemStack.isEmpty()) {
|
||||
for (int i = 0; i < amount; i++) {
|
||||
- this.moveItemToGrid(slot2, itemStack);
|
||||
+ this.moveItemToGrid(slot2, itemStack, isExact); // Paper - Improve exact choice recipe ingredients
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,8 +140,14 @@ public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integ
|
||||
return i;
|
||||
}
|
||||
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Improve exact choice recipe ingredients
|
||||
protected void moveItemToGrid(Slot slot, ItemStack stack) {
|
||||
- int i = this.inventory.findSlotMatchingUnusedItem(stack);
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
+ this.moveItemToGrid(slot, stack, false);
|
||||
+ }
|
||||
+ protected void moveItemToGrid(Slot slot, ItemStack stack, final boolean isExact) {
|
||||
+ int i = isExact ? this.inventory.findSlotMatchingItem(stack) : this.inventory.findSlotMatchingUnusedItem(stack);
|
||||
+ // Paper end - Improve exact choice recipe ingredients
|
||||
if (i != -1) {
|
||||
ItemStack itemStack = this.inventory.getItem(i);
|
||||
if (!itemStack.isEmpty()) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/StackedContents.java b/src/main/java/net/minecraft/world/entity/player/StackedContents.java
|
||||
index a3a7bfaf5d21a50410017c8d17484ef5a409d68a..33e493874cb8cecd820e80f2c15e6f654bc64b02 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/StackedContents.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/StackedContents.java
|
||||
@@ -21,8 +21,10 @@ import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
public class StackedContents {
|
||||
private static final int EMPTY = 0;
|
||||
public final Int2IntMap contents = new Int2IntOpenHashMap();
|
||||
+ @Nullable public io.papermc.paper.inventory.recipe.StackedContentsExtraMap extrasMap = null; // Paper - Improve exact choice recipe ingredients
|
||||
|
||||
public void accountSimpleStack(ItemStack stack) {
|
||||
+ if (this.extrasMap != null && stack.hasTag() && this.extrasMap.accountStack(stack, Math.min(64, stack.getCount()))) return; // Paper - Improve exact choice recipe ingredients; max of 64 due to accountStack method below
|
||||
if (!stack.isDamaged() && !stack.isEnchanted() && !stack.hasCustomHoverName()) {
|
||||
this.accountStack(stack);
|
||||
}
|
||||
@@ -36,6 +38,7 @@ public class StackedContents {
|
||||
if (!stack.isEmpty()) {
|
||||
int i = getStackingIndex(stack);
|
||||
int j = Math.min(maxCount, stack.getCount());
|
||||
+ if (this.extrasMap != null && stack.hasTag() && this.extrasMap.accountStack(stack, j)) return; // Paper - Improve exact choice recipe ingredients; if an exact ingredient, don't include it
|
||||
this.put(i, j);
|
||||
}
|
||||
}
|
||||
@@ -82,6 +85,23 @@ public class StackedContents {
|
||||
return itemId == 0 ? ItemStack.EMPTY : new ItemStack(Item.byId(itemId));
|
||||
}
|
||||
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
+ public void initialize(final Recipe<?> recipe) {
|
||||
+ this.extrasMap = new io.papermc.paper.inventory.recipe.StackedContentsExtraMap(this, recipe);
|
||||
+ }
|
||||
+
|
||||
+ public static int maxStackSizeFromStackingIndex(final int itemId, @Nullable final StackedContents contents) {
|
||||
+ if (contents != null && contents.extrasMap != null && itemId >= BuiltInRegistries.ITEM.size()) {
|
||||
+ return fromStackingIndexExtras(itemId, contents.extrasMap).getMaxStackSize();
|
||||
+ }
|
||||
+ return fromStackingIndex(itemId).getMaxStackSize();
|
||||
+ }
|
||||
+
|
||||
+ public static ItemStack fromStackingIndexExtras(final int itemId, final io.papermc.paper.inventory.recipe.StackedContentsExtraMap extrasMap) {
|
||||
+ return extrasMap.getById(itemId).copy();
|
||||
+ }
|
||||
+ // Paper end - Improve exact choice recipe ingredients
|
||||
+
|
||||
public void clear() {
|
||||
this.contents.clear();
|
||||
}
|
||||
@@ -105,7 +125,7 @@ public class StackedContents {
|
||||
this.data = new BitSet(this.ingredientCount + this.itemCount + this.ingredientCount + this.ingredientCount * this.itemCount);
|
||||
|
||||
for (int i = 0; i < this.ingredients.size(); i++) {
|
||||
- IntList intList = this.ingredients.get(i).getStackingIds();
|
||||
+ IntList intList = this.getStackingIds(this.ingredients.get(i)); // Paper - Improve exact choice recipe ingredients
|
||||
|
||||
for (int j = 0; j < this.itemCount; j++) {
|
||||
if (intList.contains(this.items[j])) {
|
||||
@@ -168,7 +188,7 @@ public class StackedContents {
|
||||
IntCollection intCollection = new IntAVLTreeSet();
|
||||
|
||||
for (Ingredient ingredient : this.ingredients) {
|
||||
- intCollection.addAll(ingredient.getStackingIds());
|
||||
+ intCollection.addAll(this.getStackingIds(ingredient)); // Paper - Improve exact choice recipe ingredients
|
||||
}
|
||||
|
||||
IntIterator intIterator = intCollection.iterator();
|
||||
@@ -297,7 +317,7 @@ public class StackedContents {
|
||||
for (Ingredient ingredient : this.ingredients) {
|
||||
int j = 0;
|
||||
|
||||
- for (int k : ingredient.getStackingIds()) {
|
||||
+ for (int k : this.getStackingIds(ingredient)) { // Paper - Improve exact choice recipe ingredients
|
||||
j = Math.max(j, StackedContents.this.contents.get(k));
|
||||
}
|
||||
|
||||
@@ -308,5 +328,17 @@ public class StackedContents {
|
||||
|
||||
return i;
|
||||
}
|
||||
+
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
+ private IntList getStackingIds(final Ingredient ingredient) {
|
||||
+ if (StackedContents.this.extrasMap != null) {
|
||||
+ final IntList ids = StackedContents.this.extrasMap.extraStackingIds.get(ingredient);
|
||||
+ if (ids != null) {
|
||||
+ return ids;
|
||||
+ }
|
||||
+ }
|
||||
+ return ingredient.getStackingIds();
|
||||
+ }
|
||||
+ // Paper end - Improve exact choice recipe ingredients
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java b/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java
|
||||
index 7fe2389df3f033da60ec246937f67662355d3715..2a99d6b9c5c0bed7c971303cff82f84303184bca 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java
|
||||
@@ -6,7 +6,7 @@ import net.minecraft.world.Container;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
-public abstract class AbstractCookingRecipe implements Recipe<Container> {
|
||||
+public abstract class AbstractCookingRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<Container> implements Recipe<Container> { // Paper - improve exact recipe choices
|
||||
protected final RecipeType<?> type;
|
||||
protected final CookingBookCategory category;
|
||||
protected final String group;
|
||||
@@ -25,6 +25,7 @@ public abstract class AbstractCookingRecipe implements Recipe<Container> {
|
||||
this.result = result;
|
||||
this.experience = experience;
|
||||
this.cookingTime = cookingTime;
|
||||
+ this.checkExactIngredients(); // Paper - improve exact recipe choices
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/world/item/crafting/Recipe.java b/src/main/java/net/minecraft/world/item/crafting/Recipe.java
|
||||
index 8b631e457f783e55b7c37dd915b699912a9c5b49..e2d6c8ed586ef429cc712139e501df696ed10f6e 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/crafting/Recipe.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/crafting/Recipe.java
|
||||
@@ -69,4 +69,10 @@ public interface Recipe<C extends Container> {
|
||||
}
|
||||
|
||||
org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id); // CraftBukkit
|
||||
+
|
||||
+ // Paper start - improved exact choice recipes
|
||||
+ default boolean hasExactIngredients() {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java
|
||||
index 201897bbde809699b53617e09703f5b22bbbe938..d772cf80fa3831e1c79d601ea09a073da089e2c5 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java
|
||||
@@ -17,7 +17,7 @@ import org.bukkit.craftbukkit.inventory.CraftShapedRecipe;
|
||||
import org.bukkit.inventory.RecipeChoice;
|
||||
// CraftBukkit end
|
||||
|
||||
-public class ShapedRecipe implements CraftingRecipe {
|
||||
+public class ShapedRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<CraftingContainer> implements CraftingRecipe { // Paper - improve exact recipe choices
|
||||
|
||||
final ShapedRecipePattern pattern;
|
||||
final ItemStack result;
|
||||
@@ -31,6 +31,7 @@ public class ShapedRecipe implements CraftingRecipe {
|
||||
this.pattern = raw;
|
||||
this.result = result;
|
||||
this.showNotification = showNotification;
|
||||
+ this.checkExactIngredients(); // Paper - improve exact recipe choices
|
||||
}
|
||||
|
||||
public ShapedRecipe(String group, CraftingBookCategory category, ShapedRecipePattern raw, ItemStack result) {
|
||||
diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
index 870e07140d835feaa55808101722d4547d5021d0..27b0a79f7a7c47047216aae42944bac2a2151181 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
@@ -20,7 +20,7 @@ import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe;
|
||||
// CraftBukkit end
|
||||
|
||||
-public class ShapelessRecipe implements CraftingRecipe {
|
||||
+public class ShapelessRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<CraftingContainer> implements CraftingRecipe { // Paper - improve exact recipe choices
|
||||
|
||||
final String group;
|
||||
final CraftingBookCategory category;
|
||||
@@ -32,6 +32,7 @@ public class ShapelessRecipe implements CraftingRecipe {
|
||||
this.category = category;
|
||||
this.result = result;
|
||||
this.ingredients = ingredients;
|
||||
+ this.checkExactIngredients(); // Paper - improve exact recipe choices
|
||||
}
|
||||
|
||||
// CraftBukkit start
|
||||
@@ -77,6 +78,7 @@ public class ShapelessRecipe implements CraftingRecipe {
|
||||
|
||||
public boolean matches(CraftingContainer inventory, Level world) {
|
||||
StackedContents autorecipestackmanager = new StackedContents();
|
||||
+ autorecipestackmanager.initialize(this); // Paper - better exact choice recipes
|
||||
int i = 0;
|
||||
|
||||
for (int j = 0; j < inventory.getContainerSize(); ++j) {
|
|
@ -1,56 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 27 Feb 2019 22:18:40 -0500
|
||||
Subject: [PATCH] Limit Client Sign length more
|
||||
|
||||
modified clients can send more data from the client
|
||||
to the server and it would get stored on the sign as sent.
|
||||
|
||||
Mojang has a limit of 384 which is much higher than reasonable.
|
||||
|
||||
the client can barely render around 16 characters as-is, but formatting
|
||||
codes can get it to be more than 16 actual length.
|
||||
|
||||
Set a limit of 80 which should give an average of 16 characters 2
|
||||
sets of legacy formatting codes which should be plenty for all uses.
|
||||
|
||||
This does not strip any existing data from the NBT as plugins
|
||||
may use this for storing data out of the rendered area.
|
||||
|
||||
it only impacts data sent from the client.
|
||||
|
||||
Set -DPaper.maxSignLength=XX to change limit or -1 to disable
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 9e7598a0cc3965e382ba13d7fd700585a4884a97..6d540917d0d4f4787e9abc8c80fd797b2ec1656f 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -290,6 +290,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
private final MessageSignatureCache messageSignatureCache = MessageSignatureCache.createDefault();
|
||||
private final FutureChain chatMessageChain;
|
||||
private boolean waitingForSwitchToConfig;
|
||||
+ private static final int MAX_SIGN_LINE_LENGTH = Integer.getInteger("Paper.maxSignLength", 80); // Paper - Limit client sign length
|
||||
|
||||
public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie clientData) {
|
||||
super(server, connection, clientData, player); // CraftBukkit
|
||||
@@ -3059,7 +3060,19 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
@Override
|
||||
public void handleSignUpdate(ServerboundSignUpdatePacket packet) {
|
||||
- List<String> list = (List) Stream.of(packet.getLines()).map(ChatFormatting::stripFormatting).collect(Collectors.toList());
|
||||
+ // Paper start - Limit client sign length
|
||||
+ String[] lines = packet.getLines();
|
||||
+ for (int i = 0; i < lines.length; ++i) {
|
||||
+ if (MAX_SIGN_LINE_LENGTH > 0 && lines[i].length() > MAX_SIGN_LINE_LENGTH) {
|
||||
+ // This handles multibyte characters as 1
|
||||
+ int offset = lines[i].codePoints().limit(MAX_SIGN_LINE_LENGTH).map(Character::charCount).sum();
|
||||
+ if (offset < lines[i].length()) {
|
||||
+ lines[i] = lines[i].substring(0, offset); // this will break any filtering, but filtering is NYI as of 1.17
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ List<String> list = (List) Stream.of(lines).map(ChatFormatting::stripFormatting).collect(Collectors.toList());
|
||||
+ // Paper end - Limit client sign length
|
||||
|
||||
this.filterTextPacket(list).thenAcceptAsync((list1) -> {
|
||||
this.updateSignText(packet, list1);
|
|
@ -1,18 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
|
||||
Date: Wed, 13 Mar 2019 20:08:09 +0200
|
||||
Subject: [PATCH] Call WhitelistToggleEvent when whitelist is toggled
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 2a0d3319899f0b3f38135e25306b87b1974b3d83..28b81e29be07902ad4d04aeb18bffd49757c3029 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -1158,6 +1158,7 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void setUsingWhiteList(boolean whitelistEnabled) {
|
||||
+ new com.destroystokyo.paper.event.server.WhitelistToggleEvent(whitelistEnabled).callEvent(); // Paper - WhitelistToggleEvent
|
||||
this.doWhiteList = whitelistEnabled;
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 24 Mar 2019 00:24:52 -0400
|
||||
Subject: [PATCH] Entity#getEntitySpawnReason
|
||||
|
||||
Allows you to return the SpawnReason for why an Entity Spawned
|
||||
|
||||
Pre existing entities will return NATURAL if it was a non
|
||||
persistenting Living Entity, SPAWNER for spawners,
|
||||
or DEFAULT since data was not stored.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/commands/SummonCommand.java b/src/main/java/net/minecraft/server/commands/SummonCommand.java
|
||||
index 2eddeb8d5239bbfeefbf4d3bd363f1ad083299b6..e2b44b8ddb8afc6e1f7dddadb434c2268f284809 100644
|
||||
--- a/src/main/java/net/minecraft/server/commands/SummonCommand.java
|
||||
+++ b/src/main/java/net/minecraft/server/commands/SummonCommand.java
|
||||
@@ -57,6 +57,7 @@ public class SummonCommand {
|
||||
ServerLevel worldserver = source.getLevel();
|
||||
Entity entity = EntityType.loadEntityRecursive(nbttagcompound1, worldserver, (entity1) -> {
|
||||
entity1.moveTo(pos.x, pos.y, pos.z, entity1.getYRot(), entity1.getXRot());
|
||||
+ entity1.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND; // Paper - Entity#getEntitySpawnReason
|
||||
return entity1;
|
||||
});
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0811a2e87192b46c39f54c26ce0e56fc6e9d87e5..57f129651778d6c20c695bf7b3a8b4d40c402a20 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1203,6 +1203,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
return true;
|
||||
}
|
||||
// Paper end - extra debug info
|
||||
+ if (entity.spawnReason == null) entity.spawnReason = spawnReason; // Paper - Entity#getEntitySpawnReason
|
||||
if (entity.isRemoved()) {
|
||||
// WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit
|
||||
return false;
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 28b81e29be07902ad4d04aeb18bffd49757c3029..bc440f9a239d3935bf6837edf815d4fdc6093655 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -224,6 +224,11 @@ public abstract class PlayerList {
|
||||
worldserver1 = worldserver;
|
||||
}
|
||||
|
||||
+ // Paper start - Entity#getEntitySpawnReason
|
||||
+ if (nbttagcompound == null) {
|
||||
+ player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login
|
||||
+ }
|
||||
+ // Paper end - Entity#getEntitySpawnReason
|
||||
player.setServerLevel(worldserver1);
|
||||
String s1 = connection.getLoggableAddress(this.server.logIPs());
|
||||
|
||||
@@ -355,7 +360,7 @@ public abstract class PlayerList {
|
||||
// CraftBukkit start
|
||||
ServerLevel finalWorldServer = worldserver1;
|
||||
Entity entity = EntityType.loadEntityRecursive(nbttagcompound1.getCompound("Entity"), finalWorldServer, (entity1) -> {
|
||||
- return !finalWorldServer.addWithUUID(entity1) ? null : entity1;
|
||||
+ return !finalWorldServer.addWithUUID(entity1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT) ? null : entity1; // Paper - Entity#getEntitySpawnReason
|
||||
// CraftBukkit end
|
||||
});
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index f746829f1e94ee58821e56ec4192269add00395b..257be4dd3f38c089dd970b9ac6f292b4f010a01c 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -238,6 +238,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
|
||||
}
|
||||
}
|
||||
// Paper end - Share random for entities to make them more random
|
||||
+ public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason
|
||||
|
||||
public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper
|
||||
private CraftEntity bukkitEntity;
|
||||
@@ -2178,6 +2179,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
|
||||
}
|
||||
nbttagcompound.put("Paper.Origin", this.newDoubleList(origin.getX(), origin.getY(), origin.getZ()));
|
||||
}
|
||||
+ if (spawnReason != null) {
|
||||
+ nbttagcompound.putString("Paper.SpawnReason", spawnReason.name());
|
||||
+ }
|
||||
// Save entity's from mob spawner status
|
||||
if (spawnedViaMobSpawner) {
|
||||
nbttagcompound.putBoolean("Paper.FromMobSpawner", true);
|
||||
@@ -2324,6 +2328,26 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
|
||||
}
|
||||
|
||||
spawnedViaMobSpawner = nbt.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status
|
||||
+ if (nbt.contains("Paper.SpawnReason")) {
|
||||
+ String spawnReasonName = nbt.getString("Paper.SpawnReason");
|
||||
+ try {
|
||||
+ spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.valueOf(spawnReasonName);
|
||||
+ } catch (Exception ignored) {
|
||||
+ LOGGER.error("Unknown SpawnReason " + spawnReasonName + " for " + this);
|
||||
+ }
|
||||
+ }
|
||||
+ if (spawnReason == null) {
|
||||
+ if (spawnedViaMobSpawner) {
|
||||
+ spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER;
|
||||
+ } else if (this instanceof Mob && (this instanceof net.minecraft.world.entity.animal.Animal || this instanceof net.minecraft.world.entity.animal.AbstractFish) && !((Mob) this).removeWhenFarAway(0.0)) {
|
||||
+ if (!nbt.getBoolean("PersistenceRequired")) {
|
||||
+ spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if (spawnReason == null) {
|
||||
+ spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT;
|
||||
+ }
|
||||
// Paper end
|
||||
|
||||
} catch (Throwable throwable) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
index cae8c508972d771ad96228ace8a7e6cbc34d5489..3184f73ce799cc5202d2129be736e2fed9a3b8e3 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -182,6 +182,7 @@ public abstract class BaseSpawner {
|
||||
}
|
||||
|
||||
entity.spawnedViaMobSpawner = true; // Paper
|
||||
+ entity.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER; // Paper - Entity#getEntitySpawnReason
|
||||
flag = true; // Paper
|
||||
// CraftBukkit start
|
||||
if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, pos).isCancelled()) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java
|
||||
index 41fa4258fbdd2f887383b9d3def10466557c406c..d71a9fb54269f7c7e251e0e3bdd8b5a072af5201 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java
|
||||
@@ -181,7 +181,7 @@ public class SculkShriekerBlockEntity extends BlockEntity implements GameEventLi
|
||||
|
||||
private boolean trySummonWarden(ServerLevel world) {
|
||||
return this.warningLevel >= 4
|
||||
- && SpawnUtil.trySpawnMob(EntityType.WARDEN, MobSpawnType.TRIGGERED, world, this.getBlockPos(), 20, 5, 6, SpawnUtil.Strategy.ON_TOP_OF_COLLIDER)
|
||||
+ && SpawnUtil.trySpawnMob(EntityType.WARDEN, MobSpawnType.TRIGGERED, world, this.getBlockPos(), 20, 5, 6, SpawnUtil.Strategy.ON_TOP_OF_COLLIDER, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL, null) // Paper - Entity#getEntitySpawnReason
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index 6fddbcec673564ac531a852f631f6acc460accbd..9ed122efb2b380bb2c1b50fdfe75bf3e679c9c6e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -991,4 +991,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
return this.getHandle().spawnedViaMobSpawner;
|
||||
}
|
||||
// Paper end - Entity#fromMobSpawner
|
||||
+
|
||||
+ // Paper start - entity spawn reason API
|
||||
+ @Override
|
||||
+ public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason getEntitySpawnReason() {
|
||||
+ return getHandle().spawnReason;
|
||||
+ }
|
||||
+ // Paper end - entity spawn reason API
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
|
||||
Date: Sun, 17 Mar 2019 21:46:56 +0200
|
||||
Subject: [PATCH] Fire event on GS4 query
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java
|
||||
index f4596e2b82f4bc385b7460f143207c458f1f0162..0e0867d7add9a024bbe9471f8ff92bbb25996a3d 100644
|
||||
--- a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java
|
||||
+++ b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java
|
||||
@@ -106,13 +106,32 @@ public class QueryThreadGs4 extends GenericThread {
|
||||
NetworkDataOutputStream networkDataOutputStream = new NetworkDataOutputStream(1460);
|
||||
networkDataOutputStream.write(0);
|
||||
networkDataOutputStream.writeBytes(this.getIdentBytes(packet.getSocketAddress()));
|
||||
- networkDataOutputStream.writeString(this.serverName);
|
||||
+
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType =
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.BASIC;
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder()
|
||||
+ .motd(this.serverName)
|
||||
+ .map(this.worldName)
|
||||
+ .currentPlayers(this.serverInterface.getPlayerCount())
|
||||
+ .maxPlayers(this.maxPlayers)
|
||||
+ .port(this.serverPort)
|
||||
+ .hostname(this.hostIp)
|
||||
+ .gameVersion(this.serverInterface.getServerVersion())
|
||||
+ .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion())
|
||||
+ .build();
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent =
|
||||
+ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, packet.getAddress(), queryResponse);
|
||||
+ queryEvent.callEvent();
|
||||
+ queryResponse = queryEvent.getResponse();
|
||||
+
|
||||
+ networkDataOutputStream.writeString(queryResponse.getMotd());
|
||||
networkDataOutputStream.writeString("SMP");
|
||||
- networkDataOutputStream.writeString(this.worldName);
|
||||
- networkDataOutputStream.writeString(Integer.toString(this.serverInterface.getPlayerCount()));
|
||||
- networkDataOutputStream.writeString(Integer.toString(this.maxPlayers));
|
||||
- networkDataOutputStream.writeShort((short)this.serverPort);
|
||||
- networkDataOutputStream.writeString(this.hostIp);
|
||||
+ networkDataOutputStream.writeString(queryResponse.getMap());
|
||||
+ networkDataOutputStream.writeString(Integer.toString(queryResponse.getCurrentPlayers()));
|
||||
+ networkDataOutputStream.writeString(Integer.toString(queryResponse.getMaxPlayers()));
|
||||
+ networkDataOutputStream.writeShort((short) queryResponse.getPort());
|
||||
+ networkDataOutputStream.writeString(queryResponse.getHostname());
|
||||
+ // Paper end
|
||||
this.sendTo(networkDataOutputStream.toByteArray(), packet);
|
||||
LOGGER.debug("Status [{}]", socketAddress);
|
||||
}
|
||||
@@ -147,31 +166,75 @@ public class QueryThreadGs4 extends GenericThread {
|
||||
this.rulesResponse.writeString("splitnum");
|
||||
this.rulesResponse.write(128);
|
||||
this.rulesResponse.write(0);
|
||||
+ // Paper start
|
||||
+ // Pack plugins
|
||||
+ java.util.List<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> plugins = java.util.Collections.emptyList();
|
||||
+ org.bukkit.plugin.Plugin[] bukkitPlugins;
|
||||
+ if (((net.minecraft.server.dedicated.DedicatedServer) this.serverInterface).server.getQueryPlugins() && (bukkitPlugins = org.bukkit.Bukkit.getPluginManager().getPlugins()).length > 0) {
|
||||
+ plugins = java.util.stream.Stream.of(bukkitPlugins)
|
||||
+ .map(plugin -> com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation.of(plugin.getName(), plugin.getDescription().getVersion()))
|
||||
+ .collect(java.util.stream.Collectors.toList());
|
||||
+ }
|
||||
+
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder()
|
||||
+ .motd(this.serverName)
|
||||
+ .map(this.worldName)
|
||||
+ .currentPlayers(this.serverInterface.getPlayerCount())
|
||||
+ .maxPlayers(this.maxPlayers)
|
||||
+ .port(this.serverPort)
|
||||
+ .hostname(this.hostIp)
|
||||
+ .plugins(plugins)
|
||||
+ .players(this.serverInterface.getPlayerNames())
|
||||
+ .gameVersion(this.serverInterface.getServerVersion())
|
||||
+ .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion())
|
||||
+ .build();
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType =
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.FULL;
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent =
|
||||
+ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, packet.getAddress(), queryResponse);
|
||||
+ queryEvent.callEvent();
|
||||
+ queryResponse = queryEvent.getResponse();
|
||||
this.rulesResponse.writeString("hostname");
|
||||
- this.rulesResponse.writeString(this.serverName);
|
||||
+ this.rulesResponse.writeString(queryResponse.getMotd());
|
||||
this.rulesResponse.writeString("gametype");
|
||||
this.rulesResponse.writeString("SMP");
|
||||
this.rulesResponse.writeString("game_id");
|
||||
this.rulesResponse.writeString("MINECRAFT");
|
||||
this.rulesResponse.writeString("version");
|
||||
- this.rulesResponse.writeString(this.serverInterface.getServerVersion());
|
||||
+ this.rulesResponse.writeString(queryResponse.getGameVersion());
|
||||
this.rulesResponse.writeString("plugins");
|
||||
- this.rulesResponse.writeString(this.serverInterface.getPluginNames());
|
||||
+ java.lang.StringBuilder pluginsString = new java.lang.StringBuilder();
|
||||
+ pluginsString.append(queryResponse.getServerVersion());
|
||||
+ if (!queryResponse.getPlugins().isEmpty()) {
|
||||
+ pluginsString.append(": ");
|
||||
+ java.util.Iterator<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> iter = queryResponse.getPlugins().iterator();
|
||||
+ while (iter.hasNext()) {
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation info = iter.next();
|
||||
+ pluginsString.append(info.getName());
|
||||
+ if (info.getVersion() != null) {
|
||||
+ pluginsString.append(' ').append(info.getVersion().replace(";", ","));
|
||||
+ }
|
||||
+ if (iter.hasNext()) {
|
||||
+ pluginsString.append(';').append(' ');
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ this.rulesResponse.writeString(pluginsString.toString());
|
||||
this.rulesResponse.writeString("map");
|
||||
- this.rulesResponse.writeString(this.worldName);
|
||||
+ this.rulesResponse.writeString(queryResponse.getMap());
|
||||
this.rulesResponse.writeString("numplayers");
|
||||
- this.rulesResponse.writeString(this.serverInterface.getPlayerCount() + "");
|
||||
+ this.rulesResponse.writeString(Integer.toString(queryResponse.getCurrentPlayers()));
|
||||
this.rulesResponse.writeString("maxplayers");
|
||||
- this.rulesResponse.writeString(this.maxPlayers + "");
|
||||
+ this.rulesResponse.writeString(Integer.toString(queryResponse.getMaxPlayers()));
|
||||
this.rulesResponse.writeString("hostport");
|
||||
- this.rulesResponse.writeString(this.serverPort + "");
|
||||
+ this.rulesResponse.writeString(Integer.toString(queryResponse.getPort()));
|
||||
this.rulesResponse.writeString("hostip");
|
||||
- this.rulesResponse.writeString(this.hostIp);
|
||||
+ this.rulesResponse.writeString(queryResponse.getHostname());
|
||||
this.rulesResponse.write(0);
|
||||
this.rulesResponse.write(1);
|
||||
this.rulesResponse.writeString("player_");
|
||||
this.rulesResponse.write(0);
|
||||
- String[] strings = this.serverInterface.getPlayerNames();
|
||||
+ String[] strings = queryResponse.getPlayers().toArray(String[]::new);
|
||||
|
||||
for (String string : strings) {
|
||||
this.rulesResponse.writeString(string);
|
|
@ -1,48 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MisterVector <whizkid3000@hotmail.com>
|
||||
Date: Fri, 26 Oct 2018 21:31:00 -0700
|
||||
Subject: [PATCH] Add PlayerPostRespawnEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index bc440f9a239d3935bf6837edf815d4fdc6093655..6bd83549e2ff84b1bc993ef2be79a336ced28f67 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -752,9 +752,14 @@ public abstract class PlayerList {
|
||||
|
||||
boolean flag2 = false;
|
||||
|
||||
+ // Paper start - Add PlayerPostRespawnEvent
|
||||
+ boolean isBedSpawn = false;
|
||||
+ boolean isRespawn = false;
|
||||
+ // Paper end - Add PlayerPostRespawnEvent
|
||||
+
|
||||
// CraftBukkit start - fire PlayerRespawnEvent
|
||||
if (location == null) {
|
||||
- boolean isBedSpawn = false;
|
||||
+ // boolean isBedSpawn = false; // Paper - Add PlayerPostRespawnEvent; moved up
|
||||
ServerLevel worldserver1 = this.server.getLevel(entityplayer.getRespawnDimension());
|
||||
if (worldserver1 != null) {
|
||||
Optional optional;
|
||||
@@ -806,6 +811,7 @@ public abstract class PlayerList {
|
||||
|
||||
location = respawnEvent.getRespawnLocation();
|
||||
if (!flag) entityplayer.reset(); // SPIGOT-4785
|
||||
+ isRespawn = true; // Paper - Add PlayerPostRespawnEvent
|
||||
} else {
|
||||
location.setWorld(worldserver.getWorld());
|
||||
}
|
||||
@@ -864,6 +870,13 @@ public abstract class PlayerList {
|
||||
if (entityplayer.connection.isDisconnected()) {
|
||||
this.save(entityplayer);
|
||||
}
|
||||
+
|
||||
+ // Paper start - Add PlayerPostRespawnEvent
|
||||
+ if (isRespawn) {
|
||||
+ cserver.getPluginManager().callEvent(new com.destroystokyo.paper.event.player.PlayerPostRespawnEvent(entityplayer.getBukkitEntity(), location, isBedSpawn));
|
||||
+ }
|
||||
+ // Paper end - Add PlayerPostRespawnEvent
|
||||
+
|
||||
// CraftBukkit end
|
||||
return entityplayer1;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 24 Mar 2019 18:09:20 -0400
|
||||
Subject: [PATCH] don't go below 0 for pickupDelay, breaks picking up items
|
||||
|
||||
vanilla checks for == 0
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index d568726f80308e29bcfa3714728096d7d0aa822c..bfbbb9382cf483a23acf35c17250f6f9223f7507 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -141,6 +141,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
// CraftBukkit start - Use wall time for pickup and despawn timers
|
||||
int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
|
||||
if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks;
|
||||
+ this.pickupDelay = Math.max(0, this.pickupDelay); // Paper - don't go below 0
|
||||
if (this.age != -32768) this.age += elapsedTicks;
|
||||
this.lastTick = MinecraftServer.currentTick;
|
||||
// CraftBukkit end
|
||||
@@ -227,6 +228,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
// CraftBukkit start - Use wall time for pickup and despawn timers
|
||||
int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
|
||||
if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks;
|
||||
+ this.pickupDelay = Math.max(0, this.pickupDelay); // Paper - don't go below 0
|
||||
if (this.age != -32768) this.age += elapsedTicks;
|
||||
this.lastTick = MinecraftServer.currentTick;
|
||||
// CraftBukkit end
|
|
@ -1,31 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 27 Mar 2019 22:48:45 -0400
|
||||
Subject: [PATCH] Server Tick Events
|
||||
|
||||
Fires event at start and end of a server tick
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 3d59c9f256f00c213af33c35cd6471a78b97c290..176378ddbf21d758694e8e624cc6c555c78e0fab 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1357,6 +1357,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
});
|
||||
isOversleep = false;MinecraftTimings.serverOversleep.stopTiming();
|
||||
// Paper end
|
||||
+ new com.destroystokyo.paper.event.server.ServerTickStartEvent(this.tickCount+1).callEvent(); // Paper - Server Tick Events
|
||||
|
||||
++this.tickCount;
|
||||
this.tickRateManager.tick();
|
||||
@@ -1383,6 +1384,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.runAllTasks();
|
||||
}
|
||||
// Paper end
|
||||
+ // Paper start - Server Tick Events
|
||||
+ long endTime = System.nanoTime();
|
||||
+ long remaining = (TICK_TIME - (endTime - lastTick)) - catchupTime;
|
||||
+ new com.destroystokyo.paper.event.server.ServerTickEndEvent(this.tickCount, ((double)(endTime - lastTick) / 1000000D), remaining).callEvent();
|
||||
+ // Paper end - Server Tick Events
|
||||
this.profiler.push("tallying");
|
||||
long j = Util.getNanos() - i;
|
||||
int k = this.tickCount % 100;
|
|
@ -1,77 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 27 Mar 2019 23:01:33 -0400
|
||||
Subject: [PATCH] PlayerDeathEvent#getItemsToKeep
|
||||
|
||||
Exposes a mutable array on items a player should keep on death
|
||||
|
||||
Example Usage: https://gist.github.com/aikar/5bb202de6057a051a950ce1f29feb0b4
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.player.Inventory compartments
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 7433116ee68b92c86d1588296d521e5df49e5ac2..eb9668f94dbc36f3abc7d5c47c9b1b657aa94ced 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -813,6 +813,46 @@ public class ServerPlayer extends Player {
|
||||
});
|
||||
}
|
||||
|
||||
+ // Paper start - PlayerDeathEvent#getItemsToKeep
|
||||
+ private static void processKeep(org.bukkit.event.entity.PlayerDeathEvent event, NonNullList<ItemStack> inv) {
|
||||
+ List<org.bukkit.inventory.ItemStack> itemsToKeep = event.getItemsToKeep();
|
||||
+ if (inv == null) {
|
||||
+ // remainder of items left in toKeep - plugin added stuff on death that wasn't in the initial loot?
|
||||
+ if (!itemsToKeep.isEmpty()) {
|
||||
+ for (org.bukkit.inventory.ItemStack itemStack : itemsToKeep) {
|
||||
+ event.getEntity().getInventory().addItem(itemStack);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < inv.size(); ++i) {
|
||||
+ ItemStack item = inv.get(i);
|
||||
+ if (EnchantmentHelper.hasVanishingCurse(item) || itemsToKeep.isEmpty() || item.isEmpty()) {
|
||||
+ inv.set(i, ItemStack.EMPTY);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final org.bukkit.inventory.ItemStack bukkitStack = item.getBukkitStack();
|
||||
+ boolean keep = false;
|
||||
+ final Iterator<org.bukkit.inventory.ItemStack> iterator = itemsToKeep.iterator();
|
||||
+ while (iterator.hasNext()) {
|
||||
+ final org.bukkit.inventory.ItemStack itemStack = iterator.next();
|
||||
+ if (bukkitStack.equals(itemStack)) {
|
||||
+ iterator.remove();
|
||||
+ keep = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!keep) {
|
||||
+ inv.set(i, ItemStack.EMPTY);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - PlayerDeathEvent#getItemsToKeep
|
||||
+
|
||||
@Override
|
||||
public void die(DamageSource damageSource) {
|
||||
// this.gameEvent(GameEvent.ENTITY_DIE); // Paper - move below event cancellation check
|
||||
@@ -897,7 +937,12 @@ public class ServerPlayer extends Player {
|
||||
this.dropExperience();
|
||||
// we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory.
|
||||
if (!event.getKeepInventory()) {
|
||||
- this.getInventory().clearContent();
|
||||
+ // Paper start - PlayerDeathEvent#getItemsToKeep
|
||||
+ for (NonNullList<ItemStack> inv : this.getInventory().compartments) {
|
||||
+ processKeep(event, inv);
|
||||
+ }
|
||||
+ processKeep(event, null);
|
||||
+ // Paper end - PlayerDeathEvent#getItemsToKeep
|
||||
}
|
||||
|
||||
this.setCamera(this); // Remove spectated target
|
|
@ -1,30 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 6 Apr 2019 10:16:48 -0400
|
||||
Subject: [PATCH] Optimize Captured BlockEntity Lookup
|
||||
|
||||
upstream was doing a containsKey/get pattern, and always doing it at that.
|
||||
that scenario is only even valid if were in the middle of a block place.
|
||||
|
||||
Optimize to check if the captured list even has values in it, and also to
|
||||
just do a get call since the value can never be null.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 12809bc84aa07e724bebbc631199f352b7d7bbcb..6d5a0aa8f8cee0897a920c2abf18efc03cad2abb 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -911,9 +911,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
|
||||
@Nullable
|
||||
public BlockEntity getBlockEntity(BlockPos blockposition, boolean validate) {
|
||||
- if (this.capturedTileEntities.containsKey(blockposition)) {
|
||||
- return this.capturedTileEntities.get(blockposition);
|
||||
+ // Paper start - Perf: Optimize capturedTileEntities lookup
|
||||
+ net.minecraft.world.level.block.entity.BlockEntity blockEntity;
|
||||
+ if (!this.capturedTileEntities.isEmpty() && (blockEntity = this.capturedTileEntities.get(blockposition)) != null) {
|
||||
+ return blockEntity;
|
||||
}
|
||||
+ // Paper end - Perf: Optimize capturedTileEntities lookup
|
||||
// CraftBukkit end
|
||||
return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && Thread.currentThread() != this.thread ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE));
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Tue, 1 Jan 2019 02:22:01 -0800
|
||||
Subject: [PATCH] Add Heightmap API
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 18db1aa374495a214807c5eb3ccc0213fc7c6a47..4001a8c13ceed6037174bb81fd06d9758fa0336c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -229,6 +229,29 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
return CraftBlock.at(this.world, new BlockPos(x, y, z));
|
||||
}
|
||||
|
||||
+ // Paper start - Implement heightmap api
|
||||
+ @Override
|
||||
+ public int getHighestBlockYAt(final int x, final int z, final com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException {
|
||||
+ this.getChunkAt(x >> 4, z >> 4); // heightmap will ret 0 on unloaded areas
|
||||
+
|
||||
+ switch (heightmap) {
|
||||
+ case LIGHT_BLOCKING:
|
||||
+ throw new UnsupportedOperationException(); // TODO
|
||||
+ //return this.world.getHighestBlockY(HeightMap.Type.LIGHT_BLOCKING, x, z);
|
||||
+ case ANY:
|
||||
+ return this.world.getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.WORLD_SURFACE, x, z);
|
||||
+ case SOLID:
|
||||
+ return this.world.getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.OCEAN_FLOOR, x, z);
|
||||
+ case SOLID_OR_LIQUID:
|
||||
+ return this.world.getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING, x, z);
|
||||
+ case SOLID_OR_LIQUID_NO_LEAVES:
|
||||
+ return this.world.getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, x, z);
|
||||
+ default:
|
||||
+ throw new UnsupportedOperationException();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public Location getSpawnLocation() {
|
||||
BlockPos spawn = this.world.getSharedSpawnPos();
|
|
@ -1,103 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Fri, 19 Apr 2019 12:41:13 -0500
|
||||
Subject: [PATCH] Mob Spawner API Enhancements
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.level.BaseSpawner isNearPlayer(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)Z
|
||||
public net.minecraft.world.level.BaseSpawner delay(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)V
|
||||
public net.minecraft.world.level.BaseSpawner setNextSpawnData(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/SpawnData;)V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
index 3184f73ce799cc5202d2129be736e2fed9a3b8e3..b771f954f3fccd92e15196bf542e0d3703cfb71a 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -228,7 +228,13 @@ public abstract class BaseSpawner {
|
||||
}
|
||||
|
||||
public void load(@Nullable Level world, BlockPos pos, CompoundTag nbt) {
|
||||
+ // Paper start - use larger int if set
|
||||
+ if (nbt.contains("Paper.Delay")) {
|
||||
+ this.spawnDelay = nbt.getInt("Paper.Delay");
|
||||
+ } else {
|
||||
this.spawnDelay = nbt.getShort("Delay");
|
||||
+ }
|
||||
+ // Paper end
|
||||
boolean flag = nbt.contains("SpawnData", 10);
|
||||
|
||||
if (flag) {
|
||||
@@ -251,9 +257,15 @@ public abstract class BaseSpawner {
|
||||
this.spawnPotentials = SimpleWeightedRandomList.single(this.nextSpawnData != null ? this.nextSpawnData : new SpawnData());
|
||||
}
|
||||
|
||||
+ // Paper start - use ints if set
|
||||
+ if (nbt.contains("Paper.MinSpawnDelay", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) {
|
||||
+ this.minSpawnDelay = nbt.getInt("Paper.MinSpawnDelay");
|
||||
+ this.maxSpawnDelay = nbt.getInt("Paper.MaxSpawnDelay");
|
||||
+ this.spawnCount = nbt.getShort("SpawnCount");
|
||||
+ } else // Paper end
|
||||
if (nbt.contains("MinSpawnDelay", 99)) {
|
||||
- this.minSpawnDelay = nbt.getShort("MinSpawnDelay");
|
||||
- this.maxSpawnDelay = nbt.getShort("MaxSpawnDelay");
|
||||
+ this.minSpawnDelay = nbt.getInt("MinSpawnDelay"); // Paper - short -> int
|
||||
+ this.maxSpawnDelay = nbt.getInt("MaxSpawnDelay"); // Paper - short -> int
|
||||
this.spawnCount = nbt.getShort("SpawnCount");
|
||||
}
|
||||
|
||||
@@ -270,9 +282,20 @@ public abstract class BaseSpawner {
|
||||
}
|
||||
|
||||
public CompoundTag save(CompoundTag nbt) {
|
||||
- nbt.putShort("Delay", (short) this.spawnDelay);
|
||||
- nbt.putShort("MinSpawnDelay", (short) this.minSpawnDelay);
|
||||
- nbt.putShort("MaxSpawnDelay", (short) this.maxSpawnDelay);
|
||||
+ // Paper start
|
||||
+ if (spawnDelay > Short.MAX_VALUE) {
|
||||
+ nbt.putInt("Paper.Delay", this.spawnDelay);
|
||||
+ }
|
||||
+ nbt.putShort("Delay", (short) Math.min(Short.MAX_VALUE, this.spawnDelay));
|
||||
+
|
||||
+ if (minSpawnDelay > Short.MAX_VALUE || maxSpawnDelay > Short.MAX_VALUE) {
|
||||
+ nbt.putInt("Paper.MinSpawnDelay", this.minSpawnDelay);
|
||||
+ nbt.putInt("Paper.MaxSpawnDelay", this.maxSpawnDelay);
|
||||
+ }
|
||||
+
|
||||
+ nbt.putShort("MinSpawnDelay", (short) Math.min(Short.MAX_VALUE, this.minSpawnDelay));
|
||||
+ nbt.putShort("MaxSpawnDelay", (short) Math.min(Short.MAX_VALUE, this.maxSpawnDelay));
|
||||
+ // Paper end
|
||||
nbt.putShort("SpawnCount", (short) this.spawnCount);
|
||||
nbt.putShort("MaxNearbyEntities", (short) this.maxNearbyEntities);
|
||||
nbt.putShort("RequiredPlayerRange", (short) this.requiredPlayerRange);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java
|
||||
index 777241d3196a7984042967bc67fcf7429a1ddee7..0d39223d1eaa3fe7065eb9dc9f945ca965d3b43e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java
|
||||
@@ -226,4 +226,28 @@ public class CraftCreatureSpawner extends CraftBlockEntityState<SpawnerBlockEnti
|
||||
public CraftCreatureSpawner copy() {
|
||||
return new CraftCreatureSpawner(this);
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean isActivated() {
|
||||
+ this.requirePlaced();
|
||||
+ return this.getSnapshot().getSpawner().isNearPlayer(this.world.getHandle(), this.getPosition());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void resetTimer() {
|
||||
+ this.requirePlaced();
|
||||
+ this.getSnapshot().getSpawner().delay(this.world.getHandle(), this.getPosition());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSpawnedItem(org.bukkit.inventory.ItemStack itemStack) {
|
||||
+ Preconditions.checkArgument(itemStack != null && !itemStack.getType().isAir(), "spawners cannot spawn air");
|
||||
+ net.minecraft.world.item.ItemStack item = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(itemStack);
|
||||
+ net.minecraft.nbt.CompoundTag entity = new net.minecraft.nbt.CompoundTag();
|
||||
+ entity.putString("id", net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getKey(net.minecraft.world.entity.EntityType.ITEM).toString());
|
||||
+ entity.put("Item", item.save(new net.minecraft.nbt.CompoundTag()));
|
||||
+ this.getSnapshot().getSpawner().setNextSpawnData(this.isPlaced() ? this.world.getHandle() : null, this.getPosition(), new net.minecraft.world.level.SpawnData(entity, java.util.Optional.empty()));
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Fri, 10 May 2019 18:38:19 +0100
|
||||
Subject: [PATCH] Fix CB call to changed postToMainThread method
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
index d0f89a66734423ceea67fbeb99b0e72797f80e63..e69043316372d98b122ed3788fda79cdd36849e8 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
@@ -310,7 +310,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
|
||||
Objects.requireNonNull(this.connection);
|
||||
// CraftBukkit - Don't wait
|
||||
- minecraftserver.wrapRunnable(networkmanager::handleDisconnection);
|
||||
+ minecraftserver.scheduleOnMain(networkmanager::handleDisconnection); // Paper
|
||||
}
|
||||
|
||||
protected boolean isSingleplayerOwner() {
|
|
@ -1,20 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Phoenix616 <mail@moep.tv>
|
||||
Date: Sat, 27 Apr 2019 20:00:43 +0100
|
||||
Subject: [PATCH] Fix sounds when item frames are modified (MC-123450)
|
||||
|
||||
This also fixes the adding sound playing when the item frame direction is changed.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
index f90878e0449f39f66ae3a7036a65c374b36b7dbc..5c507b1160835fd4beb3b2d5b621250540545d4e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
@@ -326,7 +326,7 @@ public class ItemFrame extends HangingEntity {
|
||||
|
||||
this.onItemChanged(itemstack);
|
||||
this.getEntityData().set(ItemFrame.DATA_ITEM, itemstack);
|
||||
- if (!itemstack.isEmpty() && playSound) { // CraftBukkit
|
||||
+ if (!itemstack.isEmpty() && flag && playSound) { // CraftBukkit // Paper - only play sound when update flag is set
|
||||
this.playSound(this.getAddItemSound(), 1.0F, 1.0F);
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: simpleauthority <jacob@algorithmjunkie.com>
|
||||
Date: Tue, 28 May 2019 03:48:51 -0700
|
||||
Subject: [PATCH] Implement CraftBlockSoundGroup
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/block/CraftBlockSoundGroup.java b/src/main/java/com/destroystokyo/paper/block/CraftBlockSoundGroup.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..3913c407a3bfa7dfa4a5e374a5e792962fcdafe6
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/block/CraftBlockSoundGroup.java
|
||||
@@ -0,0 +1,39 @@
|
||||
+package com.destroystokyo.paper.block;
|
||||
+
|
||||
+import net.minecraft.world.level.block.SoundType;
|
||||
+import org.bukkit.Sound;
|
||||
+import org.bukkit.craftbukkit.CraftSound;
|
||||
+
|
||||
+@Deprecated(forRemoval = true)
|
||||
+public class CraftBlockSoundGroup implements BlockSoundGroup {
|
||||
+ private final SoundType soundEffectType;
|
||||
+
|
||||
+ public CraftBlockSoundGroup(SoundType soundEffectType) {
|
||||
+ this.soundEffectType = soundEffectType;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Sound getBreakSound() {
|
||||
+ return CraftSound.minecraftToBukkit(soundEffectType.getBreakSound());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Sound getStepSound() {
|
||||
+ return CraftSound.minecraftToBukkit(soundEffectType.getStepSound());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Sound getPlaceSound() {
|
||||
+ return CraftSound.minecraftToBukkit(soundEffectType.getPlaceSound());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Sound getHitSound() {
|
||||
+ return CraftSound.minecraftToBukkit(soundEffectType.getHitSound());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Sound getFallSound() {
|
||||
+ return CraftSound.minecraftToBukkit(soundEffectType.getFallSound());
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
index 013298c424025cd88f15d61e50d196f70fa4c58b..d4e14ac1514e2d8b87b4667a91c90eded3ba6636 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
@@ -622,4 +622,16 @@ public class CraftBlock implements Block {
|
||||
public String getTranslationKey() {
|
||||
return this.getNMS().getBlock().getDescriptionId();
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.block.BlockSoundGroup getSoundGroup() {
|
||||
+ return new com.destroystokyo.paper.block.CraftBlockSoundGroup(getNMS().getBlock().defaultBlockState().getSoundType());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.SoundGroup getBlockSoundGroup() {
|
||||
+ return org.bukkit.craftbukkit.CraftSoundGroup.getSoundGroup(this.getNMS().getSoundType());
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,220 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 13 Sep 2014 23:14:43 -0400
|
||||
Subject: [PATCH] Configurable Keep Spawn Loaded range per world
|
||||
|
||||
This lets you disable it for some worlds and lower it for others.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 176378ddbf21d758694e8e624cc6c555c78e0fab..6342b7a3c4ccad528f026384da64e973e630f030 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -768,30 +768,33 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
// CraftBukkit start
|
||||
public void prepareLevels(ChunkProgressListener worldloadlistener, ServerLevel worldserver) {
|
||||
+ ServerChunkCache chunkproviderserver = worldserver.getChunkSource(); // Paper - Configurable Keep Spawn Loaded range per world
|
||||
// WorldServer worldserver = this.overworld();
|
||||
this.forceTicks = true;
|
||||
// CraftBukkit end
|
||||
+ if (worldserver.getWorld().getKeepSpawnInMemory()) { // Paper - Configurable Keep Spawn Loaded range per world
|
||||
|
||||
MinecraftServer.LOGGER.info("Preparing start region for dimension {}", worldserver.dimension().location());
|
||||
BlockPos blockposition = worldserver.getSharedSpawnPos();
|
||||
|
||||
worldloadlistener.updateSpawnPos(new ChunkPos(blockposition));
|
||||
- ServerChunkCache chunkproviderserver = worldserver.getChunkSource();
|
||||
+ //ChunkProviderServer chunkproviderserver = worldserver.getChunkProvider(); // Paper - Configurable Keep Spawn Loaded range per world; move up
|
||||
|
||||
this.nextTickTimeNanos = Util.getNanos();
|
||||
- // CraftBukkit start
|
||||
- if (worldserver.getWorld().getKeepSpawnInMemory()) {
|
||||
- chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(blockposition), 11, Unit.INSTANCE);
|
||||
+ // Paper start - Configurable Keep Spawn Loaded range per world
|
||||
+ int radiusBlocks = worldserver.paperConfig().spawn.keepSpawnLoadedRange * 16;
|
||||
+ int radiusChunks = radiusBlocks / 16 + ((radiusBlocks & 15) != 0 ? 1 : 0);
|
||||
+ int totalChunks = ((radiusChunks) * 2 + 1);
|
||||
+ totalChunks *= totalChunks;
|
||||
+ worldloadlistener.setChunkRadius(radiusBlocks / 16);
|
||||
|
||||
- while (chunkproviderserver.getTickingGenerated() != 441) {
|
||||
- // this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS;
|
||||
- this.executeModerately();
|
||||
- }
|
||||
- }
|
||||
+ worldserver.addTicketsForSpawn(radiusBlocks, blockposition);
|
||||
+ // Paper end - Configurable Keep Spawn Loaded range per world
|
||||
|
||||
// this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS;
|
||||
this.executeModerately();
|
||||
// Iterator iterator = this.levels.values().iterator();
|
||||
+ } // Paper - Configurable Keep Spawn Loaded range per world
|
||||
|
||||
if (true) {
|
||||
ServerLevel worldserver1 = worldserver;
|
||||
@@ -814,7 +817,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS;
|
||||
this.executeModerately();
|
||||
// CraftBukkit end
|
||||
- worldloadlistener.stop();
|
||||
+ if (worldserver.getWorld().getKeepSpawnInMemory()) worldloadlistener.stop(); // Paper - Configurable Keep Spawn Loaded range per world
|
||||
// CraftBukkit start
|
||||
// this.updateMobSpawningFlags();
|
||||
worldserver.setSpawnSettings(this.isSpawningMonsters(), this.isSpawningAnimals());
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 57f129651778d6c20c695bf7b3a8b4d40c402a20..20de3be232ccc7ec7bbc3c6aee9acf66fd396af1 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1640,12 +1640,84 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
return ((MapIndex) this.getServer().overworld().getDataStorage().computeIfAbsent(MapIndex.factory(), "idcounts")).getFreeAuxValueForMap();
|
||||
}
|
||||
|
||||
+ // Paper start - Configurable Keep Spawn Loaded range per world
|
||||
+ public void addTicketsForSpawn(int radiusInBlocks, BlockPos spawn) {
|
||||
+ // In order to respect vanilla behavior, which is ensuring everything but the spawn border can tick, we add tickets
|
||||
+ // with level 31 for the non-border spawn chunks
|
||||
+ ServerChunkCache chunkproviderserver = this.getChunkSource();
|
||||
+ int tickRadius = radiusInBlocks - 16;
|
||||
+
|
||||
+ // add ticking chunks
|
||||
+ for (int x = -tickRadius; x <= tickRadius; x += 16) {
|
||||
+ for (int z = -tickRadius; z <= tickRadius; z += 16) {
|
||||
+ // radius of 2 will have the current chunk be level 31
|
||||
+ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, z)), 2, Unit.INSTANCE);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // add border chunks
|
||||
+
|
||||
+ // add border along x axis (including corner chunks)
|
||||
+ for (int x = -radiusInBlocks; x <= radiusInBlocks; x += 16) {
|
||||
+ // top
|
||||
+ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, radiusInBlocks)), 1, Unit.INSTANCE); // level 32
|
||||
+ // bottom
|
||||
+ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, -radiusInBlocks)), 1, Unit.INSTANCE); // level 32
|
||||
+ }
|
||||
+
|
||||
+ // add border along z axis (excluding corner chunks)
|
||||
+ for (int z = -radiusInBlocks + 16; z < radiusInBlocks; z += 16) {
|
||||
+ // right
|
||||
+ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
|
||||
+ // left
|
||||
+ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(-radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
|
||||
+ }
|
||||
+ }
|
||||
+ public void removeTicketsForSpawn(int radiusInBlocks, BlockPos spawn) {
|
||||
+ // In order to respect vanilla behavior, which is ensuring everything but the spawn border can tick, we added tickets
|
||||
+ // with level 31 for the non-border spawn chunks
|
||||
+ ServerChunkCache chunkproviderserver = this.getChunkSource();
|
||||
+ int tickRadius = radiusInBlocks - 16;
|
||||
+
|
||||
+ // remove ticking chunks
|
||||
+ for (int x = -tickRadius; x <= tickRadius; x += 16) {
|
||||
+ for (int z = -tickRadius; z <= tickRadius; z += 16) {
|
||||
+ // radius of 2 will have the current chunk be level 31
|
||||
+ chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, z)), 2, Unit.INSTANCE);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // remove border chunks
|
||||
+
|
||||
+ // remove border along x axis (including corner chunks)
|
||||
+ for (int x = -radiusInBlocks; x <= radiusInBlocks; x += 16) {
|
||||
+ // top
|
||||
+ chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, radiusInBlocks)), 1, Unit.INSTANCE); // level 32
|
||||
+ // bottom
|
||||
+ chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, -radiusInBlocks)), 1, Unit.INSTANCE); // level 32
|
||||
+ }
|
||||
+
|
||||
+ // remove border along z axis (excluding corner chunks)
|
||||
+ for (int z = -radiusInBlocks + 16; z < radiusInBlocks; z += 16) {
|
||||
+ // right
|
||||
+ chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
|
||||
+ // left
|
||||
+ chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(-radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Configurable Keep Spawn Loaded range per world
|
||||
+
|
||||
public void setDefaultSpawnPos(BlockPos pos, float angle) {
|
||||
- ChunkPos chunkcoordintpair = new ChunkPos(new BlockPos(this.levelData.getXSpawn(), 0, this.levelData.getZSpawn()));
|
||||
+ // Paper start - Configurable Keep Spawn Loaded range per world
|
||||
+ BlockPos prevSpawn = this.getSharedSpawnPos();
|
||||
+ //ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.a(), 0, this.worldData.c()));
|
||||
|
||||
this.levelData.setSpawn(pos, angle);
|
||||
- this.getChunkSource().removeRegionTicket(TicketType.START, chunkcoordintpair, 11, Unit.INSTANCE);
|
||||
- this.getChunkSource().addRegionTicket(TicketType.START, new ChunkPos(pos), 11, Unit.INSTANCE);
|
||||
+ if (this.keepSpawnInMemory) {
|
||||
+ // if this keepSpawnInMemory is false a plugin has already removed our tickets, do not re-add
|
||||
+ this.removeTicketsForSpawn(this.paperConfig().spawn.keepSpawnLoadedRange * 16, prevSpawn);
|
||||
+ this.addTicketsForSpawn(this.paperConfig().spawn.keepSpawnLoadedRange * 16, pos);
|
||||
+ }
|
||||
this.getServer().getPlayerList().broadcastAll(new ClientboundSetDefaultSpawnPositionPacket(pos, angle));
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/progress/ChunkProgressListener.java b/src/main/java/net/minecraft/server/level/progress/ChunkProgressListener.java
|
||||
index 1b565b2809c2d367e21971c5154f35c9763995e6..4792eaa30464f4c4ca7f2d6cf20f734beed81f23 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/progress/ChunkProgressListener.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/progress/ChunkProgressListener.java
|
||||
@@ -12,4 +12,6 @@ public interface ChunkProgressListener {
|
||||
void start();
|
||||
|
||||
void stop();
|
||||
+
|
||||
+ void setChunkRadius(int radius); // Paper - Configurable Keep Spawn Loaded range per world
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java b/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java
|
||||
index c9667df492e5681bf933a7f8878b0fdb324afed3..09d0c702132d4cc52ce36712aed11d30efe89f54 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java
|
||||
@@ -11,12 +11,19 @@ import org.slf4j.Logger;
|
||||
|
||||
public class LoggerChunkProgressListener implements ChunkProgressListener {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
- private final int maxCount;
|
||||
+ private int maxCount; // Paper - remove final
|
||||
private int count;
|
||||
private long startTime;
|
||||
private long nextTickTime = Long.MAX_VALUE;
|
||||
|
||||
public LoggerChunkProgressListener(int radius) {
|
||||
+ // Paper start - Configurable Keep Spawn Loaded range per world
|
||||
+ this.setChunkRadius(radius); // Move to method
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setChunkRadius(int radius) {
|
||||
+ // Paper end - Configurable Keep Spawn Loaded range per world
|
||||
int i = radius * 2 + 1;
|
||||
this.maxCount = i * i;
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 4001a8c13ceed6037174bb81fd06d9758fa0336c..b39721208f8b66c1478e89553a592070cf90fb97 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -1411,15 +1411,21 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public void setKeepSpawnInMemory(boolean keepLoaded) {
|
||||
+ // Paper start - Configurable spawn radius
|
||||
+ if (keepLoaded == this.world.keepSpawnInMemory) {
|
||||
+ // do nothing, nothing has changed
|
||||
+ return;
|
||||
+ }
|
||||
this.world.keepSpawnInMemory = keepLoaded;
|
||||
// Grab the worlds spawn chunk
|
||||
BlockPos chunkcoordinates = this.world.getSharedSpawnPos();
|
||||
if (keepLoaded) {
|
||||
- this.world.getChunkSource().addRegionTicket(TicketType.START, new ChunkPos(chunkcoordinates), 11, Unit.INSTANCE);
|
||||
+ this.world.addTicketsForSpawn(this.world.paperConfig().spawn.keepSpawnLoadedRange * 16, chunkcoordinates);
|
||||
} else {
|
||||
- // TODO: doesn't work well if spawn changed....
|
||||
- this.world.getChunkSource().removeRegionTicket(TicketType.START, new ChunkPos(chunkcoordinates), 11, Unit.INSTANCE);
|
||||
+ // TODO: doesn't work well if spawn changed.... // Paper - resolved
|
||||
+ this.world.removeTicketsForSpawn(this.world.paperConfig().spawn.keepSpawnLoadedRange * 16, chunkcoordinates);
|
||||
}
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
Loading…
Add table
Add a link
Reference in a new issue