Merge remote-tracking branch 'leaf/dev/1.17' into dev/1.17

This commit is contained in:
Jason Penilla
2021-06-12 21:35:43 -07:00
19 changed files with 508 additions and 1418 deletions

View File

@@ -0,0 +1,90 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Mon, 3 Sep 2018 18:20:03 -0500
Subject: [PATCH] Add ray tracing methods to LivingEntity
diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/MCUtil.java
+++ b/src/main/java/net/minecraft/server/MCUtil.java
@@ -0,0 +0,0 @@ public final class MCUtil {
return getNMSWorld(entity.getWorld());
}
+ public static ClipContext.Fluid getNMSFluidCollisionOption(com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode) {
+ switch (fluidMode) {
+ case NEVER:
+ return ClipContext.Fluid.NONE;
+ case SOURCE_ONLY:
+ return ClipContext.Fluid.SOURCE_ONLY;
+ case ALWAYS:
+ return ClipContext.Fluid.ANY;
+ }
+ return null;
+ }
+
public static BlockFace toBukkitBlockFace(Direction enumDirection) {
switch (enumDirection) {
case DOWN:
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
}
// Paper start
+ public HitResult getRayTrace(int maxDistance) {
+ return getRayTrace(maxDistance, ClipContext.Fluid.NONE);
+ }
+
+ public HitResult getRayTrace(int maxDistance, ClipContext.Fluid fluidCollisionOption) {
+ if (maxDistance < 1 || maxDistance > 120) {
+ throw new IllegalArgumentException("maxDistance must be between 1-120");
+ }
+
+ Vec3 start = new Vec3(getX(), getY() + getEyeHeight(), getZ());
+ org.bukkit.util.Vector dir = getBukkitEntity().getLocation().getDirection().multiply(maxDistance);
+ Vec3 end = new Vec3(start.x + dir.getX(), start.y + dir.getY(), start.z + dir.getZ());
+ ClipContext raytrace = new ClipContext(start, end, ClipContext.Block.OUTLINE, fluidCollisionOption, this);
+
+ return level.clip(raytrace);
+ }
+
public int shieldBlockingDelay = level.paperConfig.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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -0,0 +0,0 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
return blocks.get(0);
}
+ // Paper start
+ @Override
+ public Block getTargetBlock(int maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode) {
+ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, net.minecraft.server.MCUtil.getNMSFluidCollisionOption(fluidMode));
+ return !(rayTrace instanceof net.minecraft.world.phys.BlockHitResult) ? null : org.bukkit.craftbukkit.block.CraftBlock.at(getHandle().level, ((net.minecraft.world.phys.BlockHitResult)rayTrace).getBlockPos());
+ }
+
+ @Override
+ public org.bukkit.block.BlockFace getTargetBlockFace(int maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode) {
+ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, net.minecraft.server.MCUtil.getNMSFluidCollisionOption(fluidMode));
+ return !(rayTrace instanceof net.minecraft.world.phys.BlockHitResult) ? null : net.minecraft.server.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection());
+ }
+
+ @Override
+ public com.destroystokyo.paper.block.TargetBlockInfo getTargetBlockInfo(int maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode) {
+ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, net.minecraft.server.MCUtil.getNMSFluidCollisionOption(fluidMode));
+ return !(rayTrace instanceof net.minecraft.world.phys.BlockHitResult) ? null :
+ new com.destroystokyo.paper.block.TargetBlockInfo(org.bukkit.craftbukkit.block.CraftBlock.at(getHandle().level, ((net.minecraft.world.phys.BlockHitResult)rayTrace).getBlockPos()),
+ net.minecraft.server.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection()));
+ }
+ // Paper end
+
@Override
public List<Block> getLastTwoTargetBlocks(Set<Material> transparent, int maxDistance) {
return this.getLineOfSight(transparent, maxDistance, 2);

View File

@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Sat, 8 Sep 2018 18:43:31 -0500
Subject: [PATCH] Allow chests to be placed with NBT data
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -0,0 +0,0 @@ public final class ItemStack {
enuminteractionresult = InteractionResult.FAIL; // cancel placement
// PAIL: Remove this when MC-99075 fixed
placeEvent.getPlayer().updateInventory();
+ world.capturedTileEntities.clear(); // Paper - clear out tile entities as chests and such will pop loot
// revert back all captured blocks
for (BlockState blockstate : blocks) {
blockstate.update(true, false);
diff --git a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java
@@ -0,0 +0,0 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement
// CraftBukkit start
@Override
public boolean onlyOpCanSetNbt() {
- return true;
+ return false; // Paper
}
// CraftBukkit end
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Tue, 4 Sep 2018 15:02:00 -0500
Subject: [PATCH] Expose attack cooldown methods for Player
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
connection.send(new net.minecraft.network.protocol.game.ClientboundOpenBookPacket(net.minecraft.world.InteractionHand.MAIN_HAND));
connection.send(new net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket(0, slot, inventory.getSelected()));
}
+
+ @Override
+ public float getCooldownPeriod() {
+ return getHandle().getCurrentItemAttackStrengthDelay();
+ }
+
+ @Override
+ public float getCooledAttackStrength(float adjustTicks) {
+ return getHandle().getAttackStrengthScale(adjustTicks);
+ }
+
+ @Override
+ public void resetCooldown() {
+ getHandle().resetAttackStrengthTicker();
+ }
// Paper end
// Spigot start

View File

@@ -0,0 +1,416 @@
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] Implement an API for CanPlaceOn and CanDestroy NBT values
diff --git a/src/main/java/net/minecraft/commands/arguments/blocks/BlockStateParser.java b/src/main/java/net/minecraft/commands/arguments/blocks/BlockStateParser.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/commands/arguments/blocks/BlockStateParser.java
+++ b/src/main/java/net/minecraft/commands/arguments/blocks/BlockStateParser.java
@@ -0,0 +0,0 @@ public class BlockStateParser {
private final boolean forTesting;
private final Map<Property<?>, Comparable<?>> properties = Maps.newLinkedHashMap(); // CraftBukkit - stable
private final Map<String, String> vagueProperties = Maps.newHashMap();
- private ResourceLocation id = new ResourceLocation("");
+ private ResourceLocation id = new ResourceLocation(""); public final ResourceLocation getBlockKey() { return this.id; } // Paper - OBFHELPER
private StateDefinition<Block, BlockState> definition;
private BlockState state;
@Nullable
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
@@ -0,0 +0,0 @@ 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:
*
@@ -0,0 +0,0 @@ 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 - Implement an 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
// We store the raw original JSON representation of all text data. See SPIGOT-5063, SPIGOT-5656, SPIGOT-5304
private String displayName;
@@ -0,0 +0,0 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
private int hideFlag;
private boolean unbreakable;
private int damage;
+ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
+ private Set<Namespaced> placeableKeys = Sets.newHashSet();
+ private Set<Namespaced> destroyableKeys = Sets.newHashSet();
+ // Paper end
private static final Set<String> HANDLED_TAGS = Sets.newHashSet();
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
@@ -0,0 +0,0 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
this.hideFlag = meta.hideFlag;
this.unbreakable = meta.unbreakable;
this.damage = meta.damage;
+ // Paper start - Implement an 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
this.unhandledTags.putAll(meta.unhandledTags);
this.persistentDataContainer.putAll(meta.persistentDataContainer.getRaw());
@@ -0,0 +0,0 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
this.persistentDataContainer.put(key, compound.get(key));
}
}
+ // Paper start - Implement an 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.deserializeNamespaced(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.deserializeNamespaced(list.getString(i));
+ if (namespaced == null) {
+ continue;
+ }
+
+ this.placeableKeys.add(namespaced);
+ }
+ }
+ // Paper end
Set<String> keys = tag.getAllKeys();
for (String key : keys) {
@@ -0,0 +0,0 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
this.setDamage(damage);
}
+ // Paper start - Implement an 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.deserializeNamespaced(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.deserializeNamespaced(canDestroyRaw);
+ if (value == null) {
+ continue;
+ }
+
+ this.destroyableKeys.add(value);
+ }
+ }
+ // Paper end
+
String internal = SerializableMeta.getString(map, "internal", true);
if (internal != null) {
ByteArrayInputStream buf = new ByteArrayInputStream(Base64.decodeBase64(internal));
@@ -0,0 +0,0 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
if (this.hasDamage()) {
itemTag.putInt(DAMAGE.NBT, damage);
}
+ // Paper start - Implement an 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
for (Map.Entry<String, Tag> e : this.unhandledTags.entrySet()) {
itemTag.put(e.getKey(), e.getValue());
@@ -0,0 +0,0 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
}
}
+ // Paper start
+ 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
+
ListTag createStringList(List<String> list) {
if (list == null) {
return null;
@@ -0,0 +0,0 @@ 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
@@ -0,0 +0,0 @@ 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
}
/**
@@ -0,0 +0,0 @@ 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;
}
@@ -0,0 +0,0 @@ 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);
@@ -0,0 +0,0 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
builder.put(DAMAGE.BUKKIT, 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()) {
@@ -0,0 +0,0 @@ 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,
@@ -0,0 +0,0 @@ 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) {
+ Validate.notNull(canDestroy, "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) {
+ Validate.notNull(canPlaceOn, "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) {
+ Validate.notNull(canDestroy, "Cannot replace with null collection!");
+ Validate.isTrue(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) {
+ Validate.notNull(canPlaceOn, "Cannot replace with null collection!");
+ Validate.isTrue(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 deserializeNamespaced(String raw) {
+ boolean isTag = raw.length() > 0 && raw.codePointAt(0) == '#';
+ net.minecraft.commands.arguments.blocks.BlockStateParser blockParser = new net.minecraft.commands.arguments.blocks.BlockStateParser(new com.mojang.brigadier.StringReader(raw), true);
+ try {
+ blockParser = blockParser.parse(false);
+ } catch (com.mojang.brigadier.exceptions.CommandSyntaxException e) {
+ e.printStackTrace();
+ return null;
+ }
+
+ net.minecraft.resources.ResourceLocation key;
+ if (isTag) {
+ key = blockParser.getTag();
+ } else {
+ key = blockParser.getBlockKey();
+ }
+
+ if (key == null) {
+ return null;
+ }
+
+ // don't DC the player if something slips through somehow
+ Namespaced resource = null;
+ try {
+ if (isTag) {
+ resource = new NamespacedTag(key.getNamespace(), key.getPath());
+ } else {
+ resource = CraftNamespacedKey.fromMinecraft(key);
+ }
+ } catch (IllegalArgumentException ex) {
+ org.bukkit.Bukkit.getLogger().warning("Namespaced resource does not validate: " + key.toString());
+ ex.printStackTrace();
+ }
+
+ return resource;
+ }
+
+ 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
}

View File

@@ -0,0 +1,376 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Phoenix616 <mail@moep.tv>
Date: Tue, 21 Aug 2018 01:39:35 +0100
Subject: [PATCH] Improve death events
This adds the ability to cancel the death events and to modify the sound
an entity makes when dying. (In cases were no sound should it will be
called with shouldPlaySound set to false allowing unsilencing of silent
entities)
It makes handling of entity deaths a lot nicer as you no longer need
to listen on the damage event and calculate if the entity dies yourself
to cancel the death which has the benefit of also receiving the dropped
items and experience which is otherwise only properly possible by using
internal code.
TODO 1.17: this needs to be checked (actually get off your lazy ass and cancel the events) for the following entities,
maybe more (please check patch overrides for drops for more):
- players, armor stands, foxes, chested donkeys/llamas
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
public int latency;
public boolean wonGame;
private int containerUpdateDelay; // Paper
+ // Paper start - cancellable death event
+ public boolean queueHealthUpdatePacket = false;
+ public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
+ // Paper end
// CraftBukkit start
public String displayName;
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
Component defaultMessage = this.getCombatTracker().getDeathMessage();
org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, loot, PaperAdventure.asAdventure(defaultMessage), defaultMessage.getString(), keepInventory); // Paper - Adventure
+ // Paper start - cancellable death event
+ if (event.isCancelled()) {
+ // make compatible with plugins that might have already set the health in an event listener
+ if (this.getHealth() <= 0) {
+ this.setHealth((float) event.getReviveHealth());
+ }
+ return;
+ }
+ // Paper end
// SPIGOT-943 - only call if they have an inventory open
if (this.containerMenu != this.inventoryMenu) {
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
}
}
}
-
- return super.hurt(source, amount);
+ // Paper start - cancellable death events
+ //return super.hurt(source, amount);
+ this.queueHealthUpdatePacket = true;
+ boolean damaged = super.hurt(source, amount);
+ this.queueHealthUpdatePacket = false;
+ if (this.queuedHealthUpdatePacket != null) {
+ this.connection.send(this.queuedHealthUpdatePacket);
+ this.queuedHealthUpdatePacket = null;
+ }
+ return damaged;
+ // Paper end
}
}
}
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
public Set<UUID> collidableExemptions = new HashSet<>();
public boolean bukkitPickUpLoot;
public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper
+ public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event
@Override
public float getBukkitYaw() {
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
if (knockbackCancelled) this.level.broadcastEntityEvent(this, (byte) 2); // Paper - Disable explosion knockback
if (this.isDeadOrDying()) {
if (!this.checkTotemDeathProtection(source)) {
- SoundEvent soundeffect = this.getDeathSound();
-
- if (flag1 && soundeffect != null) {
- this.playSound(soundeffect, this.getSoundVolume(), this.getVoicePitch());
- }
+ // Paper start - moved into CraftEventFactory event caller for cancellable death event
+ this.silentDeath = !flag1; // mark entity as dying silently
+ // Paper end
this.die(source);
+ this.silentDeath = false; // Paper - cancellable death event - reset to default
}
} else if (flag1) {
this.playHurtSound(source);
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
if (!this.isRemoved() && !this.dead) {
Entity entity = source.getEntity();
LivingEntity entityliving = this.getKillCredit();
-
+ /* // Paper - move down to make death event cancellable - this is the runKillTrigger below
if (this.deathScore >= 0 && entityliving != null) {
entityliving.awardKillScore(this, this.deathScore, source);
}
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
if (this.isSleeping()) {
this.stopSleeping();
}
+ */ // Paper - move down to make death event cancellable - this is the runKillTrigger below
+
this.dead = true;
- this.getCombatTracker().recheckStatus();
+ // Paper - moved into if below
if (this.level instanceof ServerLevel) {
if (entity != null) {
- entity.killed((ServerLevel) this.level, this);
+ // Paper - move below into if for onKill
}
- this.dropAllDeathLoot(source);
+ // Paper start
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(source);
+ if (deathEvent == null || !deathEvent.isCancelled()) {
+ if (this.deathScore >= 0 && entityliving != null) {
+ entityliving.awardKillScore(this, this.deathScore, source);
+ }
+
+ if (this.isSleeping()) {
+ this.stopSleeping();
+ }
+
+ this.getCombatTracker().recheckStatus();
+ if (entity != null) {
+ entity.killed((ServerLevel) this.level, this);
+ }
+ } else {
+ this.dead = false;
+ this.setHealth((float) deathEvent.getReviveHealth());
+ }
+ // Paper end
this.createWitherRose(entityliving);
}
+ if (this.dead) { // Paper
this.level.broadcastEntityEvent(this, (byte) 3);
this.setPose(Pose.DYING);
+ } // Paper
}
}
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
if (!this.level.isClientSide) {
boolean flag = false;
- if (adversary instanceof WitherBoss) {
+ if (this.dead && adversary instanceof WitherBoss) { // Paper
if (this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
BlockPos blockposition = this.blockPosition();
BlockState iblockdata = Blocks.WITHER_ROSE.defaultBlockState();
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
}
}
- protected void dropAllDeathLoot(DamageSource source) {
+ protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(DamageSource source) { // Paper
Entity entity = source.getEntity();
int i;
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
this.dropCustomDeathLoot(source, i, flag);
}
// CraftBukkit start - Call death event
- CraftEventFactory.callEntityDeathEvent(this, this.drops);
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, this.drops); // Paper
+ this.postDeathDropItems(deathEvent); // Paper
this.drops = new ArrayList<>();
// CraftBukkit end
// this.dropInventory();// CraftBukkit - moved up
this.dropExperience();
+ return deathEvent; // Paper
}
protected void dropEquipment() {}
+ protected void postDeathDropItems(org.bukkit.event.entity.EntityDeathEvent event) {} // Paper - method for post death logic that cannot be ran before the event is potentially cancelled
// CraftBukkit start
public int getExpReward() {
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
return SoundEvents.GENERIC_HURT;
}
+
@Nullable
- protected SoundEvent getDeathSound() {
+ public final SoundEvent getDeathSoundPublic() { return this.getDeathSound(); } protected SoundEvent getDeathSound() { // Paper - provide PUBLIC accessor, overrides are hell to deal with
return SoundEvents.GENERIC_DEATH;
}
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
}
- protected float getSoundVolume() {
+ public final float getSoundVolumePublic() { return this.getSoundVolume(); } protected float getSoundVolume() { // Paper - provide PUBLIC accessor, overrides are hell
return 1.0F;
}
diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java
@@ -0,0 +0,0 @@ public class Fox extends Animal {
}
@Override
- protected void dropAllDeathLoot(DamageSource source) {
- ItemStack itemstack = this.getItemBySlot(EquipmentSlot.MAINHAND);
+ // Paper start - Cancellable death event
+ protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(DamageSource source) {
+ ItemStack itemstack = this.getItemBySlot(EquipmentSlot.MAINHAND).copy(); // Paper - modified by supercall
+
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = super.dropAllDeathLoot(source);
+
+ // Below is code to drop
+
+ if (deathEvent == null || deathEvent.isCancelled()) {
+ return deathEvent;
+ }
+ // Paper end
if (!itemstack.isEmpty()) {
this.spawnAtLocation(itemstack);
this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY);
}
- super.dropAllDeathLoot(source);
+ return deathEvent; // Paper
}
public static boolean isPathClear(Fox fox, LivingEntity chasedEntity) {
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractChestedHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractChestedHorse.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractChestedHorse.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractChestedHorse.java
@@ -0,0 +0,0 @@ public abstract class AbstractChestedHorse extends AbstractHorse {
this.spawnAtLocation(Blocks.CHEST);
}
- this.setChest(false);
+ //this.setCarryingChest(false); // Paper - moved to post death logic
}
}
+ // Paper start
+ protected void postDeathDropItems(org.bukkit.event.entity.EntityDeathEvent event) {
+ if (this.hasChest() && (event == null || !event.isCancelled())) {
+ this.setChest(false);
+ }
+ }
+ // Paper end
+
@Override
public void addAdditionalSaveData(CompoundTag nbt) {
super.addAdditionalSaveData(nbt);
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
@@ -0,0 +0,0 @@ public class ArmorStand extends LivingEntity {
@Override
public void kill() {
- org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, drops); // CraftBukkit - call event
+ org.bukkit.event.entity.EntityDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, drops); // CraftBukkit - call event // Paper - make cancellable
+ if (event.isCancelled()) return; // Paper - make cancellable
this.remove(Entity.RemovalReason.KILLED);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
public void sendHealthUpdate() {
- this.getHandle().connection.send(new ClientboundSetHealthPacket(this.getScaledHealth(), this.getHandle().getFoodData().getFoodLevel(), this.getHandle().getFoodData().getSaturationLevel()));
+ // Paper start - cancellable death event
+ ClientboundSetHealthPacket packet = new ClientboundSetHealthPacket(this.getScaledHealth(), this.getHandle().getFoodData().getFoodLevel(), this.getHandle().getFoodData().getSaturationLevel());
+ if (this.getHandle().queueHealthUpdatePacket) {
+ this.getHandle().queuedHealthUpdatePacket = packet;
+ } else {
+ this.getHandle().connection.send(packet);
+ }
+ // Paper end
}
public void injectScaledMaxHealth(Collection<AttributeInstance> collection, boolean force) {
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -0,0 +0,0 @@ public class CraftEventFactory {
public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List<org.bukkit.inventory.ItemStack> drops) {
CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity();
EntityDeathEvent event = new EntityDeathEvent(entity, drops, victim.getExpReward());
+ populateFields(victim, event); // Paper - make cancellable
CraftWorld world = (CraftWorld) entity.getWorld();
Bukkit.getServer().getPluginManager().callEvent(event);
+ // Paper start - make cancellable
+ if (event.isCancelled()) {
+ return event;
+ }
+ playDeathSound(victim, event);
+ // Paper end
victim.expToDrop = event.getDroppedExp();
for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
@@ -0,0 +0,0 @@ public class CraftEventFactory {
CraftPlayer entity = victim.getBukkitEntity();
PlayerDeathEvent event = new PlayerDeathEvent(entity, drops, victim.getExpReward(), 0, deathMessage, stringDeathMessage); // Paper - Adventure
event.setKeepInventory(keepInventory);
+ populateFields(victim, event); // Paper - make cancellable
org.bukkit.World world = entity.getWorld();
Bukkit.getServer().getPluginManager().callEvent(event);
+ // Paper start - make cancellable
+ if (event.isCancelled()) {
+ return event;
+ }
+ playDeathSound(victim, event);
+ // Paper end
victim.keepLevel = event.getKeepLevel();
victim.newLevel = event.getNewLevel();
@@ -0,0 +0,0 @@ public class CraftEventFactory {
return event;
}
+ // Paper start - helper methods for making death event cancellable
+ // Add information to death event
+ private static void populateFields(net.minecraft.world.entity.LivingEntity victim, EntityDeathEvent event) {
+ event.setReviveHealth(event.getEntity().getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).getValue());
+ event.setShouldPlayDeathSound(!victim.silentDeath && !victim.isSilent());
+ net.minecraft.sounds.SoundEvent soundEffect = victim.getDeathSoundPublic();
+ event.setDeathSound(soundEffect != null ? org.bukkit.craftbukkit.CraftSound.getBukkit(soundEffect) : null);
+ event.setDeathSoundCategory(org.bukkit.SoundCategory.valueOf(victim.getSoundSource().name()));
+ event.setDeathSoundVolume(victim.getSoundVolumePublic());
+ event.setDeathSoundPitch(victim.getVoicePitch());
+ }
+
+ // Play death sound manually
+ private static void playDeathSound(net.minecraft.world.entity.LivingEntity victim, EntityDeathEvent event) {
+ if (event.shouldPlayDeathSound() && event.getDeathSound() != null && event.getDeathSoundCategory() != null) {
+ net.minecraft.world.entity.player.Player source = victim instanceof net.minecraft.world.entity.player.Player ? (net.minecraft.world.entity.player.Player) victim : null;
+ double x = event.getEntity().getLocation().getX();
+ double y = event.getEntity().getLocation().getY();
+ double z = event.getEntity().getLocation().getZ();
+ net.minecraft.sounds.SoundEvent soundEffect = org.bukkit.craftbukkit.CraftSound.getSoundEffect(event.getDeathSound());
+ net.minecraft.sounds.SoundSource soundCategory = net.minecraft.sounds.SoundSource.valueOf(event.getDeathSoundCategory().name());
+ victim.level.playSound(source, x, y, z, soundEffect, soundCategory, event.getDeathSoundVolume(), event.getDeathSoundPitch());
+ }
+ }
+ // Paper end
/**
* Server methods
*/

View File

@@ -0,0 +1,289 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 9 Sep 2018 13:30:00 -0400
Subject: [PATCH] Mob Pathfinding API
Implements Pathfinding API for mobs
diff --git a/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java b/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java
@@ -0,0 +0,0 @@
+package com.destroystokyo.paper.entity;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.entity.CraftLivingEntity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Mob;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import net.minecraft.world.level.pathfinder.Node;
+import net.minecraft.world.level.pathfinder.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PaperPathfinder implements com.destroystokyo.paper.entity.Pathfinder {
+
+ private final net.minecraft.world.entity.Mob entity;
+
+ public PaperPathfinder(net.minecraft.world.entity.Mob entity) {
+ this.entity = entity;
+ }
+
+ @Override
+ public Mob getEntity() {
+ return entity.getBukkitMob();
+ }
+
+ @Override
+ public void stopPathfinding() {
+ entity.getNavigation().stopPathfinding();
+ }
+
+ @Override
+ public boolean hasPath() {
+ return entity.getNavigation().getPathEntity() != null;
+ }
+
+ @Nullable
+ @Override
+ public PathResult getCurrentPath() {
+ Path path = entity.getNavigation().getPathEntity();
+ return path != null ? new PaperPathResult(path) : null;
+ }
+
+ @Nullable
+ @Override
+ public PathResult findPath(Location loc) {
+ Validate.notNull(loc, "Location can not be null");
+ Path path = entity.getNavigation().calculateDestination(loc.getX(), loc.getY(), loc.getZ());
+ return path != null ? new PaperPathResult(path) : null;
+ }
+
+ @Nullable
+ @Override
+ public PathResult findPath(LivingEntity target) {
+ Validate.notNull(target, "Target can not be null");
+ Path path = entity.getNavigation().calculateDestination(((CraftLivingEntity) target).getHandle());
+ return path != null ? new PaperPathResult(path) : null;
+ }
+
+ @Override
+ public boolean moveTo(@Nonnull PathResult path, double speed) {
+ Validate.notNull(path, "PathResult can not be null");
+ Path pathEntity = ((PaperPathResult) path).path;
+ return entity.getNavigation().setDestination(pathEntity, speed);
+ }
+
+ @Override
+ public boolean canOpenDoors() {
+ return entity.getNavigation().getPathfinder().getPathfinder().shouldOpenDoors();
+ }
+
+ @Override
+ public void setCanOpenDoors(boolean canOpenDoors) {
+ entity.getNavigation().getPathfinder().getPathfinder().setShouldOpenDoors(canOpenDoors);
+ }
+
+ @Override
+ public boolean canPassDoors() {
+ return entity.getNavigation().getPathfinder().getPathfinder().shouldPassDoors();
+ }
+
+ @Override
+ public void setCanPassDoors(boolean canPassDoors) {
+ entity.getNavigation().getPathfinder().getPathfinder().setShouldPassDoors(canPassDoors);
+ }
+
+ @Override
+ public boolean canFloat() {
+ return entity.getNavigation().getPathfinder().getPathfinder().shouldFloat();
+ }
+
+ @Override
+ public void setCanFloat(boolean canFloat) {
+ entity.getNavigation().getPathfinder().getPathfinder().setShouldFloat(canFloat);
+ }
+
+ public class PaperPathResult implements com.destroystokyo.paper.entity.PaperPathfinder.PathResult {
+
+ private final Path path;
+ PaperPathResult(Path path) {
+ this.path = path;
+ }
+
+ @Nullable
+ @Override
+ public Location getFinalPoint() {
+ Node point = path.getFinalPoint();
+ return point != null ? toLoc(point) : null;
+ }
+
+ @Override
+ public List<Location> getPoints() {
+ List<Location> points = new ArrayList<>();
+ for (Node point : path.getPoints()) {
+ points.add(toLoc(point));
+ }
+ return points;
+ }
+
+ @Override
+ public int getNextPointIndex() {
+ return path.getNextIndex();
+ }
+
+ @Nullable
+ @Override
+ public Location getNextPoint() {
+ if (!path.hasNext()) {
+ return null;
+ }
+ return toLoc(path.getPoints().get(path.getNextIndex()));
+ }
+ }
+
+ private Location toLoc(Node point) {
+ return new Location(entity.level.getWorld(), point.getX(), point.getY(), point.getZ());
+ }
+}
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
@@ -0,0 +0,0 @@ public abstract class PathNavigation {
}
@Nullable
- public final Path createPath(double x, double y, double z, int distance) {
+ public final Path calculateDestination(double d0, double d1, double d2) { return createPath(d0, d1, d2, 0); } public final Path createPath(double x, double y, double z, int distance) { // Paper - OBFHELPER
return this.createPath(new BlockPos(x, y, z), distance);
}
@@ -0,0 +0,0 @@ public abstract class PathNavigation {
}
@Nullable
- public Path createPath(Entity entity, int distance) {
+ public final Path calculateDestination(Entity entity) { return createPath(entity, 0); } public Path createPath(Entity entity, int distance) {
return this.createPath(ImmutableSet.of(entity.blockPosition()), entity, 16, true, distance); // Paper
}
@@ -0,0 +0,0 @@ public abstract class PathNavigation {
return path != null && this.moveTo(path, speed);
}
+ public boolean setDestination(@Nullable Path pathentity, double speed) { return moveTo(pathentity, speed); } // Paper - OBFHELPER
public boolean moveTo(@Nullable Path path, double speed) {
if (path == null) {
this.path = null;
@@ -0,0 +0,0 @@ public abstract class PathNavigation {
}
}
- @Nullable
+ @Nullable public Path getPathEntity() { return getPath(); } @Nullable // Paper - OBFHELPER
public Path getPath() {
return this.path;
}
@@ -0,0 +0,0 @@ public abstract class PathNavigation {
return !this.isDone();
}
+ public void stopPathfinding() { stop(); } // Paper - OBFHELPER
public void stop() {
this.path = null;
}
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/Node.java b/src/main/java/net/minecraft/world/level/pathfinder/Node.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/Node.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/Node.java
@@ -0,0 +0,0 @@ import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3;
public class Node {
- public final int x;
- public final int y;
- public final int z;
+ public final int x; public final int getX() { return x; } // Paper - OBFHELPER
+ public final int y; public final int getY() { return y; } // Paper - OBFHELPER
+ public final int z; public final int getZ() { return z; } // Paper - OBFHELPER
private final int hash;
public int heapIdx = -1;
public float g;
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
@@ -0,0 +0,0 @@ public abstract class NodeEvaluator {
protected int entityWidth;
protected int entityHeight;
protected int entityDepth;
- protected boolean canPassDoors;
- protected boolean canOpenDoors;
- protected boolean canFloat;
+ protected boolean canPassDoors; public boolean shouldPassDoors() { return canPassDoors; } public void setShouldPassDoors(boolean b) { canPassDoors = b; } // Paper - obfhelper
+ protected boolean canOpenDoors; public boolean shouldOpenDoors() { return canOpenDoors; } public void setShouldOpenDoors(boolean b) { canOpenDoors = b; } // Paper - obfhelper
+ protected boolean canFloat; public boolean shouldFloat() { return canFloat; } public void setShouldFloat(boolean b) { canFloat = b; } // Paper - obfhelper
public void prepare(PathNavigationRegion cachedWorld, Mob entity) {
this.level = cachedWorld;
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/Path.java b/src/main/java/net/minecraft/world/level/pathfinder/Path.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/Path.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/Path.java
@@ -0,0 +0,0 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
public class Path {
- private final List<Node> nodes;
+ private final List<Node> nodes; public List<Node> getPoints() { return nodes; } // Paper - OBFHELPER
private Node[] openSet = new Node[0];
private Node[] closedSet = new Node[0];
private Set<Target> targetNodes;
- private int nextNodeIndex;
+ private int nextNodeIndex; public int getNextIndex() { return this.nextNodeIndex; } // Paper - OBFHELPER
private final BlockPos target;
private final float distToTarget;
private final boolean reached;
+ public boolean hasNext() { return getNextIndex() < getPoints().size(); } // Paper
public Path(List<Node> nodes, BlockPos target, boolean reachesTarget) {
this.nodes = nodes;
@@ -0,0 +0,0 @@ public class Path {
}
@Nullable
- public Node getEndNode() {
+ public Node getFinalPoint() { return getEndNode(); } @Nullable public Node getEndNode() { // Paper - OBFHELPER
return !this.nodes.isEmpty() ? this.nodes.get(this.nodes.size() - 1) : null;
}
@@ -0,0 +0,0 @@ public class Path {
return this.getEntityPosAtNode(entity, this.nextNodeIndex);
}
- public BlockPos getNextNodePos() {
+ public BlockPos getNext() { return getNextNodePos(); } public BlockPos getNextNodePos() { // Paper - OBFHELPER
return this.nodes.get(this.nextNodeIndex).asBlockPos();
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
@@ -0,0 +0,0 @@ import org.bukkit.loot.LootTable;
public abstract class CraftMob extends CraftLivingEntity implements Mob {
public CraftMob(CraftServer server, net.minecraft.world.entity.Mob entity) {
super(server, entity);
+ paperPathfinder = new com.destroystokyo.paper.entity.PaperPathfinder(entity); // Paper
}
+ private final com.destroystokyo.paper.entity.PaperPathfinder paperPathfinder; // Paper
+ @Override public com.destroystokyo.paper.entity.Pathfinder getPathfinder() { return paperPathfinder; } // Paper
@Override
public void setTarget(LivingEntity target) {
net.minecraft.world.entity.Mob entity = this.getHandle();

View File

@@ -0,0 +1,40 @@
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 Mob AI Rules from Loading Chunks
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 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
@@ -0,0 +0,0 @@ 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.getTypeIfLoaded(pos); // Paper
+ if (block == null) return null; // Paper
+ if (block.is(this.blockToRemove)) { // Paper
return pos;
} else {
BlockPos[] ablockposition = new BlockPos[]{pos.below(), pos.west(), pos.east(), pos.north(), pos.south(), pos.below().below()};
@@ -0,0 +0,0 @@ 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.getTypeIfLoaded(blockposition1); // Paper
+ if (block2 != null && block2.is(this.blockToRemove)) { // Paper
return blockposition1;
}
}
@@ -0,0 +0,0 @@ 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
return ichunkaccess == null ? false : ichunkaccess.getBlockState(pos).is(this.blockToRemove) && ichunkaccess.getBlockState(pos.above()).isAir() && ichunkaccess.getBlockState(pos.above(2)).isAir();
}

View File

@@ -0,0 +1,75 @@
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
@@ -0,0 +0,0 @@ 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.getTypeIfLoaded(blockposition1); // Paper
+ if (iblockdata1 == null) continue; // Paper
if (this.canSpreadTo(world, pos, blockState, enumdirection, blockposition1, iblockdata1, world.getFluidState(blockposition1), fluid1.getType())) {
// CraftBukkit start
@@ -0,0 +0,0 @@ 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.getTypeIfLoaded(blockposition1); // Paper
+ if (iblockdata1 == null) continue; // Paper
FluidState fluid = iblockdata1.getFluidState();
if (fluid.getType().isSame((Fluid) this) && this.canPassThroughWall(enumdirection, (BlockGetter) world, pos, state, blockposition1, iblockdata1)) {
@@ -0,0 +0,0 @@ public abstract class FlowingFluid extends Fluid {
if (enumdirection1 != enumdirection) {
BlockPos blockposition2 = blockposition.relative(enumdirection1);
short short0 = FlowingFluid.getCacheKey(blockposition1, blockposition2);
- Pair<BlockState, FluidState> pair = (Pair) short2objectmap.computeIfAbsent(short0, (k) -> {
- BlockState iblockdata1 = world.getBlockState(blockposition2);
+ // Paper start - avoid loading chunks
+ Pair<BlockState, FluidState> pair = short2objectmap.get(short0);
+ if (pair == null) {
+ BlockState iblockdatax = world.getTypeIfLoaded(blockposition2);
+ if (iblockdatax == null) {
+ continue;
+ }
- return Pair.of(iblockdata1, iblockdata1.getFluidState());
- });
+ pair = Pair.of(iblockdatax, iblockdatax.getFluidState());
+ short2objectmap.put(short0, pair);
+ }
+ // Paper end
BlockState iblockdata1 = (BlockState) pair.getFirst();
FluidState fluid = (FluidState) pair.getSecond();
@@ -0,0 +0,0 @@ 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, (j) -> {
- BlockState iblockdata1 = world.getBlockState(blockposition1);
-
- return Pair.of(iblockdata1, iblockdata1.getFluidState());
- });
+ // Paper start
+ Pair pair = (Pair) short2objectmap.get(short0);
+ if (pair == null) {
+ BlockState iblockdatax = world.getTypeIfLoaded(blockposition1);
+ if (iblockdatax == null) continue;
+
+ pair = Pair.of(iblockdatax, iblockdatax.getFluidState());
+ short2objectmap.put(short0, pair);
+ }
+ // Paper end
BlockState iblockdata1 = (BlockState) pair.getFirst();
FluidState fluid = (FluidState) pair.getSecond();
FluidState fluid1 = this.getNewLiquid(world, blockposition1, iblockdata1);

View File

@@ -0,0 +1,32 @@
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -0,0 +0,0 @@ public final class NaturalSpawner {
StructureFeatureManager structuremanager = world.structureFeatureManager();
ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator();
int i = pos.getY();
- BlockState iblockdata = chunk.getBlockState(pos);
+ BlockState iblockdata = world.getTypeIfLoadedAndInBounds(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;
@@ -0,0 +0,0 @@ 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, (BlockPos) blockposition_mutableblockposition);