From 2506babe8e1110f809d1d29e19921a5ea7c048fb Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Thu, 4 Jan 2024 13:49:14 +0100 Subject: [PATCH] Validate ResourceLocation in NBT reading --- .../net/minecraft/nbt/NbtUtils.java.patch | 15 ++ .../resources/ResourceLocation.java.patch | 18 +- .../world/RandomizableContainer.java.patch | 6 +- .../world/entity/EntityType.java.patch | 9 + .../world/entity/Leashable.java.patch | 32 ++-- .../world/entity/LivingEntity.java.patch | 181 ++++++++++-------- .../net/minecraft/world/entity/Mob.java.patch | 29 ++- .../projectile/AbstractArrow.java.patch | 9 + .../entity/vehicle/ContainerEntity.java.patch | 3 +- .../AbstractFurnaceBlockEntity.java.patch | 34 ++-- .../entity/BrushableBlockEntity.java.patch | 9 + 11 files changed, 223 insertions(+), 122 deletions(-) create mode 100644 paper-server/patches/sources/net/minecraft/nbt/NbtUtils.java.patch diff --git a/paper-server/patches/sources/net/minecraft/nbt/NbtUtils.java.patch b/paper-server/patches/sources/net/minecraft/nbt/NbtUtils.java.patch new file mode 100644 index 0000000000..a126b25999 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/nbt/NbtUtils.java.patch @@ -0,0 +1,15 @@ +--- a/net/minecraft/nbt/NbtUtils.java ++++ b/net/minecraft/nbt/NbtUtils.java +@@ -149,8 +149,10 @@ + if (!nbt.contains("Name", 8)) { + return Blocks.AIR.defaultBlockState(); + } else { +- ResourceLocation resourceLocation = ResourceLocation.parse(nbt.getString("Name")); +- Optional> optional = blockLookup.get(ResourceKey.create(Registries.BLOCK, resourceLocation)); ++ // Paper start - Validate resource location ++ ResourceLocation resourceLocation = ResourceLocation.tryParse(nbt.getString("Name")); ++ Optional> optional = resourceLocation != null ? blockLookup.get(ResourceKey.create(Registries.BLOCK, resourceLocation)) : Optional.empty(); ++ // Paper end - Validate resource location + if (optional.isEmpty()) { + return Blocks.AIR.defaultBlockState(); + } else { diff --git a/paper-server/patches/sources/net/minecraft/resources/ResourceLocation.java.patch b/paper-server/patches/sources/net/minecraft/resources/ResourceLocation.java.patch index db09bb8255..4f2bd280fb 100644 --- a/paper-server/patches/sources/net/minecraft/resources/ResourceLocation.java.patch +++ b/paper-server/patches/sources/net/minecraft/resources/ResourceLocation.java.patch @@ -8,7 +8,21 @@ private final String namespace; private final String path; -@@ -246,7 +247,7 @@ +@@ -40,6 +41,13 @@ + + assert isValidPath(path); + ++ // Paper start - Validate ResourceLocation ++ // Check for the max network string length (capped at Short.MAX_VALUE) as well as the max bytes of a StringTag (length written as an unsigned short) ++ final String resourceLocation = namespace + ":" + path; ++ if (resourceLocation.length() > Short.MAX_VALUE || io.netty.buffer.ByteBufUtil.utf8MaxBytes(resourceLocation) > 2 * Short.MAX_VALUE + 1) { ++ throw new ResourceLocationException("Resource location too long: " + resourceLocation); ++ } ++ // Paper end - Validate ResourceLocation + this.namespace = namespace; + this.path = path; + } +@@ -246,7 +254,7 @@ private static String assertValidNamespace(String namespace, String path) { if (!isValidNamespace(namespace)) { @@ -17,7 +31,7 @@ } else { return namespace; } -@@ -267,7 +268,7 @@ +@@ -267,7 +275,7 @@ private static String assertValidPath(String namespace, String path) { if (!isValidPath(path)) { diff --git a/paper-server/patches/sources/net/minecraft/world/RandomizableContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/RandomizableContainer.java.patch index f5c11bafc6..a79a33da44 100644 --- a/paper-server/patches/sources/net/minecraft/world/RandomizableContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/RandomizableContainer.java.patch @@ -9,10 +9,12 @@ this.setLootTable(lootTableId); this.setLootTableSeed(lootTableSeed); } -@@ -51,13 +51,14 @@ +@@ -50,14 +50,15 @@ + default boolean tryLoadLootTable(CompoundTag nbt) { if (nbt.contains("LootTable", 8)) { - this.setLootTable(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable")))); +- this.setLootTable(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable")))); ++ this.setLootTable(net.minecraft.Optionull.map(ResourceLocation.tryParse(nbt.getString("LootTable")), rl -> ResourceKey.create(Registries.LOOT_TABLE, rl))); // Paper - Validate ResourceLocation + if (this.lootableData() != null && this.getLootTable() != null) this.lootableData().loadNbt(nbt); // Paper - LootTable API if (nbt.contains("LootTableSeed", 4)) { this.setLootTableSeed(nbt.getLong("LootTableSeed")); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch index ed5e561816..1ff8d4806a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch @@ -141,6 +141,15 @@ entity.load(nbt); }, () -> { EntityType.LOGGER.warn("Skipping Entity with id {}", nbt.getString("id")); +@@ -638,7 +690,7 @@ + } + + public static Optional> by(CompoundTag nbt) { +- return BuiltInRegistries.ENTITY_TYPE.getOptional(ResourceLocation.parse(nbt.getString("id"))); ++ return BuiltInRegistries.ENTITY_TYPE.getOptional(ResourceLocation.tryParse(nbt.getString("id"))); // Paper - Validate ResourceLocation + } + + @Nullable @@ -657,7 +709,7 @@ } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Leashable.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Leashable.java.patch index a624b71821..aa36549d47 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Leashable.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Leashable.java.patch @@ -20,8 +20,18 @@ } default void readLeashData(CompoundTag nbt) { -@@ -64,7 +68,7 @@ - return new Leashable.LeashData(Either.left(nbt.getCompound("leash").getUUID("UUID"))); +@@ -61,10 +65,16 @@ + @Nullable + private static Leashable.LeashData readLeashDataInternal(CompoundTag nbt) { + if (nbt.contains("leash", 10)) { +- return new Leashable.LeashData(Either.left(nbt.getCompound("leash").getUUID("UUID"))); ++ // Paper start ++ final CompoundTag leashTag = nbt.getCompound("leash"); ++ if (!leashTag.hasUUID("UUID")) { ++ return null; ++ } ++ return new Leashable.LeashData(Either.left(leashTag.getUUID("UUID"))); ++ // Paper end } else { if (nbt.contains("leash", 11)) { - Either either = (Either) NbtUtils.readBlockPos(nbt, "leash").map(Either::right).orElse((Object) null); @@ -29,7 +39,7 @@ if (either != null) { return new Leashable.LeashData(either); -@@ -79,6 +83,11 @@ +@@ -79,6 +89,11 @@ if (leashData != null) { Either either = leashData.delayedLeashInfo; Entity entity = leashData.leashHolder; @@ -41,7 +51,7 @@ if (entity instanceof LeashFenceKnotEntity) { LeashFenceKnotEntity entityleash = (LeashFenceKnotEntity) entity; -@@ -121,7 +130,9 @@ +@@ -121,7 +136,9 @@ } if (entity.tickCount > 100) { @@ -51,7 +61,7 @@ ((Leashable) entity).setLeashData((Leashable.LeashData) null); } } -@@ -130,11 +141,11 @@ +@@ -130,11 +147,11 @@ } default void dropLeash() { @@ -65,7 +75,7 @@ } default void onLeashRemoved() {} -@@ -151,7 +162,9 @@ +@@ -151,7 +168,9 @@ ServerLevel worldserver = (ServerLevel) world; if (dropItem) { @@ -75,7 +85,7 @@ } if (sendPacket) { -@@ -171,7 +184,11 @@ +@@ -171,7 +190,11 @@ if (leashable_a != null && leashable_a.leashHolder != null) { if (!entity.isAlive() || !leashable_a.leashHolder.isAlive()) { @@ -88,7 +98,7 @@ ((Leashable) entity).dropLeash(); } else { ((Leashable) entity).removeLeash(); -@@ -187,7 +204,7 @@ +@@ -187,7 +210,7 @@ return; } @@ -97,7 +107,7 @@ ((Leashable) entity).leashTooFarBehaviour(); } else if ((double) f > 6.0D) { ((Leashable) entity).elasticRangeLeashBehaviour(entity1, f); -@@ -205,13 +222,27 @@ +@@ -205,13 +228,27 @@ } default void leashTooFarBehaviour() { @@ -127,7 +137,7 @@ } private static void legacyElasticRangeLeashBehaviour(E entity, Entity leashHolder, float distance) { -@@ -223,7 +254,7 @@ +@@ -223,7 +260,7 @@ } default void setLeashedTo(Entity leashHolder, boolean sendPacket) { @@ -136,7 +146,7 @@ } private static void setLeashedTo(E entity, Entity leashHolder, boolean sendPacket) { -@@ -254,7 +285,7 @@ +@@ -254,7 +291,7 @@ @Nullable default Entity getLeashHolder() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch index 2ff298a4ec..60b719c493 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -295,10 +295,25 @@ boolean flag = scoreboardteam != null && scoreboard.addPlayerToTeam(this.getStringUUID(), scoreboardteam); if (!flag) { -@@ -819,9 +922,32 @@ +@@ -806,22 +909,47 @@ + if (nbt.contains("SleepingX", 99) && nbt.contains("SleepingY", 99) && nbt.contains("SleepingZ", 99)) { + BlockPos blockposition = new BlockPos(nbt.getInt("SleepingX"), nbt.getInt("SleepingY"), nbt.getInt("SleepingZ")); - } ++ if (this.position().distanceToSqr(blockposition.getX(), blockposition.getY(), blockposition.getZ()) < 16 * 16) { // Paper - The sleeping pos will always also set the actual pos, so a desync suggests something is wrong + this.setSleepingPos(blockposition); + this.entityData.set(LivingEntity.DATA_POSE, Pose.SLEEPING); + if (!this.firstTick) { + this.setPosToBed(blockposition); + } ++ } // Paper - The sleeping pos will always also set the actual pos, so a desync suggests something is wrong + } + if (nbt.contains("Brain", 10)) { + this.brain = this.makeBrain(new Dynamic(NbtOps.INSTANCE, nbt.get("Brain"))); ++ } ++ ++ } ++ + // CraftBukkit start + private boolean isTickingEffects = false; + private List effectsToProcess = Lists.newArrayList(); @@ -312,15 +327,15 @@ + private ProcessableEffect(MobEffectInstance effect, EntityPotionEffectEvent.Cause cause) { + this.effect = effect; + this.cause = cause; -+ } -+ + } + + private ProcessableEffect(Holder type, EntityPotionEffectEvent.Cause cause) { + this.type = type; + this.cause = cause; + } -+ } + } + // CraftBukkit end -+ + protected void tickEffects() { Iterator> iterator = this.activeEffects.keySet().iterator(); @@ -328,7 +343,7 @@ try { while (iterator.hasNext()) { Holder holder = (Holder) iterator.next(); -@@ -831,6 +957,12 @@ +@@ -831,6 +959,12 @@ this.onEffectUpdated(mobeffect, true, (Entity) null); })) { if (!this.level().isClientSide) { @@ -341,7 +356,7 @@ iterator.remove(); this.onEffectsRemoved(List.of(mobeffect)); } -@@ -841,6 +973,17 @@ +@@ -841,6 +975,17 @@ } catch (ConcurrentModificationException concurrentmodificationexception) { ; } @@ -359,7 +374,7 @@ if (this.effectsDirty) { if (!this.level().isClientSide) { -@@ -921,7 +1064,7 @@ +@@ -921,7 +1066,7 @@ } public boolean canAttack(LivingEntity target) { @@ -368,7 +383,7 @@ } public boolean canBeSeenAsEnemy() { -@@ -952,17 +1095,36 @@ +@@ -952,17 +1097,36 @@ this.entityData.set(LivingEntity.DATA_EFFECT_PARTICLES, List.of()); } @@ -409,7 +424,7 @@ } } -@@ -987,24 +1149,63 @@ +@@ -987,24 +1151,63 @@ return this.addEffect(effect, (Entity) null); } @@ -481,7 +496,7 @@ return flag; } } -@@ -1031,14 +1232,40 @@ +@@ -1031,14 +1234,40 @@ return this.getType().is(EntityTypeTags.INVERTED_HEALING_AND_HARM); } @@ -524,7 +539,7 @@ if (mobeffect != null) { this.onEffectsRemoved(List.of(mobeffect)); return true; -@@ -1142,20 +1369,65 @@ +@@ -1142,20 +1371,65 @@ } @@ -591,7 +606,7 @@ this.entityData.set(LivingEntity.DATA_HEALTH_ID, Mth.clamp(health, 0.0F, this.getMaxHealth())); } -@@ -1167,7 +1439,7 @@ +@@ -1167,7 +1441,7 @@ public boolean hurtServer(ServerLevel world, DamageSource source, float amount) { if (this.isInvulnerableTo(world, source)) { return false; @@ -600,7 +615,7 @@ return false; } else if (source.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; -@@ -1182,10 +1454,11 @@ +@@ -1182,10 +1456,11 @@ } float f1 = amount; @@ -614,7 +629,7 @@ this.hurtCurrentlyUsedShield(amount); f2 = amount; amount = 0.0F; -@@ -1202,15 +1475,26 @@ +@@ -1202,14 +1477,25 @@ flag = true; } @@ -630,7 +645,7 @@ this.hurtHelmet(source, amount); amount *= 0.75F; } - ++ + // CraftBukkit start + EntityDamageEvent event = this.handleEntityDamage(source, amount); + amount = 0; @@ -639,11 +654,10 @@ + amount += (float) event.getDamage(DamageModifier.FREEZING); + amount += (float) event.getDamage(DamageModifier.HARD_HAT); + // CraftBukkit end -+ + this.walkAnimation.setSpeed(1.5F); if (Float.isNaN(amount) || Float.isInfinite(amount)) { - amount = Float.MAX_VALUE; -@@ -1218,18 +1502,27 @@ +@@ -1218,18 +1504,27 @@ boolean flag1 = true; @@ -675,7 +689,7 @@ this.hurtDuration = 10; this.hurtTime = this.hurtDuration; } -@@ -1243,7 +1536,7 @@ +@@ -1243,7 +1538,7 @@ world.broadcastDamageEvent(this, source); } @@ -684,7 +698,7 @@ this.markHurt(); } -@@ -1263,7 +1556,7 @@ +@@ -1263,7 +1558,7 @@ d1 = source.getSourcePosition().z() - this.getZ(); } @@ -693,7 +707,7 @@ if (!flag) { this.indicateDamage(d0, d1); } -@@ -1272,17 +1565,18 @@ +@@ -1272,17 +1567,18 @@ if (this.isDeadOrDying()) { if (!this.checkTotemDeathProtection(source)) { @@ -716,7 +730,7 @@ if (flag2) { this.lastDamageSource = source; -@@ -1329,10 +1623,10 @@ +@@ -1329,10 +1625,10 @@ } @Nullable @@ -729,7 +743,7 @@ this.lastHurtByPlayerTime = 100; this.lastHurtByPlayer = entityhuman; return entityhuman; -@@ -1342,8 +1636,8 @@ +@@ -1342,8 +1638,8 @@ this.lastHurtByPlayerTime = 100; LivingEntity entityliving = entitywolf.getOwner(); @@ -740,7 +754,7 @@ this.lastHurtByPlayer = entityhuman1; } else { -@@ -1363,7 +1657,7 @@ +@@ -1363,7 +1659,7 @@ } protected void blockedByShield(LivingEntity target) { @@ -749,7 +763,7 @@ } private boolean checkTotemDeathProtection(DamageSource source) { -@@ -1375,20 +1669,33 @@ +@@ -1375,20 +1671,33 @@ InteractionHand[] aenumhand = InteractionHand.values(); int i = aenumhand.length; @@ -787,7 +801,7 @@ ServerPlayer entityplayer = (ServerPlayer) this; entityplayer.awardStat(Stats.ITEM_USED.get(itemstack.getItem())); -@@ -1468,6 +1775,7 @@ +@@ -1468,6 +1777,7 @@ Entity entity = damageSource.getEntity(); LivingEntity entityliving = this.getKillCredit(); @@ -795,7 +809,7 @@ if (entityliving != null) { entityliving.awardKillScore(this, damageSource); } -@@ -1477,26 +1785,61 @@ +@@ -1477,26 +1787,61 @@ } if (!this.level().isClientSide && this.hasCustomName()) { @@ -862,7 +876,7 @@ } } -@@ -1506,20 +1849,28 @@ +@@ -1506,20 +1851,28 @@ if (world instanceof ServerLevel worldserver) { boolean flag = false; @@ -894,7 +908,7 @@ this.level().addFreshEntity(entityitem); } } -@@ -1527,27 +1878,60 @@ +@@ -1527,27 +1880,60 @@ } } @@ -961,7 +975,7 @@ protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) {} public long getLootTableSeed() { -@@ -1612,19 +1996,35 @@ +@@ -1612,19 +1998,35 @@ } public void knockback(double strength, double x, double z) { @@ -1004,7 +1018,7 @@ } } -@@ -1683,6 +2083,20 @@ +@@ -1683,6 +2085,20 @@ return new LivingEntity.Fallsounds(SoundEvents.GENERIC_SMALL_FALL, SoundEvents.GENERIC_BIG_FALL); } @@ -1025,7 +1039,7 @@ public Optional getLastClimbablePos() { return this.lastClimbablePos; } -@@ -1757,9 +2171,14 @@ +@@ -1757,9 +2173,14 @@ int i = this.calculateFallDamage(fallDistance, damageMultiplier); if (i > 0) { @@ -1041,7 +1055,7 @@ return true; } else { return flag; -@@ -1830,7 +2249,7 @@ +@@ -1830,7 +2251,7 @@ protected float getDamageAfterArmorAbsorb(DamageSource source, float amount) { if (!source.is(DamageTypeTags.BYPASSES_ARMOR)) { @@ -1050,7 +1064,7 @@ amount = CombatRules.getDamageAfterAbsorb(this, amount, source, (float) this.getArmorValue(), (float) this.getAttributeValue(Attributes.ARMOR_TOUGHNESS)); } -@@ -1841,7 +2260,8 @@ +@@ -1841,7 +2262,8 @@ if (source.is(DamageTypeTags.BYPASSES_EFFECTS)) { return amount; } else { @@ -1060,7 +1074,7 @@ int i = (this.getEffect(MobEffects.DAMAGE_RESISTANCE).getAmplifier() + 1) * 5; int j = 25 - i; float f1 = amount * (float) j; -@@ -1884,18 +2304,154 @@ +@@ -1884,18 +2306,154 @@ } } @@ -1087,7 +1101,7 @@ + }; + float freezingModifier = freezing.apply((double) f).floatValue(); + f += freezingModifier; - ++ + com.google.common.base.Function hardHat = new com.google.common.base.Function() { + @Override + public Double apply(Double f) { @@ -1206,7 +1220,7 @@ + this.blockUsingShield((LivingEntity) entity); + } + } -+ + + boolean human = this instanceof net.minecraft.world.entity.player.Player; + float originalDamage = (float) event.getDamage(); + float absorptionModifier = (float) -event.getDamage(DamageModifier.ABSORPTION); @@ -1224,7 +1238,7 @@ if (entity instanceof ServerPlayer) { ServerPlayer entityplayer = (ServerPlayer) entity; -@@ -1904,13 +2460,48 @@ +@@ -1904,13 +2462,48 @@ } } @@ -1277,28 +1291,27 @@ } public CombatTracker getCombatTracker() { -@@ -1935,9 +2526,19 @@ +@@ -1935,8 +2528,18 @@ } public final void setArrowCount(int stuckArrowCount) { - this.entityData.set(LivingEntity.DATA_ARROW_COUNT_ID, stuckArrowCount); + // CraftBukkit start + this.setArrowCount(stuckArrowCount, false); - } - ++ } ++ + public final void setArrowCount(int i, boolean flag) { + ArrowBodyCountChangeEvent event = CraftEventFactory.callArrowBodyCountChangeEvent(this, this.getArrowCount(), i, flag); + if (event.isCancelled()) { + return; + } + this.entityData.set(LivingEntity.DATA_ARROW_COUNT_ID, event.getNewAmount()); -+ } + } + // CraftBukkit end -+ + public final int getStingerCount() { return (Integer) this.entityData.get(LivingEntity.DATA_STINGER_COUNT_ID); - } -@@ -1999,7 +2600,7 @@ +@@ -1999,7 +2602,7 @@ this.playSound(soundeffect, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); } @@ -1307,7 +1320,7 @@ this.setHealth(0.0F); this.die(this.damageSources().generic()); } -@@ -2182,6 +2783,12 @@ +@@ -2182,6 +2785,12 @@ public abstract ItemStack getItemBySlot(EquipmentSlot slot); @@ -1320,7 +1333,7 @@ public abstract void setItemSlot(EquipmentSlot slot, ItemStack stack); public Iterable getHandSlots() { -@@ -2292,17 +2899,29 @@ +@@ -2292,17 +2901,29 @@ return this.hasEffect(MobEffects.JUMP) ? 0.1F * ((float) this.getEffect(MobEffects.JUMP).getAmplifier() + 1.0F) : 0.0F; } @@ -1351,7 +1364,7 @@ this.addDeltaMovement(new Vec3((double) (-Mth.sin(f1)) * 0.2D, 0.0D, (double) Mth.cos(f1) * 0.2D)); } -@@ -2494,7 +3113,7 @@ +@@ -2494,7 +3115,7 @@ } @@ -1360,7 +1373,7 @@ Vec3 vec3d1 = this.getRiddenInput(controllingPlayer, movementInput); this.tickRidden(controllingPlayer, vec3d1); -@@ -2507,13 +3126,13 @@ +@@ -2507,13 +3128,13 @@ } @@ -1377,7 +1390,7 @@ return this.getSpeed(); } -@@ -2571,7 +3190,7 @@ +@@ -2571,7 +3192,7 @@ double d1 = Mth.clamp(motion.z, -0.15000000596046448D, 0.15000000596046448D); double d2 = Math.max(motion.y, -0.15000000596046448D); @@ -1386,7 +1399,7 @@ d2 = 0.0D; } -@@ -2586,7 +3205,7 @@ +@@ -2586,7 +3207,7 @@ } protected float getFlyingSpeed() { @@ -1395,7 +1408,7 @@ } public float getSpeed() { -@@ -2634,7 +3253,7 @@ +@@ -2634,7 +3255,7 @@ } } @@ -1404,7 +1417,7 @@ if (this.tickCount % 20 == 0) { this.getCombatTracker().recheckStatus(); } -@@ -2687,37 +3306,15 @@ +@@ -2687,37 +3308,15 @@ gameprofilerfiller.pop(); gameprofilerfiller.push("rangeChecks"); @@ -1422,8 +1435,7 @@ - while (this.yBodyRot - this.yBodyRotO < -180.0F) { - this.yBodyRotO -= 360.0F; - } -+ this.xRotO += Math.round((this.getXRot() - this.xRotO) / 360.0F) * 360.0F; - +- - while (this.yBodyRot - this.yBodyRotO >= 180.0F) { - this.yBodyRotO += 360.0F; - } @@ -1439,7 +1451,8 @@ - while (this.yHeadRot - this.yHeadRotO < -180.0F) { - this.yHeadRotO -= 360.0F; - } -- ++ this.xRotO += Math.round((this.getXRot() - this.xRotO) / 360.0F) * 360.0F; + - while (this.yHeadRot - this.yHeadRotO >= 180.0F) { - this.yHeadRotO += 360.0F; - } @@ -1448,7 +1461,7 @@ gameprofilerfiller.pop(); this.animStep += f2; -@@ -2741,7 +3338,7 @@ +@@ -2741,7 +3340,7 @@ this.elytraAnimationState.tick(); } @@ -1457,7 +1470,7 @@ Map map = this.collectEquipmentChanges(); if (map != null) { -@@ -2778,10 +3375,17 @@ +@@ -2778,10 +3377,17 @@ throw new MatchException((String) null, (Throwable) null); } @@ -1477,7 +1490,7 @@ if (map == null) { map = Maps.newEnumMap(EquipmentSlot.class); } -@@ -2974,8 +3578,10 @@ +@@ -2974,8 +3580,10 @@ } else if (this.isInLava() && (!this.onGround() || d3 > d4)) { this.jumpInLiquid(FluidTags.LAVA); } else if ((this.onGround() || flag && d3 <= d4) && this.noJumpDelay == 0) { @@ -1488,7 +1501,7 @@ } } else { this.noJumpDelay = 0; -@@ -3000,7 +3606,7 @@ +@@ -3000,7 +3608,7 @@ { LivingEntity entityliving = this.getControllingPassenger(); @@ -1497,7 +1510,7 @@ if (this.isAlive()) { this.travelRidden(entityhuman, vec3d1); break label112; -@@ -3017,7 +3623,7 @@ +@@ -3017,7 +3625,7 @@ this.calculateEntityAnimation(this instanceof FlyingAnimal); gameprofilerfiller.pop(); gameprofilerfiller.push("freezing"); @@ -1506,7 +1519,7 @@ int i = this.getTicksFrozen(); if (this.isInPowderSnow && this.canFreeze()) { -@@ -3046,6 +3652,20 @@ +@@ -3046,6 +3654,20 @@ this.pushEntities(); gameprofilerfiller.pop(); @@ -1527,7 +1540,7 @@ world = this.level(); if (world instanceof ServerLevel worldserver) { if (this.isSensitiveToWater() && this.isInWaterRainOrBubble()) { -@@ -3063,6 +3683,7 @@ +@@ -3063,6 +3685,7 @@ this.checkSlowFallDistance(); if (!this.level().isClientSide) { if (!this.canGlide()) { @@ -1535,7 +1548,7 @@ this.setSharedFlag(7, false); return; } -@@ -3113,12 +3734,26 @@ +@@ -3113,12 +3736,26 @@ Level world = this.level(); if (!(world instanceof ServerLevel worldserver)) { @@ -1565,7 +1578,7 @@ if (i > 0 && list.size() > i - 1 && this.random.nextInt(4) == 0) { int j = 0; -@@ -3138,10 +3773,12 @@ +@@ -3138,10 +3775,12 @@ } Iterator iterator1 = list.iterator(); @@ -1580,7 +1593,7 @@ this.doPush(entity1); } } -@@ -3190,10 +3827,16 @@ +@@ -3190,10 +3829,16 @@ @Override public void stopRiding() { @@ -1599,7 +1612,7 @@ this.dismountVehicle(entity); } -@@ -3258,7 +3901,7 @@ +@@ -3258,7 +3903,7 @@ } public void onItemPickup(ItemEntity item) { @@ -1608,7 +1621,7 @@ if (entity instanceof ServerPlayer) { CriteriaTriggers.THROWN_ITEM_PICKED_UP_BY_ENTITY.trigger((ServerPlayer) entity, item.getItem(), this); -@@ -3268,7 +3911,7 @@ +@@ -3268,7 +3913,7 @@ public void take(Entity item, int count) { if (!item.isRemoved() && !this.level().isClientSide && (item instanceof ItemEntity || item instanceof AbstractArrow || item instanceof ExperienceOrb)) { @@ -1617,7 +1630,7 @@ } } -@@ -3284,7 +3927,8 @@ +@@ -3284,7 +3929,8 @@ Vec3 vec3d = new Vec3(this.getX(), this.getEyeY(), this.getZ()); Vec3 vec3d1 = new Vec3(entity.getX(), entityY, entity.getZ()); @@ -1627,7 +1640,7 @@ } } -@@ -3305,15 +3949,29 @@ +@@ -3305,15 +3951,29 @@ @Override public boolean isPickable() { @@ -1659,7 +1672,7 @@ public float getYHeadRot() { return this.yHeadRot; } -@@ -3342,7 +4000,7 @@ +@@ -3342,7 +4002,7 @@ } public final void setAbsorptionAmount(float absorptionAmount) { @@ -1668,7 +1681,7 @@ } protected void internalSetAbsorptionAmount(float absorptionAmount) { -@@ -3410,9 +4068,14 @@ +@@ -3410,9 +4070,14 @@ } public void startUsingItem(InteractionHand hand) { @@ -1684,7 +1697,7 @@ this.useItem = itemstack; this.useItemRemaining = itemstack.getUseDuration(this); if (!this.level().isClientSide) { -@@ -3483,13 +4146,50 @@ +@@ -3483,13 +4148,50 @@ this.releaseUsingItem(); } else { if (!this.useItem.isEmpty() && this.isUsingItem()) { @@ -1736,7 +1749,7 @@ } } -@@ -3512,6 +4212,7 @@ +@@ -3512,6 +4214,7 @@ public void releaseUsingItem() { if (!this.useItem.isEmpty()) { @@ -1744,7 +1757,7 @@ this.useItem.releaseUsing(this.level(), this, this.getUseItemRemainingTicks()); if (this.useItem.useOnRelease()) { this.updatingUsingItem(); -@@ -3544,12 +4245,69 @@ +@@ -3544,12 +4247,69 @@ if (this.isUsingItem() && !this.useItem.isEmpty()) { Item item = this.useItem.getItem(); @@ -1815,7 +1828,7 @@ public boolean isSuppressingSlidingDownLadder() { return this.isShiftKeyDown(); } -@@ -3568,12 +4326,18 @@ +@@ -3568,12 +4328,18 @@ } public boolean randomTeleport(double x, double y, double z, boolean particleEffects) { @@ -1836,7 +1849,7 @@ Level world = this.level(); if (world.hasChunkAt(blockposition)) { -@@ -3592,18 +4356,43 @@ +@@ -3592,18 +4358,43 @@ } if (flag2) { @@ -1884,7 +1897,7 @@ world.broadcastEntityEvent(this, (byte) 46); } -@@ -3613,7 +4402,7 @@ +@@ -3613,7 +4404,7 @@ entitycreature.getNavigation().stop(); } @@ -1893,7 +1906,7 @@ } } -@@ -3706,7 +4495,7 @@ +@@ -3706,7 +4497,7 @@ } public void stopSleeping() { @@ -1902,7 +1915,7 @@ Level world = this.level(); java.util.Objects.requireNonNull(world); -@@ -3718,9 +4507,9 @@ +@@ -3718,9 +4509,9 @@ this.level().setBlock(blockposition, (BlockState) iblockdata.setValue(BedBlock.OCCUPIED, false), 3); Vec3 vec3d = (Vec3) BedBlock.findStandUpPosition(this.getType(), this.level(), blockposition, enumdirection, this.getYRot()).orElseGet(() -> { @@ -1914,7 +1927,7 @@ }); Vec3 vec3d1 = Vec3.atBottomCenterOf(blockposition).subtract(vec3d).normalize(); float f = (float) Mth.wrapDegrees(Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D); -@@ -3740,7 +4529,7 @@ +@@ -3740,7 +4531,7 @@ @Nullable public Direction getBedOrientation() { @@ -1923,7 +1936,7 @@ return blockposition != null ? BedBlock.getBedOrientation(this.level(), blockposition) : null; } -@@ -3905,7 +4694,7 @@ +@@ -3905,7 +4696,7 @@ public float maxUpStep() { float f = (float) this.getAttributeValue(Attributes.STEP_HEIGHT); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch index 945d862f95..aeaafc3a1b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch @@ -35,12 +35,13 @@ protected Mob(EntityType type, Level world) { super(type, world); this.handItems = NonNullList.withSize(2, ItemStack.EMPTY); -@@ -158,7 +172,13 @@ +@@ -157,8 +171,14 @@ + if (world instanceof ServerLevel) { this.registerGoals(); } - -+ } + ++ } + + // CraftBukkit start + public void setPersistenceRequired(boolean persistenceRequired) { + this.persistenceRequired = persistenceRequired; @@ -49,7 +50,7 @@ protected void registerGoals() {} -@@ -264,11 +284,42 @@ +@@ -264,13 +284,44 @@ @Nullable protected final LivingEntity getTargetFromBrain() { @@ -61,8 +62,8 @@ - this.target = target; + // CraftBukkit start - fire event + this.setTarget(target, EntityTargetEvent.TargetReason.UNKNOWN, true); -+ } -+ + } + + public boolean setTarget(LivingEntity entityliving, EntityTargetEvent.TargetReason reason, boolean fireEvent) { + if (this.getTarget() == entityliving) return false; + if (fireEvent) { @@ -91,9 +92,11 @@ + this.target = entityliving; + return true; + // CraftBukkit end - } - ++ } ++ @Override + public boolean canAttackType(EntityType type) { + return type != EntityType.GHAST; @@ -399,6 +450,12 @@ return null; } @@ -135,7 +138,15 @@ ListTag nbttaglist; CompoundTag nbttagcompound1; int i; -@@ -547,6 +616,11 @@ +@@ -540,13 +609,18 @@ + this.readLeashData(nbt); + this.setLeftHanded(nbt.getBoolean("LeftHanded")); + if (nbt.contains("DeathLootTable", 8)) { +- this.lootTable = Optional.of(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("DeathLootTable")))); ++ this.lootTable = Optional.ofNullable(ResourceLocation.tryParse(nbt.getString("DeathLootTable"))).map((rs) -> ResourceKey.create(Registries.LOOT_TABLE, rs)); // Paper - Validate ResourceLocation + } else { + this.lootTable = Optional.empty(); + } this.lootTableSeed = nbt.getLong("DeathLootTableSeed"); this.setNoAi(nbt.getBoolean("NoAI")); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch index c09d1374fb..4899e75462 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch @@ -216,6 +216,15 @@ } } +@@ -665,7 +710,7 @@ + this.setCritArrow(nbt.getBoolean("crit")); + this.setPierceLevel(nbt.getByte("PierceLevel")); + if (nbt.contains("SoundEvent", 8)) { +- this.soundEvent = (SoundEvent) BuiltInRegistries.SOUND_EVENT.getOptional(ResourceLocation.parse(nbt.getString("SoundEvent"))).orElse(this.getDefaultHitGroundSoundEvent()); ++ this.soundEvent = (SoundEvent) BuiltInRegistries.SOUND_EVENT.getOptional(ResourceLocation.tryParse(nbt.getString("SoundEvent"))).orElse(this.getDefaultHitGroundSoundEvent()); // Paper - Validate resource location + } + + if (nbt.contains("item", 10)) { @@ -675,7 +720,7 @@ } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/ContainerEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/ContainerEntity.java.patch index 0e502d4f10..b9d1729134 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/ContainerEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/ContainerEntity.java.patch @@ -17,7 +17,8 @@ default void readChestVehicleSaveData(CompoundTag nbt, HolderLookup.Provider registries) { this.clearItemStacks(); if (nbt.contains("LootTable", 8)) { - this.setContainerLootTable(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable")))); +- this.setContainerLootTable(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable")))); ++ this.setContainerLootTable(net.minecraft.Optionull.map(ResourceLocation.tryParse(nbt.getString("LootTable")), rl -> ResourceKey.create(Registries.LOOT_TABLE, rl))); // Paper - Validate ResourceLocation + // Paper start - LootTable API + if (this.getContainerLootTable() != null) { + this.lootableData().loadNbt(nbt); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch index 174904cbed..8438fd826a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch @@ -80,8 +80,16 @@ private boolean isLit() { return this.litTimeRemaining > 0; } -@@ -135,6 +181,11 @@ - this.recipesUsed.put(ResourceKey.create(Registries.RECIPE, ResourceLocation.parse(s)), nbttagcompound1.getInt(s)); +@@ -132,9 +178,18 @@ + while (iterator.hasNext()) { + String s = (String) iterator.next(); + +- this.recipesUsed.put(ResourceKey.create(Registries.RECIPE, ResourceLocation.parse(s)), nbttagcompound1.getInt(s)); ++ // Paper start - Validate ResourceLocation ++ final ResourceLocation resourceLocation = ResourceLocation.tryParse(s); ++ if (resourceLocation != null) { ++ this.recipesUsed.put(ResourceKey.create(Registries.RECIPE, resourceLocation), nbttagcompound1.getInt(s)); ++ } } + // Paper start - cook speed multiplier API @@ -92,7 +100,7 @@ } @Override -@@ -144,6 +195,7 @@ +@@ -144,6 +199,7 @@ nbt.putShort("cooking_total_time", (short) this.cookingTotalTime); nbt.putShort("lit_time_remaining", (short) this.litTimeRemaining); nbt.putShort("lit_total_time", (short) this.litTotalTime); @@ -100,7 +108,7 @@ ContainerHelper.saveAllItems(nbt, this.items, registries); CompoundTag nbttagcompound1 = new CompoundTag(); -@@ -175,7 +227,7 @@ +@@ -175,7 +231,7 @@ RecipeHolder recipeholder; if (flag2) { @@ -109,7 +117,7 @@ } else { recipeholder = null; } -@@ -183,11 +235,22 @@ +@@ -183,11 +239,22 @@ int i = blockEntity.getMaxStackSize(); if (!blockEntity.isLit() && AbstractFurnaceBlockEntity.canBurn(world.registryAccess(), recipeholder, singlerecipeinput, blockEntity.items, i)) { @@ -135,7 +143,7 @@ Item item = itemstack.getItem(); itemstack.shrink(1); -@@ -199,11 +262,23 @@ +@@ -199,11 +266,23 @@ } if (blockEntity.isLit() && AbstractFurnaceBlockEntity.canBurn(world.registryAccess(), recipeholder, singlerecipeinput, blockEntity.items, i)) { @@ -162,7 +170,7 @@ blockEntity.setRecipeUsed(recipeholder); } -@@ -242,20 +317,47 @@ +@@ -242,20 +321,47 @@ } } @@ -176,11 +184,11 @@ + ItemStack itemstack = (ItemStack) nonnulllist.get(0); + ItemStack itemstack1 = ((AbstractCookingRecipe) recipeholder.value()).assemble(singlerecipeinput, iregistrycustom); + ItemStack itemstack2 = (ItemStack) nonnulllist.get(2); -+ + + // CraftBukkit start - fire FurnaceSmeltEvent + CraftItemStack source = CraftItemStack.asCraftMirror(itemstack); + org.bukkit.inventory.ItemStack result = CraftItemStack.asBukkitCopy(itemstack1); - ++ + FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(CraftBlock.at(world, blockposition), source, result, (org.bukkit.inventory.CookingRecipe) recipeholder.toBukkitRecipe()); // Paper - Add recipe to cook events + world.getCraftServer().getPluginManager().callEvent(furnaceSmeltEvent); + @@ -218,7 +226,7 @@ } itemstack.shrink(1); -@@ -269,12 +371,14 @@ +@@ -269,12 +375,14 @@ return fuelRegistry.burnDuration(stack); } @@ -237,7 +245,7 @@ } @Override -@@ -320,12 +424,11 @@ +@@ -320,12 +428,11 @@ if (world instanceof ServerLevel) { ServerLevel worldserver = (ServerLevel) world; @@ -251,7 +259,7 @@ } @Override -@@ -358,19 +461,19 @@ +@@ -358,19 +465,19 @@ } @Override @@ -276,7 +284,7 @@ } } -@@ -378,41 +481,56 @@ +@@ -378,41 +485,56 @@ } public List> getRecipesToAwardAndPopExperience(ServerLevel world, Vec3 pos) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrushableBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrushableBlockEntity.java.patch index 95c49f058b..57515e3834 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrushableBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrushableBlockEntity.java.patch @@ -25,3 +25,12 @@ this.item = ItemStack.EMPTY; } +@@ -185,7 +194,7 @@ + + private boolean tryLoadLootTable(CompoundTag nbt) { + if (nbt.contains("LootTable", 8)) { +- this.lootTable = ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable"))); ++ this.lootTable = net.minecraft.Optionull.map(ResourceLocation.tryParse(nbt.getString("LootTable")), rl -> ResourceKey.create(Registries.LOOT_TABLE, rl)); // Paper - Validate ResourceLocation + this.lootTableSeed = nbt.getLong("LootTableSeed"); + return true; + } else {