From 9f7eef81fd4c83b792b854ab4a17325d13e3616c Mon Sep 17 00:00:00 2001 From: Noah van der Aa Date: Sat, 26 Nov 2022 01:23:12 +0100 Subject: [PATCH] Friction API (#6611) --- patches/api/0412-Friction-API.patch | 73 ++++++++++++ patches/server/0947-Friction-API.patch | 156 +++++++++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 patches/api/0412-Friction-API.patch create mode 100644 patches/server/0947-Friction-API.patch diff --git a/patches/api/0412-Friction-API.patch b/patches/api/0412-Friction-API.patch new file mode 100644 index 000000000..8cff02f9c --- /dev/null +++ b/patches/api/0412-Friction-API.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Wed, 15 Sep 2021 20:40:51 +0200 +Subject: [PATCH] Friction API + + +diff --git a/src/main/java/io/papermc/paper/entity/Frictional.java b/src/main/java/io/papermc/paper/entity/Frictional.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6eb88c664d873506372ad14075bfcbe42958126f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/entity/Frictional.java +@@ -0,0 +1,35 @@ ++package io.papermc.paper.entity; ++ ++import net.kyori.adventure.util.TriState; ++import org.bukkit.entity.Entity; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Represents an {@link Entity} that can experience friction with the air and ground. ++ */ ++public interface Frictional { ++ ++ /** ++ * Gets the friction state of this entity. ++ * When set to {@link TriState#TRUE}, the entity will always experience friction. ++ * When set to {@link TriState#FALSE}, the entity will never experience friction. ++ * When set to {@link TriState#NOT_SET}, the entity will fall back to Minecraft's default behaviour. ++ * ++ * @return the entity's friction state ++ */ ++ @NotNull ++ TriState getFrictionState(); ++ ++ /** ++ * Sets the friction state of this entity. ++ * When set to {@link TriState#TRUE}, the entity will always experience friction. ++ * When set to {@link TriState#FALSE}, the entity will never experience friction. ++ * When set to {@link TriState#NOT_SET}, the entity will fall back to Minecraft's default behaviour. ++ *

++ * Please note that changing this value will do nothing for a player. ++ * ++ * @param state the new friction state to set for the entity ++ */ ++ void setFrictionState(@NotNull TriState state); ++ ++} +diff --git a/src/main/java/org/bukkit/entity/Item.java b/src/main/java/org/bukkit/entity/Item.java +index d0bef15785493b512ff0f7414c1d58d38fead581..58017fce436cdbda255f7172fbdadb726d4b113c 100644 +--- a/src/main/java/org/bukkit/entity/Item.java ++++ b/src/main/java/org/bukkit/entity/Item.java +@@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a dropped item. + */ +-public interface Item extends Entity { ++public interface Item extends Entity, io.papermc.paper.entity.Frictional { // Paper + + /** + * Gets the item stack associated with this item drop. +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index f6cbada38ca48638e5ad0bd99d0b6ea65f6b02de..97336be470a9d545d93f78e683a793f328013ad8 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -25,7 +25,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a living entity, such as a monster or player + */ +-public interface LivingEntity extends Attributable, Damageable, ProjectileSource { ++public interface LivingEntity extends Attributable, Damageable, ProjectileSource, io.papermc.paper.entity.Frictional { // Paper + + /** + * Gets the height of the living entity's eyes above its Location. diff --git a/patches/server/0947-Friction-API.patch b/patches/server/0947-Friction-API.patch new file mode 100644 index 000000000..5d3d0715f --- /dev/null +++ b/patches/server/0947-Friction-API.patch @@ -0,0 +1,156 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Wed, 15 Sep 2021 20:44:22 +0200 +Subject: [PATCH] Friction API + + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index fb6fd9357f665a001238384475a9b674715700ba..11d7c42d65b91bf57b7bba7812aa17e60e018c67 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -264,6 +264,7 @@ public abstract class LivingEntity extends Entity { + 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 ++ public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper + + @Override + public float getBukkitYaw() { +@@ -706,7 +707,7 @@ public abstract class LivingEntity extends Entity { + } + + public boolean shouldDiscardFriction() { +- return this.discardFriction; ++ return !this.frictionState.toBooleanOrElse(!this.discardFriction); // Paper + } + + public void setDiscardFriction(boolean noDrag) { +@@ -751,6 +752,11 @@ public abstract class LivingEntity extends Entity { + + @Override + public void addAdditionalSaveData(CompoundTag nbt) { ++ // Paper start ++ if (this.frictionState != net.kyori.adventure.util.TriState.NOT_SET) { ++ nbt.putString("Paper.FrictionState", this.frictionState.toString()); ++ } ++ // Paper end + nbt.putFloat("Health", this.getHealth()); + nbt.putShort("HurtTime", (short) this.hurtTime); + nbt.putInt("HurtByTimestamp", this.lastHurtByMobTimestamp); +@@ -793,6 +799,15 @@ public abstract class LivingEntity extends Entity { + absorptionAmount = 0; + } + this.setAbsorptionAmount(absorptionAmount); ++ ++ if (nbt.contains("Paper.FrictionState")) { ++ String fs = nbt.getString("Paper.FrictionState"); ++ try { ++ frictionState = net.kyori.adventure.util.TriState.valueOf(fs); ++ } catch (Exception ignored) { ++ LOGGER.error("Unknown friction state " + fs + " for " + this); ++ } ++ } + // Paper end + if (nbt.contains("Attributes", 9) && this.level != null && !this.level.isClientSide) { + this.getAttributes().load(nbt.getList("Attributes", 10)); +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 da877bfb87c34f83991dd0957f6042c7543edb3e..c8d8fdef7b8abc0f59b7d19462825ae30c8d4f48 100644 +--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java ++++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java +@@ -55,6 +55,7 @@ public class ItemEntity extends Entity { + private int lastTick = MinecraftServer.currentTick - 1; // CraftBukkit + public boolean canMobPickup = true; // Paper + private int despawnRate = -1; // Paper ++ public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper + + public ItemEntity(EntityType type, Level world) { + super(type, world); +@@ -152,7 +153,11 @@ public class ItemEntity extends Entity { + this.move(MoverType.SELF, this.getDeltaMovement()); + float f1 = 0.98F; + +- if (this.onGround) { ++ // Paper start ++ if (frictionState == net.kyori.adventure.util.TriState.FALSE) { ++ f1 = 1F; ++ } else if (this.onGround) { ++ // Paper end + f1 = this.level.getBlockState(new BlockPos(this.getX(), this.getY() - 1.0D, this.getZ())).getBlock().getFriction() * 0.98F; + } + +@@ -353,6 +358,11 @@ public class ItemEntity extends Entity { + + @Override + public void addAdditionalSaveData(CompoundTag nbt) { ++ // Paper start ++ if (this.frictionState != net.kyori.adventure.util.TriState.NOT_SET) { ++ nbt.putString("Paper.FrictionState", this.frictionState.toString()); ++ } ++ // Paper end + nbt.putShort("Health", (short) this.health); + nbt.putShort("Age", (short) this.age); + nbt.putShort("PickupDelay", (short) this.pickupDelay); +@@ -386,6 +396,17 @@ public class ItemEntity extends Entity { + this.thrower = nbt.getUUID("Thrower"); + } + ++ // Paper start ++ if (nbt.contains("Paper.FrictionState")) { ++ String fs = nbt.getString("Paper.FrictionState"); ++ try { ++ frictionState = net.kyori.adventure.util.TriState.valueOf(fs); ++ } catch (Exception ignored) { ++ com.mojang.logging.LogUtils.getLogger().error("Unknown friction state " + fs + " for " + this); ++ } ++ } ++ // Paper end ++ + CompoundTag nbttagcompound1 = nbt.getCompound("Item"); + + this.setItem(ItemStack.of(nbttagcompound1)); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +index fea44ba6a6584b4a510af6a58cab07eecec6b68b..ecec5e17807a760769fc0ea79c2a0161cc5db1ef 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +@@ -103,6 +103,18 @@ public class CraftItem extends CraftEntity implements Item { + item.age = willAge ? 0 : NO_AGE_TIME; + } + ++ @org.jetbrains.annotations.NotNull ++ @Override ++ public net.kyori.adventure.util.TriState getFrictionState() { ++ return this.item.frictionState; ++ } ++ ++ @Override ++ public void setFrictionState(@org.jetbrains.annotations.NotNull net.kyori.adventure.util.TriState state) { ++ java.util.Objects.requireNonNull(state, "state may not be null"); ++ this.item.frictionState = state; ++ } ++ + @Override + public int getHealth() { + return item.health; +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index fa2e865324c11b724c351cdf8c03bfc4c8a274f6..316120a57802c45fb9b02a4daee207a0845c63be 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -1025,6 +1025,18 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + }); + } + ++ @org.jetbrains.annotations.NotNull ++ @Override ++ public net.kyori.adventure.util.TriState getFrictionState() { ++ return this.getHandle().frictionState; ++ } ++ ++ @Override ++ public void setFrictionState(@org.jetbrains.annotations.NotNull net.kyori.adventure.util.TriState state) { ++ java.util.Objects.requireNonNull(state, "state may not be null"); ++ this.getHandle().frictionState = state; ++ } ++ + @Override + public void knockback(double strength, double directionX, double directionZ) { + Preconditions.checkArgument(strength > 0, "Knockback strength must be > 0");