Skip Improve-exact-choice-recipe-ingredients for now
This commit is contained in:
parent
8851d25a4d
commit
f677393a88
27 changed files with 129 additions and 158 deletions
|
@ -1,27 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Phoenix616 <mail@moep.tv>
|
||||
Date: Tue, 18 Sep 2018 23:53:23 +0100
|
||||
Subject: [PATCH] PreSpawnerSpawnEvent
|
||||
|
||||
This adds a separate event before an entity is spawned by a spawner
|
||||
which contains the location of the spawner too similarly to how the
|
||||
SpawnerSpawnEvent gets called instead of the CreatureSpawnEvent for
|
||||
spawners.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
index d13abdcc7a54bdecf853c883911ef535733610b4..ee897b8c9462dbb3d7be9a2994753155065ce205 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -133,10 +133,10 @@ public abstract class BaseSpawner {
|
||||
continue;
|
||||
}
|
||||
// Paper start - PreCreatureSpawnEvent
|
||||
- com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
|
||||
+ com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent event = new com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent(
|
||||
io.papermc.paper.util.MCUtil.toLocation(world, d0, d1, d2),
|
||||
org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(optional.get()),
|
||||
- org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER
|
||||
+ io.papermc.paper.util.MCUtil.toLocation(world, pos)
|
||||
);
|
||||
if (!event.callEvent()) {
|
||||
flag = true;
|
|
@ -1,108 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sat, 22 Sep 2018 00:33:08 -0500
|
||||
Subject: [PATCH] Add LivingEntity#getTargetEntity
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 64aa52c2d1fe50d304d75ebb197e8a834016c3cf..7bc0a66602d77902d83d6ca515da48e3453de900 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -127,6 +127,7 @@ import net.minecraft.world.level.storage.loot.LootTable;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
+import net.minecraft.world.phys.EntityHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.scores.PlayerTeam;
|
||||
@@ -4044,6 +4045,38 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
return this.level().clip(raytrace);
|
||||
}
|
||||
|
||||
+ public @Nullable EntityHitResult getTargetEntity(int maxDistance) {
|
||||
+ if (maxDistance < 1 || maxDistance > 120) {
|
||||
+ throw new IllegalArgumentException("maxDistance must be between 1-120");
|
||||
+ }
|
||||
+
|
||||
+ Vec3 start = this.getEyePosition(1.0F);
|
||||
+ Vec3 direction = this.getLookAngle();
|
||||
+ Vec3 end = start.add(direction.x * maxDistance, direction.y * maxDistance, direction.z * maxDistance);
|
||||
+
|
||||
+ List<Entity> entityList = this.level().getEntities(this, getBoundingBox().expandTowards(direction.x * maxDistance, direction.y * maxDistance, direction.z * maxDistance).inflate(1.0D, 1.0D, 1.0D), EntitySelector.NO_SPECTATORS.and(Entity::isPickable));
|
||||
+
|
||||
+ double distance = 0.0D;
|
||||
+ EntityHitResult result = null;
|
||||
+
|
||||
+ for (Entity entity : entityList) {
|
||||
+ final double inflationAmount = (double) entity.getPickRadius();
|
||||
+ AABB aabb = entity.getBoundingBox().inflate(inflationAmount, inflationAmount, inflationAmount);
|
||||
+ Optional<Vec3> rayTraceResult = aabb.clip(start, end);
|
||||
+
|
||||
+ if (rayTraceResult.isPresent()) {
|
||||
+ Vec3 rayTrace = rayTraceResult.get();
|
||||
+ double distanceTo = start.distanceToSqr(rayTrace);
|
||||
+ if (distanceTo < distance || distance == 0.0D) {
|
||||
+ result = new EntityHitResult(entity, rayTrace);
|
||||
+ distance = distanceTo;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return result;
|
||||
+ }
|
||||
+
|
||||
public int shieldBlockingDelay = this.level().paperConfig().misc.shieldBlockingDelay;
|
||||
|
||||
public int getShieldBlockingDelay() {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
index c8ac50351b7b1b2f4afc138570b8098a3c0ce1ba..c0684f1864ece26b4f337ac615db04f615957c13 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.bukkit.craftbukkit.entity;
|
||||
|
||||
+import com.destroystokyo.paper.entity.TargetEntityInfo;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.ArrayList;
|
||||
@@ -227,6 +228,39 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
+
|
||||
+ public Entity getTargetEntity(int maxDistance, boolean ignoreBlocks) {
|
||||
+ net.minecraft.world.phys.EntityHitResult rayTrace = rayTraceEntity(maxDistance, ignoreBlocks);
|
||||
+ return rayTrace == null ? null : rayTrace.getEntity().getBukkitEntity();
|
||||
+ }
|
||||
+
|
||||
+ public TargetEntityInfo getTargetEntityInfo(int maxDistance, boolean ignoreBlocks) {
|
||||
+ net.minecraft.world.phys.EntityHitResult rayTrace = rayTraceEntity(maxDistance, ignoreBlocks);
|
||||
+ return rayTrace == null ? null : new TargetEntityInfo(rayTrace.getEntity().getBukkitEntity(), new org.bukkit.util.Vector(rayTrace.getLocation().x, rayTrace.getLocation().y, rayTrace.getLocation().z));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public RayTraceResult rayTraceEntities(int maxDistance, boolean ignoreBlocks) {
|
||||
+ net.minecraft.world.phys.EntityHitResult rayTrace = this.rayTraceEntity(maxDistance, ignoreBlocks);
|
||||
+ return rayTrace == null ? null : new org.bukkit.util.RayTraceResult(org.bukkit.craftbukkit.util.CraftVector.toBukkit(rayTrace.getLocation()), rayTrace.getEntity().getBukkitEntity());
|
||||
+ }
|
||||
+
|
||||
+ public net.minecraft.world.phys.EntityHitResult rayTraceEntity(int maxDistance, boolean ignoreBlocks) {
|
||||
+ net.minecraft.world.phys.EntityHitResult rayTrace = getHandle().getTargetEntity(maxDistance);
|
||||
+ if (rayTrace == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ if (!ignoreBlocks) {
|
||||
+ net.minecraft.world.phys.HitResult rayTraceBlocks = getHandle().getRayTrace(maxDistance, net.minecraft.world.level.ClipContext.Fluid.NONE);
|
||||
+ if (rayTraceBlocks != null) {
|
||||
+ net.minecraft.world.phys.Vec3 eye = getHandle().getEyePosition(1.0F);
|
||||
+ if (eye.distanceToSqr(rayTraceBlocks.getLocation()) <= eye.distanceToSqr(rayTrace.getLocation())) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return rayTrace;
|
||||
+ }
|
||||
// Paper end
|
||||
|
||||
@Override
|
|
@ -1,42 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 7 Oct 2018 00:54:21 -0500
|
||||
Subject: [PATCH] Add sun related API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.Mob isSunBurnTick()Z
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 333e3109d19c867e8a74f20693952bdb3df804e4..20bb365b188c7081123db87186f0e1a999758817 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -756,6 +756,13 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean isDayTime() {
|
||||
+ return getHandle().isDay();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public long getGameTime() {
|
||||
return this.world.levelData.getGameTime();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
|
||||
index d597eea5d5c2f223e87bff06f292619657596f1f..2a8596e4f9d7be966c18e867c2c7b5bfbea9742c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
|
||||
@@ -90,4 +90,11 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob {
|
||||
public long getSeed() {
|
||||
return this.getHandle().lootTableSeed;
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean isInDaylight() {
|
||||
+ return getHandle().isSunBurnTick();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sat, 29 Sep 2018 16:08:23 -0500
|
||||
Subject: [PATCH] Turtle API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.animal.Turtle getHomePos()Lnet/minecraft/core/BlockPos;
|
||||
public net.minecraft.world.entity.animal.Turtle setHasEgg(Z)V
|
||||
public net.minecraft.world.entity.animal.Turtle isGoingHome()Z
|
||||
public net.minecraft.world.entity.animal.Turtle setGoingHome(Z)V
|
||||
public net.minecraft.world.entity.animal.Turtle isTravelling()Z
|
||||
public net.minecraft.world.entity.animal.Turtle setTravelling(Z)V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
index 6f90ee749aed98b97868aa40fc233d164ddc2ef6..34e6bf677a9f4548f3febe6d57e6af9602530271 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
@@ -487,14 +487,17 @@ public class Turtle extends Animal {
|
||||
|
||||
if (!this.turtle.isInWater() && this.isReachedTarget()) {
|
||||
if (this.turtle.layEggCounter < 1) {
|
||||
- this.turtle.setLayingEgg(true);
|
||||
+ this.turtle.setLayingEgg(new com.destroystokyo.paper.event.entity.TurtleStartDiggingEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(this.turtle.level(), this.blockPos)).callEvent()); // Paper - Turtle API
|
||||
} else if (this.turtle.layEggCounter > this.adjustedTickDelay(200)) {
|
||||
Level world = this.turtle.level();
|
||||
|
||||
- if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.turtle, this.blockPos.above(), (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1))) { // CraftBukkit
|
||||
+ // Paper start - Turtle API
|
||||
+ int eggCount = this.turtle.random.nextInt(4) + 1;
|
||||
+ com.destroystokyo.paper.event.entity.TurtleLayEggEvent layEggEvent = new com.destroystokyo.paper.event.entity.TurtleLayEggEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(this.turtle.level(), this.blockPos.above()), eggCount);
|
||||
+ if (layEggEvent.callEvent() && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.turtle, this.blockPos.above(), Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount()))) {
|
||||
world.playSound((Player) null, blockposition, SoundEvents.TURTLE_LAY_EGG, SoundSource.BLOCKS, 0.3F, 0.9F + world.random.nextFloat() * 0.2F);
|
||||
BlockPos blockposition1 = this.blockPos.above();
|
||||
- BlockState iblockdata = (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1);
|
||||
+ BlockState iblockdata = (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount()); // Paper
|
||||
|
||||
world.setBlock(blockposition1, iblockdata, 3);
|
||||
world.gameEvent((Holder) GameEvent.BLOCK_PLACE, blockposition1, GameEvent.Context.of(this.turtle, iblockdata));
|
||||
@@ -564,7 +567,7 @@ public class Turtle extends Animal {
|
||||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
- return this.turtle.isBaby() ? false : (this.turtle.hasEgg() ? true : (this.turtle.getRandom().nextInt(reducedTickDelay(700)) != 0 ? false : !this.turtle.getHomePos().closerToCenterThan(this.turtle.position(), 64.0D)));
|
||||
+ return this.turtle.isBaby() ? false : (this.turtle.hasEgg() ? true : (this.turtle.getRandom().nextInt(reducedTickDelay(700)) != 0 ? false : !this.turtle.getHomePos().closerToCenterThan(this.turtle.position(), 64.0D))) && new com.destroystokyo.paper.event.entity.TurtleGoHomeEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity()).callEvent(); // Paper - Turtle API
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTurtle.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTurtle.java
|
||||
index fac0317ff945db991e761ac8973f0d3d41ade26b..d44e6f4bb682d18c1497eee9fb2802f2bda6e840 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTurtle.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTurtle.java
|
||||
@@ -28,4 +28,31 @@ public class CraftTurtle extends CraftAnimals implements Turtle {
|
||||
public boolean isLayingEgg() {
|
||||
return this.getHandle().isLayingEgg();
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public org.bukkit.Location getHome() {
|
||||
+ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level(), this.getHandle().getHomePos());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setHome(org.bukkit.Location location) {
|
||||
+ this.getHandle().setHomePos(io.papermc.paper.util.MCUtil.toBlockPosition(location));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isGoingHome() {
|
||||
+ return this.getHandle().isGoingHome();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isDigging() {
|
||||
+ return this.getHandle().isLayingEgg();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setHasEgg(boolean hasEgg) {
|
||||
+ this.getHandle().setHasEgg(hasEgg);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Caleb Bassham <caleb.bassham@gmail.com>
|
||||
Date: Fri, 28 Sep 2018 02:32:19 -0500
|
||||
Subject: [PATCH] Call player spectator target events and improve
|
||||
implementation
|
||||
|
||||
Use a proper teleport for teleporting to entities in different
|
||||
worlds.
|
||||
|
||||
Implementation improvements authored by Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Validate that the target entity is valid and deny spectate
|
||||
requests from frozen players.
|
||||
|
||||
Also, make sure the entity is spawned to the client before
|
||||
sending the camera packet. If the entity isn't spawned clientside
|
||||
when it receives the camera packet, then the client will not
|
||||
spectate the target entity.
|
||||
|
||||
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index fa8640f961b93dc811296131dfda58faa1908add..15328d344a26f5c40011ee6ba0bc54dd5ab0b87b 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -2182,6 +2182,21 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
|
||||
this.camera = (Entity) (entity == null ? this : entity);
|
||||
if (entity1 != this.camera) {
|
||||
+ // Paper start - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity
|
||||
+ if (this.camera == this) {
|
||||
+ com.destroystokyo.paper.event.player.PlayerStopSpectatingEntityEvent playerStopSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStopSpectatingEntityEvent(this.getBukkitEntity(), entity1.getBukkitEntity());
|
||||
+ if (!playerStopSpectatingEntityEvent.callEvent()) {
|
||||
+ this.camera = entity1; // rollback camera entity again
|
||||
+ return;
|
||||
+ }
|
||||
+ } else {
|
||||
+ com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent playerStartSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent(this.getBukkitEntity(), entity1.getBukkitEntity(), entity.getBukkitEntity());
|
||||
+ if (!playerStartSpectatingEntityEvent.callEvent()) {
|
||||
+ this.camera = entity1; // rollback camera entity again
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity
|
||||
Level world = this.camera.level();
|
||||
|
||||
if (world instanceof ServerLevel) {
|
|
@ -1,101 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Fri, 12 Oct 2018 14:10:46 -0500
|
||||
Subject: [PATCH] Add more Witch API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.monster.Witch usingTime
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Witch.java b/src/main/java/net/minecraft/world/entity/monster/Witch.java
|
||||
index f6d01d21745391595d61b191832be4c28a3e58cb..b8ff1e3d280171378fe383bcc7c6a855d20ae5d1 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Witch.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java
|
||||
@@ -151,21 +151,7 @@ public class Witch extends Raider implements RangedAttackMob {
|
||||
}
|
||||
|
||||
if (holder != null) {
|
||||
- // Paper start
|
||||
- ItemStack potion = PotionContents.createItemStack(Items.POTION, holder);
|
||||
- potion = org.bukkit.craftbukkit.event.CraftEventFactory.handleWitchReadyPotionEvent(this, potion);
|
||||
- this.setItemSlot(EquipmentSlot.MAINHAND, potion);
|
||||
- // Paper end
|
||||
- this.usingTime = this.getMainHandItem().getUseDuration(this);
|
||||
- this.setUsingItem(true);
|
||||
- if (!this.isSilent()) {
|
||||
- this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.WITCH_DRINK, this.getSoundSource(), 1.0F, 0.8F + this.random.nextFloat() * 0.4F);
|
||||
- }
|
||||
-
|
||||
- AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
|
||||
-
|
||||
- attributemodifiable.removeModifier(Witch.SPEED_MODIFIER_DRINKING_ID);
|
||||
- attributemodifiable.addTransientModifier(Witch.SPEED_MODIFIER_DRINKING);
|
||||
+ this.setDrinkingPotion(PotionContents.createItemStack(Items.POTION, holder)); // Paper - logic moved into setDrinkingPotion, copy exact impl into the method and then comment out
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,6 +163,23 @@ public class Witch extends Raider implements RangedAttackMob {
|
||||
super.aiStep();
|
||||
}
|
||||
|
||||
+ // Paper start - moved to its own method
|
||||
+ public void setDrinkingPotion(ItemStack potion) {
|
||||
+ potion = org.bukkit.craftbukkit.event.CraftEventFactory.handleWitchReadyPotionEvent(this, potion);
|
||||
+ this.setItemSlot(EquipmentSlot.MAINHAND, potion);
|
||||
+ this.usingTime = this.getMainHandItem().getUseDuration(this);
|
||||
+ this.setUsingItem(true);
|
||||
+ if (!this.isSilent()) {
|
||||
+ this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.WITCH_DRINK, this.getSoundSource(), 1.0F, 0.8F + this.random.nextFloat() * 0.4F);
|
||||
+ }
|
||||
+
|
||||
+ AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
|
||||
+
|
||||
+ attributemodifiable.removeModifier(Witch.SPEED_MODIFIER_DRINKING_ID);
|
||||
+ attributemodifiable.addTransientModifier(Witch.SPEED_MODIFIER_DRINKING);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public SoundEvent getCelebrateSound() {
|
||||
return SoundEvents.WITCH_CELEBRATE;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWitch.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWitch.java
|
||||
index 524b5ba5995affc09eedf9a85d22e8b0b4efc156..4b3d783cabcb2de1a67d7fbfb6f525bfb493aed1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWitch.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWitch.java
|
||||
@@ -2,6 +2,13 @@ package org.bukkit.craftbukkit.entity;
|
||||
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.entity.Witch;
|
||||
+// Paper start
|
||||
+import com.destroystokyo.paper.entity.CraftRangedEntity;
|
||||
+import com.google.common.base.Preconditions;
|
||||
+import org.bukkit.Material;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.inventory.ItemStack;
|
||||
+// Paper end
|
||||
|
||||
public class CraftWitch extends CraftRaider implements Witch, com.destroystokyo.paper.entity.CraftRangedEntity<net.minecraft.world.entity.monster.Witch> { // Paper
|
||||
public CraftWitch(CraftServer server, net.minecraft.world.entity.monster.Witch entity) {
|
||||
@@ -22,4 +29,23 @@ public class CraftWitch extends CraftRaider implements Witch, com.destroystokyo.
|
||||
public boolean isDrinkingPotion() {
|
||||
return this.getHandle().isDrinkingPotion();
|
||||
}
|
||||
+ // Paper start
|
||||
+ public int getPotionUseTimeLeft() {
|
||||
+ return getHandle().usingTime;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setPotionUseTimeLeft(int ticks) {
|
||||
+ getHandle().usingTime = ticks;
|
||||
+ }
|
||||
+
|
||||
+ public ItemStack getDrinkingPotion() {
|
||||
+ return CraftItemStack.asCraftMirror(getHandle().getMainHandItem());
|
||||
+ }
|
||||
+
|
||||
+ public void setDrinkingPotion(ItemStack potion) {
|
||||
+ Preconditions.checkArgument(potion == null || potion.getType().isEmpty() || potion.getType() == Material.POTION, "must be potion, air, or null");
|
||||
+ getHandle().setDrinkingPotion(CraftItemStack.asNMSCopy(potion));
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Wed, 10 Oct 2018 21:22:44 -0500
|
||||
Subject: [PATCH] Check Drowned for Villager Aggression Config
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Drowned.java b/src/main/java/net/minecraft/world/entity/monster/Drowned.java
|
||||
index d4b3ce2bb2021625c90a3f51c6f9da6056b2e2ff..cff1b5e0e3fd32d82157d5f13d83d4abdfad7378 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Drowned.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Drowned.java
|
||||
@@ -81,7 +81,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
|
||||
this.goalSelector.addGoal(7, new RandomStrollGoal(this, 1.0D));
|
||||
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Drowned.class})).setAlertOthers(ZombifiedPiglin.class));
|
||||
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::okTarget));
|
||||
- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false));
|
||||
+ if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Paper - Check drowned for villager aggression config
|
||||
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
|
||||
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Axolotl.class, true, false));
|
||||
this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR));
|
|
@ -1,67 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gabriele C <sgdc3.mail@gmail.com>
|
||||
Date: Mon, 22 Oct 2018 17:34:10 +0200
|
||||
Subject: [PATCH] Add option to prevent players from moving into unloaded
|
||||
chunks #1551
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 5ed35d744a87290a03e9bf58143b5650501af0e6..6cf68d7173bc23c39261856f11cbd42de387bd60 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -494,9 +494,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
double d0 = entity.getX();
|
||||
double d1 = entity.getY();
|
||||
double d2 = entity.getZ();
|
||||
- double d3 = ServerGamePacketListenerImpl.clampHorizontal(packet.getX());
|
||||
- double d4 = ServerGamePacketListenerImpl.clampVertical(packet.getY());
|
||||
- double d5 = ServerGamePacketListenerImpl.clampHorizontal(packet.getZ());
|
||||
+ double d3 = ServerGamePacketListenerImpl.clampHorizontal(packet.getX()); final double toX = d3; // Paper - OBFHELPER
|
||||
+ double d4 = ServerGamePacketListenerImpl.clampVertical(packet.getY()); final double toY = d4; // Paper - OBFHELPER
|
||||
+ double d5 = ServerGamePacketListenerImpl.clampHorizontal(packet.getZ()); final double toZ = d5; // Paper - OBFHELPER
|
||||
float f = Mth.wrapDegrees(packet.getYRot());
|
||||
float f1 = Mth.wrapDegrees(packet.getXRot());
|
||||
double d6 = d3 - this.vehicleFirstGoodX;
|
||||
@@ -530,6 +530,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
speed *= 2f; // TODO: Get the speed of the vehicle instead of the player
|
||||
|
||||
+ // Paper start - Prevent moving into unloaded chunks
|
||||
+ if (this.player.level().paperConfig().chunks.preventMovingIntoUnloadedChunks && (
|
||||
+ !worldserver.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(this.player.position()))) ||
|
||||
+ !worldserver.areChunksLoadedForMove(entity.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(entity.position())))
|
||||
+ )) {
|
||||
+ this.connection.send(new ClientboundMoveVehiclePacket(entity));
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Prevent moving into unloaded chunks
|
||||
+
|
||||
if (d10 - d9 > Math.max(100.0D, Math.pow((double) (org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed), 2)) && !this.isSingleplayerOwner()) {
|
||||
// CraftBukkit end
|
||||
ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", new Object[]{entity.getName().getString(), this.player.getName().getString(), d6, d7, d8});
|
||||
@@ -1157,9 +1167,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
|
||||
if (!this.updateAwaitingTeleport()) {
|
||||
- double d0 = ServerGamePacketListenerImpl.clampHorizontal(packet.getX(this.player.getX()));
|
||||
- double d1 = ServerGamePacketListenerImpl.clampVertical(packet.getY(this.player.getY()));
|
||||
- double d2 = ServerGamePacketListenerImpl.clampHorizontal(packet.getZ(this.player.getZ()));
|
||||
+ double d0 = ServerGamePacketListenerImpl.clampHorizontal(packet.getX(this.player.getX())); final double toX = d0; // Paper - OBFHELPER
|
||||
+ double d1 = ServerGamePacketListenerImpl.clampVertical(packet.getY(this.player.getY())); final double toY = d1; // Paper - OBFHELPER
|
||||
+ double d2 = ServerGamePacketListenerImpl.clampHorizontal(packet.getZ(this.player.getZ())); final double toZ = d2; // Paper - OBFHELPER
|
||||
float f = Mth.wrapDegrees(packet.getYRot(this.player.getYRot()));
|
||||
float f1 = Mth.wrapDegrees(packet.getXRot(this.player.getXRot()));
|
||||
|
||||
@@ -1217,6 +1227,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
} else {
|
||||
speed = this.player.getAbilities().walkingSpeed * 10f;
|
||||
}
|
||||
+ // Paper start - Prevent moving into unloaded chunks
|
||||
+ if (this.player.level().paperConfig().chunks.preventMovingIntoUnloadedChunks && (this.player.getX() != toX || this.player.getZ() != toZ) && !worldserver.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(this.player.position())))) {
|
||||
+ this.internalTeleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot(), Collections.emptySet());
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Prevent moving into unloaded chunks
|
||||
|
||||
if (!this.player.isChangingDimension() && (!this.player.level().getGameRules().getBoolean(GameRules.RULE_DISABLE_ELYTRA_MOVEMENT_CHECK) || !flag)) {
|
||||
float f2 = flag ? 300.0F : 100.0F;
|
|
@ -1,18 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: GreenMeanie <GreenMeanieMC@gmail.com>
|
||||
Date: Sat, 20 Oct 2018 22:34:02 -0400
|
||||
Subject: [PATCH] Reset players airTicks on respawn
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 15328d344a26f5c40011ee6ba0bc54dd5ab0b87b..7cca5c778f9d20cfa6cb543c9afcf74779aaa355 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -2703,6 +2703,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
|
||||
this.setHealth(this.getMaxHealth());
|
||||
this.stopUsingItem(); // CraftBukkit - SPIGOT-6682: Clear active item on reset
|
||||
+ this.setAirSupply(this.getMaxAirSupply()); // Paper - Reset players airTicks on respawn
|
||||
this.setRemainingFireTicks(0);
|
||||
this.fallDistance = 0;
|
||||
this.foodData = new FoodData(this);
|
|
@ -1,33 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 23 Oct 2018 20:25:05 -0400
|
||||
Subject: [PATCH] Don't sleep after profile lookups if not needed
|
||||
|
||||
Mojang was sleeping even if we had no more requests to go after
|
||||
the current one finished, resulting in 100ms lost per profile lookup
|
||||
|
||||
diff --git a/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java b/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java
|
||||
index b87546f0061458b2b919a1fe00dde1f4eea6cb3e..55dac5edf694b3bf82b475a71e3524a1bce98882 100644
|
||||
--- a/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java
|
||||
+++ b/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java
|
||||
@@ -44,6 +44,7 @@ public class YggdrasilGameProfileRepository implements GameProfileRepository {
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final int page = 0;
|
||||
+ boolean hasRequested = false; // Paper - Don't sleep after profile lookups if not needed
|
||||
|
||||
for (final List<String> request : Iterables.partition(criteria, ENTRIES_PER_PAGE)) {
|
||||
final List<String> normalizedRequest = request.stream().map(YggdrasilGameProfileRepository::normalizeName).toList();
|
||||
@@ -75,6 +76,12 @@ public class YggdrasilGameProfileRepository implements GameProfileRepository {
|
||||
LOGGER.debug("Couldn't find profile {}", name);
|
||||
callback.onProfileLookupFailed(name, new ProfileNotFoundException("Server did not find the requested profile"));
|
||||
}
|
||||
+ // Paper start - Don't sleep after profile lookups if not needed
|
||||
+ if (!hasRequested) {
|
||||
+ hasRequested = true;
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Paper end - Don't sleep after profile lookups if not needed
|
||||
|
||||
try {
|
||||
Thread.sleep(DELAY_BETWEEN_PAGES);
|
|
@ -1,105 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 23 Oct 2018 23:14:38 -0400
|
||||
Subject: [PATCH] Improve Server Thread Pool and Thread Priorities
|
||||
|
||||
Use a simple executor since Fork join is a much more complex pool
|
||||
type and we are not using its capabilities.
|
||||
|
||||
Set thread priorities so main thread has above normal priority over
|
||||
server threads
|
||||
|
||||
Allow usage of a single thread executor by not using ForkJoin so single core CPU's
|
||||
and reduce worldgen thread worker count for low core count CPUs.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.Util onThreadException(Ljava/lang/Thread;Ljava/lang/Throwable;)V
|
||||
|
||||
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/ServerWorkerThread.java b/src/main/java/io/papermc/paper/util/ServerWorkerThread.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b60f59cf5cc8eb84a6055b7861857dece7f2501b
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/ServerWorkerThread.java
|
||||
@@ -0,0 +1,14 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import java.util.concurrent.atomic.AtomicInteger;
|
||||
+import net.minecraft.Util;
|
||||
+
|
||||
+public class ServerWorkerThread extends Thread {
|
||||
+ private static final AtomicInteger threadId = new AtomicInteger(1);
|
||||
+ public ServerWorkerThread(Runnable target, String poolName, int prioritityModifier) {
|
||||
+ super(target, "Worker-" + poolName + "-" + threadId.getAndIncrement());
|
||||
+ setPriority(Thread.NORM_PRIORITY+prioritityModifier); // Deprioritize over main
|
||||
+ this.setDaemon(true);
|
||||
+ this.setUncaughtExceptionHandler(Util::onThreadException);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
|
||||
index 54562fa04d14a937451ea7aa9d80194f2c31b471..4cf88f6d815d60cfbf8e4ecf9d96d0cfadd0620b 100644
|
||||
--- a/src/main/java/net/minecraft/Util.java
|
||||
+++ b/src/main/java/net/minecraft/Util.java
|
||||
@@ -89,7 +89,7 @@ public class Util {
|
||||
private static final int DEFAULT_MAX_THREADS = 255;
|
||||
private static final int DEFAULT_SAFE_FILE_OPERATION_RETRIES = 10;
|
||||
private static final String MAX_THREADS_SYSTEM_PROPERTY = "max.bg.threads";
|
||||
- private static final ExecutorService BACKGROUND_EXECUTOR = makeExecutor("Main");
|
||||
+ private static final ExecutorService BACKGROUND_EXECUTOR = makeExecutor("Main", -1); // Paper - Perf: add priority
|
||||
private static final ExecutorService IO_POOL = makeIoExecutor("IO-Worker-", false);
|
||||
private static final ExecutorService DOWNLOAD_POOL = makeIoExecutor("Download-", true);
|
||||
// Paper start - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
|
||||
@@ -160,15 +160,27 @@ public class Util {
|
||||
return FILENAME_DATE_TIME_FORMATTER.format(ZonedDateTime.now());
|
||||
}
|
||||
|
||||
- private static ExecutorService makeExecutor(String name) {
|
||||
- int i = Mth.clamp(Runtime.getRuntime().availableProcessors() - 1, 1, getMaxThreads());
|
||||
+ private static ExecutorService makeExecutor(String s, int priorityModifier) { // Paper - Perf: add priority
|
||||
+ // Paper start - Perf: use simpler thread pool that allows 1 thread and reduce worldgen thread worker count for low core count CPUs
|
||||
+ int cpus = Runtime.getRuntime().availableProcessors() / 2;
|
||||
+ int i;
|
||||
+ if (cpus <= 4) {
|
||||
+ i = cpus <= 2 ? 1 : 2;
|
||||
+ } else if (cpus <= 8) {
|
||||
+ // [5, 8]
|
||||
+ i = Math.max(3, cpus - 2);
|
||||
+ } else {
|
||||
+ i = cpus * 2 / 3;
|
||||
+ }
|
||||
+ i = Math.min(8, i);
|
||||
+ i = Integer.getInteger("Paper.WorkerThreadCount", i);
|
||||
ExecutorService executorService;
|
||||
if (i <= 0) {
|
||||
executorService = MoreExecutors.newDirectExecutorService();
|
||||
} else {
|
||||
- AtomicInteger atomicInteger = new AtomicInteger(1);
|
||||
- executorService = new ForkJoinPool(i, pool -> {
|
||||
- ForkJoinWorkerThread forkJoinWorkerThread = new ForkJoinWorkerThread(pool) {
|
||||
+ executorService = new java.util.concurrent.ThreadPoolExecutor(i, i,0L, TimeUnit.MILLISECONDS, new java.util.concurrent.LinkedBlockingQueue<>(), target -> new io.papermc.paper.util.ServerWorkerThread(target, s, priorityModifier));
|
||||
+ }
|
||||
+ /*
|
||||
@Override
|
||||
protected void onTermination(Throwable throwable) {
|
||||
if (throwable != null) {
|
||||
@@ -184,6 +196,7 @@ public class Util {
|
||||
return forkJoinWorkerThread;
|
||||
}, Util::onThreadException, true);
|
||||
}
|
||||
+ }*/ // Paper end - Perf: use simpler thread pool
|
||||
|
||||
return executorService;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 2d5ae71c143556a938f078d2fb84cab7bd4f789b..f3f3f80f14bc1df13b80033aa143fcccab6f3a31 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -322,6 +322,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
thread.setUncaughtExceptionHandler((thread1, throwable) -> {
|
||||
MinecraftServer.LOGGER.error("Uncaught exception in server thread", throwable);
|
||||
});
|
||||
+ thread.setPriority(Thread.NORM_PRIORITY+2); // Paper - Perf: Boost priority
|
||||
if (Runtime.getRuntime().availableProcessors() > 4) {
|
||||
thread.setPriority(8);
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 2 Nov 2018 23:11:51 -0400
|
||||
Subject: [PATCH] Optimize World Time Updates
|
||||
|
||||
Splits time updates into incremental updates as well as does
|
||||
the updates per world, so that we can re-use the same packet
|
||||
object for every player unless they have per-player time enabled.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index f3f3f80f14bc1df13b80033aa143fcccab6f3a31..699191356a9d873fa6bbe04ea3e5db91eb2db41d 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1560,12 +1560,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
MinecraftTimings.timeUpdateTimer.startTiming(); // Spigot // Paper
|
||||
// Send time updates to everyone, it will get the right time from the world the player is in.
|
||||
- if (this.tickCount % 20 == 0) {
|
||||
- for (int i = 0; i < this.getPlayerList().players.size(); ++i) {
|
||||
- ServerPlayer entityplayer = (ServerPlayer) this.getPlayerList().players.get(i);
|
||||
- entityplayer.connection.send(new ClientboundSetTimePacket(entityplayer.level().getGameTime(), entityplayer.getPlayerTime(), entityplayer.level().getGameRules().getBoolean(GameRules.RULE_DAYLIGHT))); // Add support for per player time
|
||||
+ // Paper start - Perf: Optimize time updates
|
||||
+ for (final ServerLevel level : this.getAllLevels()) {
|
||||
+ final boolean doDaylight = level.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT);
|
||||
+ final long dayTime = level.getDayTime();
|
||||
+ long worldTime = level.getGameTime();
|
||||
+ final ClientboundSetTimePacket worldPacket = new ClientboundSetTimePacket(worldTime, dayTime, doDaylight);
|
||||
+ for (Player entityhuman : level.players()) {
|
||||
+ if (!(entityhuman instanceof ServerPlayer) || (tickCount + entityhuman.getId()) % 20 != 0) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ ServerPlayer entityplayer = (ServerPlayer) entityhuman;
|
||||
+ long playerTime = entityplayer.getPlayerTime();
|
||||
+ ClientboundSetTimePacket packet = (playerTime == dayTime) ? worldPacket :
|
||||
+ new ClientboundSetTimePacket(worldTime, playerTime, doDaylight);
|
||||
+ entityplayer.connection.send(packet); // Add support for per player time
|
||||
}
|
||||
}
|
||||
+ // Paper end - Perf: Optimize time updates
|
||||
MinecraftTimings.timeUpdateTimer.stopTiming(); // Spigot // Paper
|
||||
|
||||
while (iterator.hasNext()) {
|
|
@ -1,358 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Mon, 5 Nov 2018 04:23:51 +0000
|
||||
Subject: [PATCH] Restore custom InventoryHolder support
|
||||
|
||||
Upstream removed the ability to consistently use a custom InventoryHolder,
|
||||
However, the implementation does not use an InventoryHolder in any form
|
||||
outside of custom inventories.
|
||||
|
||||
== AT ==
|
||||
public-f net.minecraft.world.inventory.AbstractContainerMenu dataSlots
|
||||
public-f net.minecraft.world.inventory.AbstractContainerMenu remoteDataSlots
|
||||
|
||||
Co-authored-by: Shane Freeder <theboyetronic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/inventory/PaperInventoryCustomHolderContainer.java b/src/main/java/io/papermc/paper/inventory/PaperInventoryCustomHolderContainer.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..224d4b2cc45b0d02230a76caee9c88573a448b4c
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/inventory/PaperInventoryCustomHolderContainer.java
|
||||
@@ -0,0 +1,141 @@
|
||||
+package io.papermc.paper.inventory;
|
||||
+
|
||||
+import io.papermc.paper.adventure.PaperAdventure;
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
+import net.minecraft.world.Container;
|
||||
+import net.minecraft.world.entity.player.Player;
|
||||
+import net.minecraft.world.item.ItemStack;
|
||||
+import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
||||
+import org.bukkit.Location;
|
||||
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
+import org.bukkit.entity.HumanEntity;
|
||||
+import org.bukkit.event.inventory.InventoryType;
|
||||
+import org.bukkit.inventory.InventoryHolder;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+import java.util.List;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class PaperInventoryCustomHolderContainer implements Container {
|
||||
+
|
||||
+ private final InventoryHolder owner;
|
||||
+ private final Container delegate;
|
||||
+ private final InventoryType type;
|
||||
+ private final String title;
|
||||
+ private final Component adventure$title;
|
||||
+
|
||||
+ public PaperInventoryCustomHolderContainer(InventoryHolder owner, Container delegate, InventoryType type) {
|
||||
+ this.owner = owner;
|
||||
+ this.delegate = delegate;
|
||||
+ this.type = type;
|
||||
+ @Nullable Component adventure$title = null;
|
||||
+ if (delegate instanceof BaseContainerBlockEntity blockEntity) {
|
||||
+ adventure$title = blockEntity.getCustomName() != null ? PaperAdventure.asAdventure(blockEntity.getCustomName()) : null;
|
||||
+ }
|
||||
+ if (adventure$title == null) {
|
||||
+ adventure$title = type.defaultTitle();
|
||||
+ }
|
||||
+ this.adventure$title = adventure$title;
|
||||
+ this.title = LegacyComponentSerializer.legacySection().serialize(this.adventure$title);
|
||||
+ }
|
||||
+
|
||||
+ public Component title() {
|
||||
+ return this.adventure$title;
|
||||
+ }
|
||||
+
|
||||
+ public String getTitle() {
|
||||
+ return this.title;
|
||||
+ }
|
||||
+
|
||||
+ public InventoryType getType() {
|
||||
+ return this.type;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getContainerSize() {
|
||||
+ return this.delegate.getContainerSize();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isEmpty() {
|
||||
+ return this.delegate.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ItemStack getItem(int slot) {
|
||||
+ return this.delegate.getItem(slot);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ItemStack removeItem(int slot, int amount) {
|
||||
+ return this.delegate.removeItem(slot, amount);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ItemStack removeItemNoUpdate(int slot) {
|
||||
+ return this.delegate.removeItemNoUpdate(slot);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setItem(int slot, ItemStack stack) {
|
||||
+ this.delegate.setItem(slot, stack);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getMaxStackSize() {
|
||||
+ return this.delegate.getMaxStackSize();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setChanged() {
|
||||
+ this.delegate.setChanged();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean stillValid(Player player) {
|
||||
+ return this.delegate.stillValid(player);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<ItemStack> getContents() {
|
||||
+ return this.delegate.getContents();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onOpen(CraftHumanEntity who) {
|
||||
+ this.delegate.onOpen(who);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onClose(CraftHumanEntity who) {
|
||||
+ this.delegate.onClose(who);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<HumanEntity> getViewers() {
|
||||
+ return this.delegate.getViewers();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public InventoryHolder getOwner() {
|
||||
+ return this.owner;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setMaxStackSize(int size) {
|
||||
+ this.delegate.setMaxStackSize(size);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Location getLocation() {
|
||||
+ return this.delegate.getLocation();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void clearContent() {
|
||||
+ this.delegate.clearContent();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
|
||||
index 1a2329021a6b29777c637ee4dc8cd69ed18001c9..674e3a827f8fb64e5c0beefb3c1874d6e8aee4e5 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
|
||||
@@ -49,7 +49,7 @@ public class CraftContainer extends AbstractContainerMenu {
|
||||
public CraftContainer(final Inventory inventory, final Player player, int id) {
|
||||
this(new CraftAbstractInventoryView() {
|
||||
|
||||
- private final String originalTitle = (inventory instanceof CraftInventoryCustom) ? ((CraftInventoryCustom.MinecraftInventory) ((CraftInventory) inventory).getInventory()).getTitle() : inventory.getType().getDefaultTitle();
|
||||
+ private final String originalTitle = inventory instanceof CraftInventoryCustom ? ((CraftInventoryCustom) inventory).getTitle() : inventory.getType().getDefaultTitle(); // Paper
|
||||
private String title = this.originalTitle;
|
||||
|
||||
@Override
|
||||
@@ -75,7 +75,7 @@ public class CraftContainer extends AbstractContainerMenu {
|
||||
// Paper start
|
||||
@Override
|
||||
public net.kyori.adventure.text.Component title() {
|
||||
- return inventory instanceof CraftInventoryCustom ? ((CraftInventoryCustom.MinecraftInventory) ((CraftInventory) inventory).getInventory()).title() : net.kyori.adventure.text.Component.text(inventory.getType().getDefaultTitle());
|
||||
+ return inventory instanceof CraftInventoryCustom custom ? custom.title() : inventory.getType().defaultTitle(); // Paper
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -214,6 +214,10 @@ public class CraftContainer extends AbstractContainerMenu {
|
||||
this.lastSlots = this.delegate.lastSlots;
|
||||
this.slots = this.delegate.slots;
|
||||
this.remoteSlots = this.delegate.remoteSlots;
|
||||
+ // Paper start - copy data slots for InventoryView#set/getProperty
|
||||
+ this.dataSlots = this.delegate.dataSlots;
|
||||
+ this.remoteDataSlots = this.delegate.remoteDataSlots;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
// SPIGOT-4598 - we should still delegate the shift click handler
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
index 6a47c6adb721f0c6737150d8b0ee18ab70f5f281..75eb794f796b31c0c5ef80a6d27a56711a522f5e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
@@ -497,6 +497,10 @@ public class CraftInventory implements Inventory {
|
||||
return InventoryType.BREWING;
|
||||
} else if (this.inventory instanceof CraftInventoryCustom.MinecraftInventory) {
|
||||
return ((CraftInventoryCustom.MinecraftInventory) this.inventory).getType();
|
||||
+ // Paper start
|
||||
+ } else if (this.inventory instanceof io.papermc.paper.inventory.PaperInventoryCustomHolderContainer holderContainer) {
|
||||
+ return holderContainer.getType();
|
||||
+ // Paper end
|
||||
} else if (this.inventory instanceof PlayerEnderChestContainer) {
|
||||
return InventoryType.ENDER_CHEST;
|
||||
} else if (this.inventory instanceof MerchantContainer) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java
|
||||
index fc0e1212022d1aa3506699b60ef338196eb54eba..da1c1fe0faf6819b15a81d6ad53370948e5f984f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java
|
||||
@@ -15,6 +15,11 @@ import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
|
||||
public class CraftInventoryCustom extends CraftInventory {
|
||||
+ // Paper start
|
||||
+ public CraftInventoryCustom(InventoryHolder owner, InventoryType type, Container delegate) {
|
||||
+ super(new io.papermc.paper.inventory.PaperInventoryCustomHolderContainer(owner, delegate, type));
|
||||
+ }
|
||||
+ // Paper end
|
||||
public CraftInventoryCustom(InventoryHolder owner, InventoryType type) {
|
||||
super(new MinecraftInventory(owner, type));
|
||||
}
|
||||
@@ -42,6 +47,27 @@ public class CraftInventoryCustom extends CraftInventory {
|
||||
public CraftInventoryCustom(InventoryHolder owner, int size, String title) {
|
||||
super(new MinecraftInventory(owner, size, title));
|
||||
}
|
||||
+ // Paper start
|
||||
+ public String getTitle() {
|
||||
+ if (this.inventory instanceof MinecraftInventory minecraftInventory) {
|
||||
+ return minecraftInventory.getTitle();
|
||||
+ } else if (this.inventory instanceof io.papermc.paper.inventory.PaperInventoryCustomHolderContainer customHolderContainer) {
|
||||
+ return customHolderContainer.getTitle();
|
||||
+ } else {
|
||||
+ throw new UnsupportedOperationException(this.inventory.getClass() + " isn't a recognized Container type here");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public net.kyori.adventure.text.Component title() {
|
||||
+ if (this.inventory instanceof MinecraftInventory minecraftInventory) {
|
||||
+ return minecraftInventory.title();
|
||||
+ } else if (this.inventory instanceof io.papermc.paper.inventory.PaperInventoryCustomHolderContainer customHolderContainer) {
|
||||
+ return customHolderContainer.title();
|
||||
+ } else {
|
||||
+ throw new UnsupportedOperationException(this.inventory.getClass() + " isn't a recognized Container type here");
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
static class MinecraftInventory implements Container {
|
||||
private final NonNullList<ItemStack> items;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java
|
||||
index 7bc082d08a3d577481046818f0d58133413fc723..a6c758c5c5da2fb3f2d251bc109f72a5d8b0eb14 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java
|
||||
@@ -28,7 +28,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(InventoryHolder holder, InventoryType type) {
|
||||
- return this.getInventory(this.getTileEntity());
|
||||
+ return this.getInventory(holder, type, this.getTileEntity()); // Paper
|
||||
}
|
||||
|
||||
// Paper start
|
||||
@@ -39,7 +39,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
((RandomizableContainerBlockEntity) te).name = io.papermc.paper.adventure.PaperAdventure.asVanilla(title);
|
||||
}
|
||||
|
||||
- return getInventory(te);
|
||||
+ return this.getInventory(owner, type, te); // Paper
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -50,10 +50,18 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
((RandomizableContainerBlockEntity) te).name = CraftChatMessage.fromStringOrNull(title);
|
||||
}
|
||||
|
||||
- return this.getInventory(te);
|
||||
+ return this.getInventory(holder, type, te); // Paper
|
||||
}
|
||||
|
||||
+ @Deprecated // Paper - use getInventory with owner and type
|
||||
public Inventory getInventory(Container tileEntity) {
|
||||
+ // Paper start
|
||||
+ return this.getInventory(null, null, tileEntity);
|
||||
+ }
|
||||
+
|
||||
+ public Inventory getInventory(InventoryHolder owner, InventoryType type, Container tileEntity) { // Paper
|
||||
+ if (owner != null) return new org.bukkit.craftbukkit.inventory.CraftInventoryCustom(owner, type, tileEntity); // Paper
|
||||
+ // Paper end
|
||||
return new CraftInventory(tileEntity);
|
||||
}
|
||||
|
||||
@@ -69,8 +77,8 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
@Override
|
||||
public Inventory createInventory(InventoryHolder owner, InventoryType type, net.kyori.adventure.text.Component title) {
|
||||
Container tileEntity = getTileEntity();
|
||||
- ((AbstractFurnaceBlockEntity) tileEntity).setCustomName(io.papermc.paper.adventure.PaperAdventure.asVanilla(title));
|
||||
- return getInventory(tileEntity);
|
||||
+ ((AbstractFurnaceBlockEntity) tileEntity).name = io.papermc.paper.adventure.PaperAdventure.asVanilla(title);
|
||||
+ return this.getInventory(owner, type, tileEntity); // Paper
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -78,11 +86,19 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
public Inventory createInventory(InventoryHolder owner, InventoryType type, String title) {
|
||||
Container tileEntity = this.getTileEntity();
|
||||
((AbstractFurnaceBlockEntity) tileEntity).name = CraftChatMessage.fromStringOrNull(title);
|
||||
- return this.getInventory(tileEntity);
|
||||
+ return this.getInventory(owner, type, tileEntity); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getInventory(Container tileEntity) {
|
||||
+ // Paper start
|
||||
+ return getInventory(null, null, tileEntity);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Inventory getInventory(InventoryHolder owner, InventoryType type, net.minecraft.world.Container tileEntity) { // Paper
|
||||
+ if (owner != null) return new org.bukkit.craftbukkit.inventory.CraftInventoryCustom(owner, type, tileEntity); // Paper
|
||||
+ // Paper end
|
||||
return new CraftInventoryFurnace((AbstractFurnaceBlockEntity) tileEntity);
|
||||
}
|
||||
}
|
||||
@@ -102,7 +118,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
if (tileEntity instanceof BrewingStandBlockEntity) {
|
||||
((BrewingStandBlockEntity) tileEntity).name = io.papermc.paper.adventure.PaperAdventure.asVanilla(title);
|
||||
}
|
||||
- return getInventory(tileEntity);
|
||||
+ return this.getInventory(owner, type, tileEntity); // Paper
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -113,11 +129,19 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
|
||||
if (tileEntity instanceof BrewingStandBlockEntity) {
|
||||
((BrewingStandBlockEntity) tileEntity).name = CraftChatMessage.fromStringOrNull(title);
|
||||
}
|
||||
- return this.getInventory(tileEntity);
|
||||
+ return this.getInventory(holder, type, tileEntity); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getInventory(Container tileEntity) {
|
||||
+ // Paper start
|
||||
+ return getInventory(null, null, tileEntity);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Inventory getInventory(InventoryHolder owner, InventoryType type, net.minecraft.world.Container tileEntity) { // Paper
|
||||
+ if (owner != null) return new org.bukkit.craftbukkit.inventory.CraftInventoryCustom(owner, type, tileEntity); // Paper
|
||||
+ // Paper end
|
||||
return new CraftInventoryBrewer(tileEntity);
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sat, 10 Nov 2018 05:15:21 +0000
|
||||
Subject: [PATCH] Fix SpongeAbsortEvent handling
|
||||
|
||||
Only process drops when the block is actually going to be removed
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/SpongeBlock.java b/src/main/java/net/minecraft/world/level/block/SpongeBlock.java
|
||||
index 2e54730deee3149517a535f15ef6c0628ba659c2..902825ec9ea05f4418b45f56a008d73f217bd178 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/SpongeBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/SpongeBlock.java
|
||||
@@ -134,7 +134,11 @@ public class SpongeBlock extends Block {
|
||||
} else if (iblockdata.is(Blocks.KELP) || iblockdata.is(Blocks.KELP_PLANT) || iblockdata.is(Blocks.SEAGRASS) || iblockdata.is(Blocks.TALL_SEAGRASS)) {
|
||||
BlockEntity tileentity = iblockdata.hasBlockEntity() ? world.getBlockEntity(blockposition1) : null;
|
||||
|
||||
+ // Paper start - Fix SpongeAbsortEvent handling
|
||||
+ if (block.getHandle().isAir()) {
|
||||
dropResources(iblockdata, world, blockposition1, tileentity);
|
||||
+ }
|
||||
+ // Paper end - Fix SpongeAbsortEvent handling
|
||||
}
|
||||
}
|
||||
world.setBlock(blockposition1, block.getHandle(), block.getFlag());
|
|
@ -1,77 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sun, 11 Nov 2018 21:01:09 +0000
|
||||
Subject: [PATCH] Don't allow digging into unloaded chunks
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index a5b0efd6142075ca1ecb604afbc1d0162199e7a4..da9e864520150acd8027545672aa476be414bb4d 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -124,8 +124,8 @@ public class ServerPlayerGameMode {
|
||||
BlockState iblockdata;
|
||||
|
||||
if (this.hasDelayedDestroy) {
|
||||
- iblockdata = this.level.getBlockState(this.delayedDestroyPos);
|
||||
- if (iblockdata.isAir()) {
|
||||
+ iblockdata = this.level.getBlockStateIfLoaded(this.delayedDestroyPos); // Paper - Don't allow digging into unloaded chunks
|
||||
+ if (iblockdata == null || iblockdata.isAir()) { // Paper - Don't allow digging into unloaded chunks
|
||||
this.hasDelayedDestroy = false;
|
||||
} else {
|
||||
float f = this.incrementDestroyProgress(iblockdata, this.delayedDestroyPos, this.delayedTickStart);
|
||||
@@ -136,7 +136,13 @@ public class ServerPlayerGameMode {
|
||||
}
|
||||
}
|
||||
} else if (this.isDestroyingBlock) {
|
||||
- iblockdata = this.level.getBlockState(this.destroyPos);
|
||||
+ // Paper start - Don't allow digging into unloaded chunks; don't want to do same logic as above, return instead
|
||||
+ iblockdata = this.level.getBlockStateIfLoaded(this.destroyPos);
|
||||
+ if (iblockdata == null) {
|
||||
+ this.isDestroyingBlock = false;
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Don't allow digging into unloaded chunks
|
||||
if (iblockdata.isAir()) {
|
||||
this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1);
|
||||
this.lastSentState = -1;
|
||||
@@ -165,6 +171,7 @@ public class ServerPlayerGameMode {
|
||||
|
||||
public void handleBlockBreakAction(BlockPos pos, ServerboundPlayerActionPacket.Action action, Direction direction, int worldHeight, int sequence) {
|
||||
if (!this.player.canInteractWithBlock(pos, 1.0D)) {
|
||||
+ if (true) return; // Paper - Don't allow digging into unloaded chunks; Don't notify if unreasonably far away
|
||||
this.debugLogging(pos, false, sequence, "too far");
|
||||
} else if (pos.getY() >= worldHeight) {
|
||||
this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos)));
|
||||
@@ -307,10 +314,12 @@ public class ServerPlayerGameMode {
|
||||
this.debugLogging(pos, true, sequence, "stopped destroying");
|
||||
} else if (action == ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK) {
|
||||
this.isDestroyingBlock = false;
|
||||
- if (!Objects.equals(this.destroyPos, pos)) {
|
||||
+ if (!Objects.equals(this.destroyPos, pos) && !BlockPos.ZERO.equals(this.destroyPos)) { // Paper
|
||||
ServerPlayerGameMode.LOGGER.debug("Mismatch in destroy block pos: {} {}", this.destroyPos, pos); // CraftBukkit - SPIGOT-5457 sent by client when interact event cancelled
|
||||
- this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1);
|
||||
- this.debugLogging(pos, true, sequence, "aborted mismatched destroying");
|
||||
+ BlockState type = this.level.getBlockStateIfLoaded(this.destroyPos); // Paper - don't load unloaded chunks for stale records here
|
||||
+ if (type != null) this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1);
|
||||
+ if (type != null) this.debugLogging(pos, true, sequence, "aborted mismatched destroying");
|
||||
+ this.destroyPos = BlockPos.ZERO; // Paper
|
||||
}
|
||||
|
||||
this.level.destroyBlockProgress(this.player.getId(), pos, -1);
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 6cf68d7173bc23c39261856f11cbd42de387bd60..4942aa857ecc5762c9b0b1662eefaeae4daab80d 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1595,6 +1595,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
case START_DESTROY_BLOCK:
|
||||
case ABORT_DESTROY_BLOCK:
|
||||
case STOP_DESTROY_BLOCK:
|
||||
+ // Paper start - Don't allow digging into unloaded chunks
|
||||
+ if (this.player.level().getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4) == null) {
|
||||
+ this.player.connection.ackBlockChangesUpTo(packet.getSequence());
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Don't allow digging into unloaded chunks
|
||||
this.player.gameMode.handleBlockBreakAction(blockposition, packetplayinblockdig_enumplayerdigtype, packet.getDirection(), this.player.level().getMaxBuildHeight(), packet.getSequence());
|
||||
this.player.connection.ackBlockChangesUpTo(packet.getSequence());
|
||||
return;
|
|
@ -1,40 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sun, 18 Nov 2018 19:49:56 +0000
|
||||
Subject: [PATCH] Make the default permission message configurable
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
index 5b070d158760789bbcaa984426a55d20767abe4a..e1820a339452cd3388dd7cbb928c5f58779a77b6 100644
|
||||
--- a/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
@@ -73,7 +73,7 @@ public final class PaperCommand extends Command {
|
||||
if (sender.hasPermission(BASE_PERM + permission) || sender.hasPermission("bukkit.command.paper")) {
|
||||
return true;
|
||||
}
|
||||
- sender.sendMessage(text("I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error.", RED));
|
||||
+ sender.sendMessage(Bukkit.permissionMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 954b3725d4f702f284cd8712305a3f97fb90b9c1..7407d9f3480e0e44be44c84831864e511dfdebc2 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2874,6 +2874,16 @@ public final class CraftServer implements Server {
|
||||
return io.papermc.paper.configuration.GlobalConfiguration.get().commands.suggestPlayerNamesWhenNullTabCompletions;
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ public String getPermissionMessage() {
|
||||
+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().serialize(io.papermc.paper.configuration.GlobalConfiguration.get().messages.noPermission);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.kyori.adventure.text.Component permissionMessage() {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().messages.noPermission;
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nonnull UUID uuid) {
|
||||
return createProfile(uuid, null);
|
|
@ -1,166 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Thu, 15 Nov 2018 13:38:37 +0000
|
||||
Subject: [PATCH] force entity dismount during teleportation
|
||||
|
||||
Entities must be dismounted before teleportation in order to avoid
|
||||
multiple issues in the server with regards to teleportation, shamefully,
|
||||
too many plugins rely on the events firing, which means that not firing
|
||||
these events caues more issues than it solves;
|
||||
|
||||
In order to counteract this, Entity dismount/exit vehicle events have
|
||||
been modified to supress cancellation (and has a method to allow plugins
|
||||
to check if this has been set), noting that cancellation will be silently
|
||||
surpressed given that plugins are not expecting this event to not be cancellable.
|
||||
|
||||
This is a far from ideal scenario, however: given the current state of this
|
||||
event and other alternatives causing issues elsewhere, I believe that
|
||||
this is going to be the best soultion all around.
|
||||
|
||||
Improvements/suggestions welcome!
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 7cca5c778f9d20cfa6cb543c9afcf74779aaa355..c2571855ca6a8ecd144b8fbb97d601d1808e8d61 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -2522,9 +2522,15 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
|
||||
@Override
|
||||
public void stopRiding() {
|
||||
+ // Paper start - Force entity dismount during teleportation
|
||||
+ this.stopRiding(false);
|
||||
+ }
|
||||
+ @Override
|
||||
+ public void stopRiding(boolean suppressCancellation) {
|
||||
+ // Paper end - Force entity dismount during teleportation
|
||||
Entity entity = this.getVehicle();
|
||||
|
||||
- super.stopRiding();
|
||||
+ super.stopRiding(suppressCancellation); // Paper - Force entity dismount during teleportation
|
||||
if (entity instanceof LivingEntity entityliving) {
|
||||
Iterator iterator = entityliving.getActiveEffects().iterator();
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 7fd1a75ba0068ee3ca6c29a550a9a1b33c5cacc5..f330ddca00ed11bf76ae825820423b94920013b9 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2704,17 +2704,28 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public void removeVehicle() {
|
||||
+ // Paper start - Force entity dismount during teleportation
|
||||
+ this.removeVehicle(false);
|
||||
+ }
|
||||
+ public void removeVehicle(boolean suppressCancellation) {
|
||||
+ // Paper end - Force entity dismount during teleportation
|
||||
if (this.vehicle != null) {
|
||||
Entity entity = this.vehicle;
|
||||
|
||||
this.vehicle = null;
|
||||
- if (!entity.removePassenger(this)) this.vehicle = entity; // CraftBukkit
|
||||
+ if (!entity.removePassenger(this, suppressCancellation)) this.vehicle = entity; // CraftBukkit // Paper - Force entity dismount during teleportation
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void stopRiding() {
|
||||
- this.removeVehicle();
|
||||
+ // Paper start - Force entity dismount during teleportation
|
||||
+ this.stopRiding(false);
|
||||
+ }
|
||||
+
|
||||
+ public void stopRiding(boolean suppressCancellation) {
|
||||
+ this.removeVehicle(suppressCancellation);
|
||||
+ // Paper end - Force entity dismount during teleportation
|
||||
}
|
||||
|
||||
protected void addPassenger(Entity passenger) {
|
||||
@@ -2739,7 +2750,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
}
|
||||
|
||||
- protected boolean removePassenger(Entity entity) { // CraftBukkit
|
||||
+ // Paper start - Force entity dismount during teleportation
|
||||
+ protected boolean removePassenger(Entity entity) { return removePassenger(entity, false);}
|
||||
+ protected boolean removePassenger(Entity entity, boolean suppressCancellation) { // CraftBukkit
|
||||
+ // Paper end - Force entity dismount during teleportation
|
||||
if (entity.getVehicle() == this) {
|
||||
throw new IllegalStateException("Use x.stopRiding(y), not y.removePassenger(x)");
|
||||
} else {
|
||||
@@ -2749,7 +2763,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
if (this.getBukkitEntity() instanceof Vehicle && entity.getBukkitEntity() instanceof LivingEntity) {
|
||||
VehicleExitEvent event = new VehicleExitEvent(
|
||||
(Vehicle) this.getBukkitEntity(),
|
||||
- (LivingEntity) entity.getBukkitEntity()
|
||||
+ (LivingEntity) entity.getBukkitEntity(), !suppressCancellation // Paper - Force entity dismount during teleportation
|
||||
);
|
||||
// Suppress during worldgen
|
||||
if (this.valid) {
|
||||
@@ -2762,7 +2776,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
}
|
||||
|
||||
- EntityDismountEvent event = new EntityDismountEvent(entity.getBukkitEntity(), this.getBukkitEntity());
|
||||
+ EntityDismountEvent event = new EntityDismountEvent(entity.getBukkitEntity(), this.getBukkitEntity(), !suppressCancellation); // Paper - Force entity dismount during teleportation
|
||||
// Suppress during worldgen
|
||||
if (this.valid) {
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 689aaf4ceedc598fe71db726215cceae6cc97296..fad0445628499ac14cd9d8ab7f618c490885e798 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3619,9 +3619,15 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
|
||||
@Override
|
||||
public void stopRiding() {
|
||||
+ // Paper start - Force entity dismount during teleportation
|
||||
+ this.stopRiding(false);
|
||||
+ }
|
||||
+ @Override
|
||||
+ public void stopRiding(boolean suppressCancellation) {
|
||||
+ // Paper end - Force entity dismount during teleportation
|
||||
Entity entity = this.getVehicle();
|
||||
|
||||
- super.stopRiding();
|
||||
+ super.stopRiding(suppressCancellation); // Paper - Force entity dismount during teleportation
|
||||
if (entity != null && entity != this.getVehicle() && !this.level().isClientSide) {
|
||||
this.dismountVehicle(entity);
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java
|
||||
index 882236c8ebad90ed2adc873de4dda3b7f3f869d9..632b74e84d6ee58da8806e30b75e16fb864afa64 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java
|
||||
@@ -288,7 +288,13 @@ public class Shulker extends AbstractGolem implements VariantHolder<Optional<Dye
|
||||
|
||||
@Override
|
||||
public void stopRiding() {
|
||||
- super.stopRiding();
|
||||
+ // Paper start - Force entity dismount during teleportation
|
||||
+ this.stopRiding(false);
|
||||
+ }
|
||||
+ @Override
|
||||
+ public void stopRiding(boolean suppressCancellation) {
|
||||
+ super.stopRiding(suppressCancellation);
|
||||
+ // Paper end - Force entity dismount during teleportation
|
||||
if (this.level().isClientSide) {
|
||||
this.clientOldAttachPosition = this.blockPosition();
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
index b70fbc1a93271bbf28402afbe9c6e538a4b6e9aa..fa906334a1c569748d3f2dc073ec03a85bd09d3b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -1161,7 +1161,13 @@ public abstract class Player extends LivingEntity {
|
||||
|
||||
@Override
|
||||
public void removeVehicle() {
|
||||
- super.removeVehicle();
|
||||
+ // Paper start - Force entity dismount during teleportation
|
||||
+ this.removeVehicle(false);
|
||||
+ }
|
||||
+ @Override
|
||||
+ public void removeVehicle(boolean suppressCancellation) {
|
||||
+ super.removeVehicle(suppressCancellation);
|
||||
+ // Paper end - Force entity dismount during teleportation
|
||||
this.boardingCooldown = 0;
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 7 Oct 2018 04:29:59 -0500
|
||||
Subject: [PATCH] Add more Zombie API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.monster.Zombie isSunSensitive()Z
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
index d97c3c139f10a45febc0cfb1057ff6e33266228e..d981f8679149669f6ca4ea950d744149974532b2 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
@@ -97,6 +97,7 @@ public class Zombie extends Monster {
|
||||
private int inWaterTime;
|
||||
public int conversionTime;
|
||||
private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field
|
||||
+ private boolean shouldBurnInDay = true; // Paper - Add more Zombie API
|
||||
|
||||
public Zombie(EntityType<? extends Zombie> type, Level world) {
|
||||
super(type, world);
|
||||
@@ -267,6 +268,12 @@ public class Zombie extends Monster {
|
||||
super.aiStep();
|
||||
}
|
||||
|
||||
+ // Paper start - Add more Zombie API
|
||||
+ public void stopDrowning() {
|
||||
+ this.conversionTime = -1;
|
||||
+ this.getEntityData().set(Zombie.DATA_DROWNED_CONVERSION_ID, false);
|
||||
+ }
|
||||
+ // Paper end - Add more Zombie API
|
||||
public void startUnderWaterConversion(int ticksUntilWaterConversion) {
|
||||
this.lastTick = MinecraftServer.currentTick; // CraftBukkit
|
||||
this.conversionTime = ticksUntilWaterConversion;
|
||||
@@ -296,9 +303,15 @@ public class Zombie extends Monster {
|
||||
}
|
||||
|
||||
public boolean isSunSensitive() {
|
||||
- return true;
|
||||
+ return this.shouldBurnInDay; // Paper - Add more Zombie API
|
||||
}
|
||||
|
||||
+ // Paper start - Add more Zombie API
|
||||
+ public void setShouldBurnInDay(boolean shouldBurnInDay) {
|
||||
+ this.shouldBurnInDay = shouldBurnInDay;
|
||||
+ }
|
||||
+ // Paper end - Add more Zombie API
|
||||
+
|
||||
@Override
|
||||
public boolean hurt(DamageSource source, float amount) {
|
||||
if (!super.hurt(source, amount)) {
|
||||
@@ -417,6 +430,7 @@ public class Zombie extends Monster {
|
||||
nbt.putBoolean("CanBreakDoors", this.canBreakDoors());
|
||||
nbt.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1);
|
||||
nbt.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1);
|
||||
+ nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -428,6 +442,11 @@ public class Zombie extends Monster {
|
||||
if (nbt.contains("DrownedConversionTime", 99) && nbt.getInt("DrownedConversionTime") > -1) {
|
||||
this.startUnderWaterConversion(nbt.getInt("DrownedConversionTime"));
|
||||
}
|
||||
+ // Paper start - Add more Zombie API
|
||||
+ if (nbt.contains("Paper.ShouldBurnInDay")) {
|
||||
+ this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay");
|
||||
+ }
|
||||
+ // Paper end - Add more Zombie API
|
||||
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java
|
||||
index 99dcaa827831a40ea46453f502d8b6ccb107f0ad..4412c913123f7521f449c98b60378e8d3b1671ce 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java
|
||||
@@ -87,6 +87,42 @@ public class CraftZombie extends CraftMonster implements Zombie {
|
||||
@Override
|
||||
public void setAgeLock(boolean b) {
|
||||
}
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean isDrowning() {
|
||||
+ return getHandle().isUnderWaterConverting();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void startDrowning(int drownedConversionTime) {
|
||||
+ getHandle().startUnderWaterConversion(drownedConversionTime);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void stopDrowning() {
|
||||
+ getHandle().stopDrowning();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean shouldBurnInDay() {
|
||||
+ return getHandle().isSunSensitive();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isArmsRaised() {
|
||||
+ return getHandle().isAggressive();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setArmsRaised(final boolean raised) {
|
||||
+ getHandle().setAggressive(raised);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setShouldBurnInDay(boolean shouldBurnInDay) {
|
||||
+ getHandle().setShouldBurnInDay(shouldBurnInDay);
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
@Override
|
||||
public boolean getAgeLock() {
|
|
@ -1,72 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 16 Nov 2018 23:08:50 -0500
|
||||
Subject: [PATCH] Book size limits
|
||||
|
||||
Puts some limits on the size of books.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundEditBookPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundEditBookPacket.java
|
||||
index ed61767a64cdce37dc7c226ebd0d693a60de24a9..f634a830a2b58a419e84f969bd53eeae4f4513bb 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ServerboundEditBookPacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundEditBookPacket.java
|
||||
@@ -16,9 +16,9 @@ public record ServerboundEditBookPacket(int slot, List<String> pages, Optional<S
|
||||
public static final StreamCodec<FriendlyByteBuf, ServerboundEditBookPacket> STREAM_CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.VAR_INT,
|
||||
ServerboundEditBookPacket::slot,
|
||||
- ByteBufCodecs.stringUtf8(8192).apply(ByteBufCodecs.list(200)),
|
||||
+ ByteBufCodecs.stringUtf8(net.minecraft.world.item.component.WritableBookContent.PAGE_EDIT_LENGTH).apply(ByteBufCodecs.list(net.minecraft.world.item.component.WritableBookContent.MAX_PAGES)), // Paper - limit books
|
||||
ServerboundEditBookPacket::pages,
|
||||
- ByteBufCodecs.stringUtf8(128).apply(ByteBufCodecs::optional),
|
||||
+ ByteBufCodecs.stringUtf8(net.minecraft.world.item.component.WrittenBookContent.TITLE_MAX_LENGTH).apply(ByteBufCodecs::optional), // Paper - limit books
|
||||
ServerboundEditBookPacket::title,
|
||||
ServerboundEditBookPacket::new
|
||||
);
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 4942aa857ecc5762c9b0b1662eefaeae4daab80d..577f0e290f66afd2ded18714fb8b5f62a7a9aa71 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1043,6 +1043,44 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
@Override
|
||||
public void handleEditBook(ServerboundEditBookPacket packet) {
|
||||
+ // Paper start - Book size limits
|
||||
+ final io.papermc.paper.configuration.type.number.IntOr.Disabled pageMax = io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.pageMax;
|
||||
+ if (!this.cserver.isPrimaryThread() && pageMax.enabled()) {
|
||||
+ final List<String> pageList = packet.pages();
|
||||
+ long byteTotal = 0;
|
||||
+ final int maxBookPageSize = pageMax.intValue();
|
||||
+ final double multiplier = Math.clamp(io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.totalMultiplier, 0.3D, 1D);
|
||||
+ long byteAllowed = maxBookPageSize;
|
||||
+ for (final String page : pageList) {
|
||||
+ final int byteLength = page.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;
|
||||
+ byteTotal += byteLength;
|
||||
+ final int length = page.length();
|
||||
+ int multiByteCharacters = 0;
|
||||
+ if (byteLength != length) {
|
||||
+ // Count the number of multi byte characters
|
||||
+ for (final char c : page.toCharArray()) {
|
||||
+ if (c > 127) {
|
||||
+ multiByteCharacters++;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Allow pages with fewer characters to consume less of the allowed byte quota
|
||||
+ byteAllowed += maxBookPageSize * Math.clamp((double) length / 255D, 0.1D, 1) * multiplier;
|
||||
+
|
||||
+ if (multiByteCharacters > 1) {
|
||||
+ // Penalize multibyte characters
|
||||
+ byteAllowed -= multiByteCharacters;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (byteTotal > byteAllowed) {
|
||||
+ ServerGamePacketListenerImpl.LOGGER.warn("{} tried to send a book too large. Book size: {} - Allowed: {} - Pages: {}", this.player.getScoreboardName(), byteTotal, byteAllowed, pageList.size());
|
||||
+ this.disconnect(Component.literal("Book too large!"));
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Book size limits
|
||||
// CraftBukkit start
|
||||
if (this.lastBookTick + 20 > MinecraftServer.currentTick) {
|
||||
this.disconnect(Component.literal("Book edited too quickly!"));
|
|
@ -1,83 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 7 Oct 2018 12:05:28 -0700
|
||||
Subject: [PATCH] Add PlayerConnectionCloseEvent
|
||||
|
||||
This event is invoked when a player has disconnected. It is guaranteed that,
|
||||
if the server is in online-mode, that the provided uuid and username have been
|
||||
validated.
|
||||
|
||||
The event is invoked for players who have not yet logged into the world, whereas
|
||||
PlayerQuitEvent is only invoked on players who have logged into the world.
|
||||
|
||||
The event is invoked for players who have already logged into the world,
|
||||
although whether or not the player exists in the world at the time of
|
||||
firing is undefined. (That is, whether the plugin can retrieve a Player object
|
||||
using the event parameters is undefined). However, it is guaranteed that this
|
||||
event is invoked AFTER PlayerQuitEvent, if the player has already logged into
|
||||
the world.
|
||||
|
||||
This event is guaranteed to never fire unless AsyncPlayerPreLoginEvent has
|
||||
been called beforehand, and this event may not be called in parallel with
|
||||
AsyncPlayerPreLoginEvent for the same connection.
|
||||
|
||||
Cancelling the AsyncPlayerPreLoginEvent guarantees the corresponding
|
||||
PlayerConnectionCloseEvent is never called.
|
||||
|
||||
The event may be invoked asynchronously or synchronously. As it stands,
|
||||
it is never invoked asynchronously. However, plugins should check
|
||||
Event#isAsynchronous to be future-proof.
|
||||
|
||||
On purpose, the deprecated PlayerPreLoginEvent event is left out of the
|
||||
API spec for this event. Plugins should not be using that event, and
|
||||
how PlayerPreLoginEvent interacts with PlayerConnectionCloseEvent
|
||||
is undefined.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.server.network.ServerLoginPacketListenerImpl$State
|
||||
public net.minecraft.server.network.ServerLoginPacketListenerImpl state
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index c45b8b2c89ffec7bd6a6875963c61f11185d3ee1..38947f40864f3661df2eb4baa0aef5740b82f9d9 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -692,6 +692,26 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
packetlistener1.onDisconnect(disconnectiondetails);
|
||||
}
|
||||
this.pendingActions.clear(); // Free up packet queue.
|
||||
+ // Paper start - Add PlayerConnectionCloseEvent
|
||||
+ final PacketListener packetListener = this.getPacketListener();
|
||||
+ if (packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) {
|
||||
+ /* Player was logged in, either game listener or configuration listener */
|
||||
+ final com.mojang.authlib.GameProfile profile = commonPacketListener.getOwner();
|
||||
+ new com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent(profile.getId(),
|
||||
+ profile.getName(), ((InetSocketAddress) this.address).getAddress(), false).callEvent();
|
||||
+ } else if (packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginListener) {
|
||||
+ /* Player is login stage */
|
||||
+ switch (loginListener.state) {
|
||||
+ case VERIFYING:
|
||||
+ case WAITING_FOR_DUPE_DISCONNECT:
|
||||
+ case PROTOCOL_SWITCHING:
|
||||
+ case ACCEPTED:
|
||||
+ final com.mojang.authlib.GameProfile profile = loginListener.authenticatedProfile; /* Should be non-null at this stage */
|
||||
+ new com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent(profile.getId(), profile.getName(),
|
||||
+ ((InetSocketAddress) this.address).getAddress(), false).callEvent();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Add PlayerConnectionCloseEvent
|
||||
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 636b8aef2348fa4cfe63a9b7d77a64b14dc7a42c..de25b9ea8aa4b7d6fd3fed12cdd16be9ddfcbfff 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -86,7 +86,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
@Nullable
|
||||
String requestedUsername;
|
||||
@Nullable
|
||||
- private GameProfile authenticatedProfile;
|
||||
+ public GameProfile authenticatedProfile; // Paper - public
|
||||
private final String serverId;
|
||||
private final boolean transferred;
|
||||
private ServerPlayer player; // CraftBukkit
|
|
@ -1,164 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach@zachbr.io>
|
||||
Date: Wed, 2 Jan 2019 00:35:43 -0600
|
||||
Subject: [PATCH] Replace OfflinePlayer#getLastPlayed
|
||||
|
||||
Currently OfflinePlayer#getLastPlayed could more accurately be described
|
||||
as "OfflinePlayer#getLastTimeTheirDataWasSaved".
|
||||
|
||||
The API doc says it should return the last time the server "witnessed"
|
||||
the player, whilst also saying it should return the last time they
|
||||
logged in. The current implementation does neither.
|
||||
|
||||
Given this interesting contradiction in the API documentation and the
|
||||
current defacto implementation, I've elected to deprecate (with no
|
||||
intent to remove) and replace it with two new methods, clearly named and
|
||||
documented as to their purpose.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index c2571855ca6a8ecd144b8fbb97d601d1808e8d61..bd130d3a4d0cfe431be627c3f4d85bb394fe099b 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -269,6 +269,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
private int containerCounter;
|
||||
public boolean wonGame;
|
||||
private int containerUpdateDelay; // Paper - Configurable container update tick rate
|
||||
+ public long loginTime; // Paper - Replace OfflinePlayer#getLastPlayed
|
||||
// Paper start - cancellable death event
|
||||
public boolean queueHealthUpdatePacket;
|
||||
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 5fc76fd70f98fe874b38d8da08017fdadbd115e5..cdd1d8222ad1796abd0858b9ed0e2ddc9be83c93 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -182,6 +182,7 @@ public abstract class PlayerList {
|
||||
|
||||
public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData) {
|
||||
player.isRealPlayer = true; // Paper
|
||||
+ player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed
|
||||
GameProfile gameprofile = player.getGameProfile();
|
||||
GameProfileCache usercache = this.server.getProfileCache();
|
||||
// Optional optional; // CraftBukkit - decompile error
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
||||
index 461656e1cb095243bfe7a9ee2906e5b00574ae78..411b280ac3e27e72091db813c0c9b69b62df6097 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
||||
@@ -262,6 +262,61 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
|
||||
return this.getData() != null;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public long getLastLogin() {
|
||||
+ Player player = getPlayer();
|
||||
+ if (player != null) return player.getLastLogin();
|
||||
+
|
||||
+ CompoundTag data = getPaperData();
|
||||
+
|
||||
+ if (data != null) {
|
||||
+ if (data.contains("LastLogin")) {
|
||||
+ return data.getLong("LastLogin");
|
||||
+ } else {
|
||||
+ // if the player file cannot provide accurate data, this is probably the closest we can approximate
|
||||
+ File file = getDataFile();
|
||||
+ return file.lastModified();
|
||||
+ }
|
||||
+ } else {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public long getLastSeen() {
|
||||
+ Player player = getPlayer();
|
||||
+ if (player != null) return player.getLastSeen();
|
||||
+
|
||||
+ CompoundTag data = getPaperData();
|
||||
+
|
||||
+ if (data != null) {
|
||||
+ if (data.contains("LastSeen")) {
|
||||
+ return data.getLong("LastSeen");
|
||||
+ } else {
|
||||
+ // if the player file cannot provide accurate data, this is probably the closest we can approximate
|
||||
+ File file = getDataFile();
|
||||
+ return file.lastModified();
|
||||
+ }
|
||||
+ } else {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private CompoundTag getPaperData() {
|
||||
+ CompoundTag result = getData();
|
||||
+
|
||||
+ if (result != null) {
|
||||
+ if (!result.contains("Paper")) {
|
||||
+ result.put("Paper", new CompoundTag());
|
||||
+ }
|
||||
+ result = result.getCompound("Paper");
|
||||
+ }
|
||||
+
|
||||
+ return result;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public Location getLastDeathLocation() {
|
||||
if (this.getData().contains("LastDeathLocation", 10)) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 004ac565d4124f6059d530034cf0c9a28f0be467..6a3bf3f34ff36e0b11bb3c250074f672b1e81b4f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -210,6 +210,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
private BorderChangeListener clientWorldBorderListener = this.createWorldBorderListener();
|
||||
public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus; // Paper - more resource pack API
|
||||
private static final boolean DISABLE_CHANNEL_LIMIT = System.getProperty("paper.disableChannelLimit") != null; // Paper - add a flag to disable the channel limit
|
||||
+ private long lastSaveTime; // Paper - getLastPlayed replacement API
|
||||
|
||||
public CraftPlayer(CraftServer server, ServerPlayer entity) {
|
||||
super(server, entity);
|
||||
@@ -2049,6 +2050,18 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
this.firstPlayed = firstPlayed;
|
||||
}
|
||||
|
||||
+ // Paper start - getLastPlayed replacement API
|
||||
+ @Override
|
||||
+ public long getLastLogin() {
|
||||
+ return this.getHandle().loginTime;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public long getLastSeen() {
|
||||
+ return this.isOnline() ? System.currentTimeMillis() : this.lastSaveTime;
|
||||
+ }
|
||||
+ // Paper end - getLastPlayed replacement API
|
||||
+
|
||||
public void readExtraData(CompoundTag nbttagcompound) {
|
||||
this.hasPlayedBefore = true;
|
||||
if (nbttagcompound.contains("bukkit")) {
|
||||
@@ -2071,6 +2084,8 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
}
|
||||
|
||||
public void setExtraData(CompoundTag nbttagcompound) {
|
||||
+ this.lastSaveTime = System.currentTimeMillis(); // Paper
|
||||
+
|
||||
if (!nbttagcompound.contains("bukkit")) {
|
||||
nbttagcompound.put("bukkit", new CompoundTag());
|
||||
}
|
||||
@@ -2085,6 +2100,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
data.putLong("firstPlayed", this.getFirstPlayed());
|
||||
data.putLong("lastPlayed", System.currentTimeMillis());
|
||||
data.putString("lastKnownName", handle.getScoreboardName());
|
||||
+
|
||||
+ // Paper start - persist for use in offline save data
|
||||
+ if (!nbttagcompound.contains("Paper")) {
|
||||
+ nbttagcompound.put("Paper", new CompoundTag());
|
||||
+ }
|
||||
+
|
||||
+ CompoundTag paper = nbttagcompound.getCompound("Paper");
|
||||
+ paper.putLong("LastLogin", handle.loginTime);
|
||||
+ paper.putLong("LastSeen", System.currentTimeMillis());
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,24 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: connorhartley <vectrixu+gh@gmail.com>
|
||||
Date: Mon, 7 Jan 2019 14:43:48 -0600
|
||||
Subject: [PATCH] Workaround for vehicle tracking issue on disconnect
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index bd130d3a4d0cfe431be627c3f4d85bb394fe099b..ad2b8ea068469f2b0597c0e0436ad3c94dcb62ea 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1833,6 +1833,13 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
public void disconnect() {
|
||||
this.disconnected = true;
|
||||
this.ejectPassengers();
|
||||
+
|
||||
+ // Paper start - Workaround vehicle not tracking the passenger disconnection dismount
|
||||
+ if (this.isPassenger() && this.getVehicle() instanceof ServerPlayer) {
|
||||
+ this.stopRiding();
|
||||
+ }
|
||||
+ // Paper end - Workaround vehicle not tracking the passenger disconnection dismount
|
||||
+
|
||||
if (this.isSleeping()) {
|
||||
this.stopSleepInBed(true, false);
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach@zachbr.io>
|
||||
Date: Mon, 4 Feb 2019 23:33:24 -0500
|
||||
Subject: [PATCH] Dont block Player#remove if the handle is a custom player
|
||||
|
||||
Upstream throws UOE if you try to call remove on a Player.
|
||||
We just add a check to ensure that the CraftPlayer's handle
|
||||
is a ServerPlayer
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 6a3bf3f34ff36e0b11bb3c250074f672b1e81b4f..d0af4b838bd43ef2388e918ac14e7acec71b63ef 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -224,8 +224,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
+ if (this.getHandle().getClass().equals(ServerPlayer.class)) { // special case for NMS plugins inheriting
|
||||
// Will lead to an inconsistent player state if we remove the player as any other entity.
|
||||
throw new UnsupportedOperationException(String.format("Cannot remove player %s, use Player#kickPlayer(String) instead.", this.getName()));
|
||||
+ } else {
|
||||
+ super.remove();
|
||||
+ }
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,53 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 6 Feb 2019 00:20:33 -0500
|
||||
Subject: [PATCH] BlockDestroyEvent
|
||||
|
||||
Adds an event for when the server is going to destroy a current block,
|
||||
potentially causing it to drop. This event can be cancelled to avoid
|
||||
the block destruction, such as preventing signs from popping when
|
||||
floating in the air.
|
||||
|
||||
This can replace many uses of BlockPhysicsEvent
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 5929b450a26e7c3cf63de3dc1d0e67cb781b24c7..4c4449f7dee8695a362f83b9356e5754244fff18 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -25,6 +25,7 @@ import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
+import io.papermc.paper.util.MCUtil;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.FullChunkStatus;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
@@ -576,9 +577,26 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
return false;
|
||||
} else {
|
||||
FluidState fluid = this.getFluidState(pos);
|
||||
+ // Paper start - BlockDestroyEvent; while the above setAir method is named same and looks very similar
|
||||
+ // they are NOT used with same intent and the above should not fire this event. The above method is more of a BlockSetToAirEvent,
|
||||
+ // it doesn't imply destruction of a block that plays a sound effect / drops an item.
|
||||
+ boolean playEffect = true;
|
||||
+ BlockState effectType = iblockdata;
|
||||
+ int xp = iblockdata.getBlock().getExpDrop(iblockdata, (ServerLevel) this, pos, ItemStack.EMPTY, true);
|
||||
+ if (com.destroystokyo.paper.event.block.BlockDestroyEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
+ com.destroystokyo.paper.event.block.BlockDestroyEvent event = new com.destroystokyo.paper.event.block.BlockDestroyEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), fluid.createLegacyBlock().createCraftBlockData(), effectType.createCraftBlockData(), xp, drop);
|
||||
+ if (!event.callEvent()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ effectType = ((CraftBlockData) event.getEffectBlock()).getState();
|
||||
+ playEffect = event.playEffect();
|
||||
+ drop = event.willDrop();
|
||||
+ xp = event.getExpToDrop();
|
||||
+ }
|
||||
+ // Paper end - BlockDestroyEvent
|
||||
|
||||
- if (!(iblockdata.getBlock() instanceof BaseFireBlock)) {
|
||||
- this.levelEvent(2001, pos, Block.getId(iblockdata));
|
||||
+ if (playEffect && !(effectType.getBlock() instanceof BaseFireBlock)) { // Paper - BlockDestroyEvent
|
||||
+ this.levelEvent(2001, pos, Block.getId(effectType)); // Paper - BlockDestroyEvent
|
||||
}
|
||||
|
||||
if (drop) {
|
|
@ -1,66 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Callahan <mr.callahhh@gmail.com>
|
||||
Date: Wed, 8 Apr 2020 02:42:14 -0500
|
||||
Subject: [PATCH] Async command map building
|
||||
|
||||
This adds a custom pool inorder to make sure that they are closed
|
||||
without much though, as it doesn't matter if the client is not sent
|
||||
commands if the server is restarting. Using the default async pool caused issues to arise
|
||||
due to the shutdown logic generally being much later.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
|
||||
index 72756ef14b8ec8afd80313b9f6aaf76722cb18cf..a05aea8561ac102476ee1b3068942b095950a86a 100644
|
||||
--- a/src/main/java/net/minecraft/commands/Commands.java
|
||||
+++ b/src/main/java/net/minecraft/commands/Commands.java
|
||||
@@ -450,6 +450,24 @@ public class Commands {
|
||||
if ( org.spigotmc.SpigotConfig.tabComplete < 0 ) return; // Spigot
|
||||
// CraftBukkit start
|
||||
// Register Vanilla commands into builtRoot as before
|
||||
+ // Paper start - Perf: Async command map building
|
||||
+ COMMAND_SENDING_POOL.execute(() -> {
|
||||
+ this.sendAsync(player);
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ public static final java.util.concurrent.ThreadPoolExecutor COMMAND_SENDING_POOL = new java.util.concurrent.ThreadPoolExecutor(
|
||||
+ 0, 2, 60L, java.util.concurrent.TimeUnit.SECONDS,
|
||||
+ new java.util.concurrent.LinkedBlockingQueue<>(),
|
||||
+ new com.google.common.util.concurrent.ThreadFactoryBuilder()
|
||||
+ .setNameFormat("Paper Async Command Builder Thread Pool - %1$d")
|
||||
+ .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER))
|
||||
+ .build(),
|
||||
+ new java.util.concurrent.ThreadPoolExecutor.DiscardPolicy()
|
||||
+ );
|
||||
+
|
||||
+ private void sendAsync(ServerPlayer player) {
|
||||
+ // Paper end - Perf: Async command map building
|
||||
Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> map = Maps.newIdentityHashMap(); // Use identity to prevent aliasing issues
|
||||
RootCommandNode vanillaRoot = new RootCommandNode();
|
||||
|
||||
@@ -467,7 +485,14 @@ public class Commands {
|
||||
for (CommandNode node : rootcommandnode.getChildren()) {
|
||||
bukkit.add(node.getName());
|
||||
}
|
||||
+ // Paper start - Perf: Async command map building
|
||||
+ net.minecraft.server.MinecraftServer.getServer().execute(() -> {
|
||||
+ runSync(player, bukkit, rootcommandnode);
|
||||
+ });
|
||||
+ }
|
||||
|
||||
+ private void runSync(ServerPlayer player, Collection<String> bukkit, RootCommandNode<SharedSuggestionProvider> rootcommandnode) {
|
||||
+ // Paper end - Perf: Async command map building
|
||||
PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit));
|
||||
event.getPlayer().getServer().getPluginManager().callEvent(event);
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 699191356a9d873fa6bbe04ea3e5db91eb2db41d..8ecfd7a3daa99dabe796d28d27790fb8b45c628b 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -930,6 +930,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
MinecraftServer.LOGGER.info("Stopping server");
|
||||
+ Commands.COMMAND_SENDING_POOL.shutdownNow(); // Paper - Perf: Async command map building; Shutdown and don't bother finishing
|
||||
MinecraftTimings.stopServer(); // Paper
|
||||
// CraftBukkit start
|
||||
if (this.server != null) {
|
|
@ -1,206 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 19 Apr 2020 18:15:29 -0400
|
||||
Subject: [PATCH] Brigadier Mojang API
|
||||
|
||||
Adds AsyncPlayerSendCommandsEvent
|
||||
- Allows modifying on a per command basis what command data they see.
|
||||
|
||||
Adds CommandRegisteredEvent
|
||||
- Allows manipulating the CommandNode to add more children/metadata for the client
|
||||
|
||||
diff --git a/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java b/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java
|
||||
index 3370731ee064d2693b972a0765c13dd4fd69f66a..09d486a05179b9d878e1c33725b4e614c3544da9 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java
|
||||
@@ -5,7 +5,7 @@ package com.mojang.brigadier.exceptions;
|
||||
|
||||
import com.mojang.brigadier.Message;
|
||||
|
||||
-public class CommandSyntaxException extends Exception {
|
||||
+public class CommandSyntaxException extends Exception implements net.kyori.adventure.util.ComponentMessageThrowable { // Paper - Brigadier API
|
||||
public static final int CONTEXT_AMOUNT = 10;
|
||||
public static boolean ENABLE_COMMAND_STACK_TRACES = true;
|
||||
public static BuiltInExceptionProvider BUILT_IN_EXCEPTIONS = new BuiltInExceptions();
|
||||
@@ -73,4 +73,11 @@ public class CommandSyntaxException extends Exception {
|
||||
public int getCursor() {
|
||||
return cursor;
|
||||
}
|
||||
+
|
||||
+ // Paper start - Brigadier API
|
||||
+ @Override
|
||||
+ public @org.jetbrains.annotations.Nullable net.kyori.adventure.text.Component componentMessage() {
|
||||
+ return io.papermc.paper.brigadier.PaperBrigadier.componentFromMessage(this.message);
|
||||
+ }
|
||||
+ // Paper end - Brigadier API
|
||||
}
|
||||
diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
index da6250df1c5f3385b683cffde47754bca4606f5e..14ccd0c8f721e9be7dca8a5dcb8ef95b5cd82731 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
@@ -34,6 +34,7 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
||||
private final RedirectModifier<S> modifier;
|
||||
private final boolean forks;
|
||||
private Command<S> command;
|
||||
+ public CommandNode<CommandSourceStack> clientNode; // Paper - Brigadier API
|
||||
// CraftBukkit start
|
||||
public void removeCommand(String name) {
|
||||
this.children.remove(name);
|
||||
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
index d9fc3c25bef251df6a53ee47ec224b07240a931c..2a22827f44dd0d524c22264447959a6979e9f0de 100644
|
||||
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
@@ -45,7 +45,7 @@ import net.minecraft.world.phys.Vec2;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import com.mojang.brigadier.tree.CommandNode; // CraftBukkit
|
||||
|
||||
-public class CommandSourceStack implements ExecutionCommandSource<CommandSourceStack>, SharedSuggestionProvider {
|
||||
+public class CommandSourceStack implements ExecutionCommandSource<CommandSourceStack>, SharedSuggestionProvider, com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource { // Paper - Brigadier API
|
||||
|
||||
public static final SimpleCommandExceptionType ERROR_NOT_PLAYER = new SimpleCommandExceptionType(Component.translatable("permissions.requires.player"));
|
||||
public static final SimpleCommandExceptionType ERROR_NOT_ENTITY = new SimpleCommandExceptionType(Component.translatable("permissions.requires.entity"));
|
||||
@@ -170,6 +170,26 @@ public class CommandSourceStack implements ExecutionCommandSource<CommandSourceS
|
||||
return this.textName;
|
||||
}
|
||||
|
||||
+ // Paper start - Brigadier API
|
||||
+ @Override
|
||||
+ public org.bukkit.entity.Entity getBukkitEntity() {
|
||||
+ return getEntity() != null ? getEntity().getBukkitEntity() : null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.World getBukkitWorld() {
|
||||
+ return getLevel() != null ? getLevel().getWorld() : null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.Location getBukkitLocation() {
|
||||
+ Vec3 pos = getPosition();
|
||||
+ org.bukkit.World world = getBukkitWorld();
|
||||
+ Vec2 rot = getRotation();
|
||||
+ return world != null && pos != null ? new org.bukkit.Location(world, pos.x, pos.y, pos.z, rot != null ? rot.y : 0, rot != null ? rot.x : 0) : null;
|
||||
+ }
|
||||
+ // Paper end - Brigadier API
|
||||
+
|
||||
@Override
|
||||
public boolean hasPermission(int level) {
|
||||
// CraftBukkit start
|
||||
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
|
||||
index a05aea8561ac102476ee1b3068942b095950a86a..e25fc35716aff1d1805884b18f67b0eb33d8c05c 100644
|
||||
--- a/src/main/java/net/minecraft/commands/Commands.java
|
||||
+++ b/src/main/java/net/minecraft/commands/Commands.java
|
||||
@@ -486,6 +486,7 @@ public class Commands {
|
||||
bukkit.add(node.getName());
|
||||
}
|
||||
// Paper start - Perf: Async command map building
|
||||
+ new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent<CommandSourceStack>(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper - Brigadier API
|
||||
net.minecraft.server.MinecraftServer.getServer().execute(() -> {
|
||||
runSync(player, bukkit, rootcommandnode);
|
||||
});
|
||||
@@ -493,6 +494,7 @@ public class Commands {
|
||||
|
||||
private void runSync(ServerPlayer player, Collection<String> bukkit, RootCommandNode<SharedSuggestionProvider> rootcommandnode) {
|
||||
// Paper end - Perf: Async command map building
|
||||
+ new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent<CommandSourceStack>(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, true).callEvent(); // Paper - Brigadier API
|
||||
PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit));
|
||||
event.getPlayer().getServer().getPluginManager().callEvent(event);
|
||||
|
||||
@@ -511,6 +513,11 @@ public class Commands {
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
CommandNode<CommandSourceStack> commandnode2 = (CommandNode) iterator.next();
|
||||
+ // Paper start - Brigadier API
|
||||
+ if (commandnode2.clientNode != null) {
|
||||
+ commandnode2 = commandnode2.clientNode;
|
||||
+ }
|
||||
+ // Paper end - Brigadier API
|
||||
if ( !org.spigotmc.SpigotConfig.sendNamespaced && commandnode2.getName().contains( ":" ) ) continue; // Spigot
|
||||
|
||||
if (commandnode2.canUse(source)) {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 577f0e290f66afd2ded18714fb8b5f62a7a9aa71..e786d4b940a6fcd6d5ce66c5e13f52ff001b8367 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -769,19 +769,34 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
builder.suggest(completion.suggestion(), PaperAdventure.asVanilla(completion.tooltip()));
|
||||
}
|
||||
}
|
||||
- this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), builder.buildFuture().join()));
|
||||
+ // Paper start - Brigadier API
|
||||
+ com.mojang.brigadier.suggestion.Suggestions suggestions = builder.buildFuture().join();
|
||||
+ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, packet.getCommand());
|
||||
+ suggestEvent.setCancelled(suggestions.isEmpty());
|
||||
+ if (suggestEvent.callEvent()) {
|
||||
+ this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), limitTo(suggestEvent.getSuggestions(), ServerGamePacketListenerImpl.MAX_COMMAND_SUGGESTIONS)));
|
||||
+ }
|
||||
+ // Paper end - Brigadier API
|
||||
}
|
||||
}
|
||||
+ // Paper start - brig API
|
||||
+ private static Suggestions limitTo(final Suggestions suggestions, final int size) {
|
||||
+ return suggestions.getList().size() <= size ? suggestions : new Suggestions(suggestions.getRange(), suggestions.getList().subList(0, size));
|
||||
+ }
|
||||
+ // Paper end - brig API
|
||||
|
||||
private void sendServerSuggestions(final ServerboundCommandSuggestionPacket packet, final StringReader stringreader) {
|
||||
// Paper end - AsyncTabCompleteEvent
|
||||
ParseResults<CommandSourceStack> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack());
|
||||
|
||||
this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> {
|
||||
- if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [<args>] from showing for plugins with nothing more to offer
|
||||
- Suggestions suggestions1 = suggestions.getList().size() <= 1000 ? suggestions : new Suggestions(suggestions.getRange(), suggestions.getList().subList(0, 1000));
|
||||
-
|
||||
- this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions1));
|
||||
+ // Paper start - Brigadier API
|
||||
+ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, packet.getCommand());
|
||||
+ suggestEvent.setCancelled(suggestions.isEmpty());
|
||||
+ if (suggestEvent.callEvent()) {
|
||||
+ this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), limitTo(suggestEvent.getSuggestions(), ServerGamePacketListenerImpl.MAX_COMMAND_SUGGESTIONS)));
|
||||
+ }
|
||||
+ // Paper end - Brigadier API
|
||||
});
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java
|
||||
index 83d81b9371902b0302d13e53b31c15fac4e67966..d113e54a30db16e2ad955170df6030d15de530d6 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java
|
||||
@@ -20,7 +20,7 @@ import org.bukkit.command.CommandException;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
|
||||
-public class BukkitCommandWrapper implements com.mojang.brigadier.Command<CommandSourceStack>, Predicate<CommandSourceStack>, SuggestionProvider<CommandSourceStack> {
|
||||
+public class BukkitCommandWrapper implements com.mojang.brigadier.Command<CommandSourceStack>, Predicate<CommandSourceStack>, SuggestionProvider<CommandSourceStack>, com.destroystokyo.paper.brigadier.BukkitBrigadierCommand<CommandSourceStack> { // Paper
|
||||
|
||||
private final CraftServer server;
|
||||
private final Command command;
|
||||
@@ -31,10 +31,24 @@ public class BukkitCommandWrapper implements com.mojang.brigadier.Command<Comman
|
||||
}
|
||||
|
||||
public LiteralCommandNode<CommandSourceStack> register(CommandDispatcher<CommandSourceStack> dispatcher, String label) {
|
||||
- return dispatcher.register(
|
||||
- LiteralArgumentBuilder.<CommandSourceStack>literal(label).requires(this).executes(this)
|
||||
- .then(RequiredArgumentBuilder.<CommandSourceStack, String>argument("args", StringArgumentType.greedyString()).suggests(this).executes(this))
|
||||
- );
|
||||
+ // Paper start - Expose Brigadier to Paper-MojangAPI
|
||||
+ com.mojang.brigadier.tree.RootCommandNode<CommandSourceStack> root = dispatcher.getRoot();
|
||||
+ LiteralCommandNode<CommandSourceStack> literal = LiteralArgumentBuilder.<CommandSourceStack>literal(label).requires(this).executes(this).build();
|
||||
+ LiteralCommandNode<CommandSourceStack> defaultNode = literal;
|
||||
+ com.mojang.brigadier.tree.ArgumentCommandNode<CommandSourceStack, String> defaultArgs = RequiredArgumentBuilder.<CommandSourceStack, String>argument("args", StringArgumentType.greedyString()).suggests(this).executes(this).build();
|
||||
+ literal.addChild(defaultArgs);
|
||||
+ com.destroystokyo.paper.event.brigadier.CommandRegisteredEvent<CommandSourceStack> event = new com.destroystokyo.paper.event.brigadier.CommandRegisteredEvent<>(label, this, this.command, root, literal, defaultArgs);
|
||||
+ if (!event.callEvent()) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ literal = event.getLiteral();
|
||||
+ if (event.isRawCommand()) {
|
||||
+ defaultNode.clientNode = literal;
|
||||
+ literal = defaultNode;
|
||||
+ }
|
||||
+ root.addChild(literal);
|
||||
+ return literal;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,436 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sun, 25 Jun 2023 23:10:14 -0700
|
||||
Subject: [PATCH] Improve exact choice recipe ingredients
|
||||
|
||||
Fixes exact choices not working with recipe book clicks
|
||||
and shapeless recipes.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.item.ItemStackLinkedSet TYPE_AND_TAG
|
||||
public net.minecraft.world.entity.player.StackedContents put(II)V
|
||||
public net.minecraft.world.entity.player.StackedContents take(II)I
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/inventory/recipe/RecipeBookExactChoiceRecipe.java b/src/main/java/io/papermc/paper/inventory/recipe/RecipeBookExactChoiceRecipe.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ef68600f6b59674ddea6c77f7e412902888e39b7
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/inventory/recipe/RecipeBookExactChoiceRecipe.java
|
||||
@@ -0,0 +1,30 @@
|
||||
+package io.papermc.paper.inventory.recipe;
|
||||
+
|
||||
+import net.minecraft.world.Container;
|
||||
+import net.minecraft.world.item.crafting.Ingredient;
|
||||
+import net.minecraft.world.item.crafting.Recipe;
|
||||
+
|
||||
+public abstract class RecipeBookExactChoiceRecipe<C extends net.minecraft.world.item.crafting.RecipeInput> implements Recipe<C> {
|
||||
+
|
||||
+ private boolean hasExactIngredients;
|
||||
+
|
||||
+ protected final void checkExactIngredients() {
|
||||
+ // skip any special recipes
|
||||
+ if (this.isSpecial()) {
|
||||
+ this.hasExactIngredients = false;
|
||||
+ return;
|
||||
+ }
|
||||
+ for (final Ingredient ingredient : this.getIngredients()) {
|
||||
+ if (!ingredient.isEmpty() && ingredient.exact) {
|
||||
+ this.hasExactIngredients = true;
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ this.hasExactIngredients = false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final boolean hasExactIngredients() {
|
||||
+ return this.hasExactIngredients;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtraMap.java b/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtraMap.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..568ba6aed2e74b8d84f4e82c1e785ef1587e2617
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtraMap.java
|
||||
@@ -0,0 +1,109 @@
|
||||
+package io.papermc.paper.inventory.recipe;
|
||||
+
|
||||
+import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
|
||||
+import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
+import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
+import it.unimi.dsi.fastutil.ints.IntComparators;
|
||||
+import it.unimi.dsi.fastutil.ints.IntList;
|
||||
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
+import it.unimi.dsi.fastutil.objects.Object2IntOpenCustomHashMap;
|
||||
+import java.util.IdentityHashMap;
|
||||
+import java.util.Map;
|
||||
+import java.util.concurrent.atomic.AtomicInteger;
|
||||
+import net.minecraft.core.registries.BuiltInRegistries;
|
||||
+import net.minecraft.world.entity.player.StackedContents;
|
||||
+import net.minecraft.world.item.ItemStack;
|
||||
+import net.minecraft.world.item.ItemStackLinkedSet;
|
||||
+import net.minecraft.world.item.crafting.CraftingInput;
|
||||
+import net.minecraft.world.item.crafting.Ingredient;
|
||||
+import net.minecraft.world.item.crafting.Recipe;
|
||||
+
|
||||
+public final class StackedContentsExtraMap {
|
||||
+
|
||||
+ private final AtomicInteger idCounter = new AtomicInteger(BuiltInRegistries.ITEM.size()); // start at max vanilla stacked contents idx
|
||||
+ public final Object2IntMap<ItemStack> exactChoiceIds = new Object2IntOpenCustomHashMap<>(ItemStackLinkedSet.TYPE_AND_TAG);
|
||||
+ private final Int2ObjectMap<ItemStack> idToExactChoice = new Int2ObjectOpenHashMap<>();
|
||||
+ private final StackedContents contents;
|
||||
+ public final Map<Ingredient, IntList> extraStackingIds = new IdentityHashMap<>();
|
||||
+
|
||||
+ public StackedContentsExtraMap(final StackedContents contents, final Recipe<?> recipe) {
|
||||
+ this.exactChoiceIds.defaultReturnValue(-1);
|
||||
+ this.contents = contents;
|
||||
+ this.initialize(recipe);
|
||||
+ }
|
||||
+
|
||||
+ private void initialize(final Recipe<?> recipe) {
|
||||
+ if (recipe.hasExactIngredients()) {
|
||||
+ for (final Ingredient ingredient : recipe.getIngredients()) {
|
||||
+ if (!ingredient.isEmpty() && ingredient.exact) {
|
||||
+ final net.minecraft.world.item.ItemStack[] items = ingredient.getItems();
|
||||
+ final IntList idList = new IntArrayList(items.length);
|
||||
+ for (final ItemStack item : items) {
|
||||
+ idList.add(this.registerExact(item)); // I think not copying the stack here is safe because cb copies the stack when creating the ingredient
|
||||
+ if (item.getComponentsPatch().isEmpty()) {
|
||||
+ // add regular index if it's a plain itemstack but still registered as exact
|
||||
+ idList.add(StackedContents.getStackingIndex(item));
|
||||
+ }
|
||||
+ }
|
||||
+ idList.sort(IntComparators.NATURAL_COMPARATOR);
|
||||
+ this.extraStackingIds.put(ingredient, idList);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private int registerExact(final ItemStack exactChoice) {
|
||||
+ final int existing = this.exactChoiceIds.getInt(exactChoice);
|
||||
+ if (existing > -1) {
|
||||
+ return existing;
|
||||
+ }
|
||||
+ final int id = this.idCounter.getAndIncrement();
|
||||
+ this.exactChoiceIds.put(exactChoice, id);
|
||||
+ this.idToExactChoice.put(id, exactChoice);
|
||||
+ return id;
|
||||
+ }
|
||||
+
|
||||
+ public ItemStack getById(int id) {
|
||||
+ return this.idToExactChoice.get(id);
|
||||
+ }
|
||||
+
|
||||
+ public Int2IntMap regularRemoved = new Int2IntArrayMap();
|
||||
+ public void accountInput(final CraftingInput input) {
|
||||
+ // similar logic to the CraftingInput constructor
|
||||
+ for (final ItemStack item : input.items()) {
|
||||
+ if (!item.isEmpty()) {
|
||||
+ if (this.accountStack(item, 1)) {
|
||||
+ // remove one of the items if it was added to the contents as a non-extra item
|
||||
+ final int plainStackIdx = StackedContents.getStackingIndex(item);
|
||||
+ if (this.contents.take(plainStackIdx, 1) == plainStackIdx) {
|
||||
+ this.regularRemoved.put(plainStackIdx, 1);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void resetExtras() {
|
||||
+ // clear previous extra ids
|
||||
+ for (final int extraId : this.exactChoiceIds.values()) {
|
||||
+ this.contents.contents.remove(extraId);
|
||||
+ }
|
||||
+ for (final Int2IntMap.Entry entry : this.regularRemoved.int2IntEntrySet()) {
|
||||
+ this.contents.put(entry.getIntKey(), entry.getIntValue());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public boolean accountStack(final ItemStack stack, final int count) {
|
||||
+ if (!this.exactChoiceIds.isEmpty()) {
|
||||
+ final int id = this.exactChoiceIds.getInt(stack);
|
||||
+ if (id >= 0) {
|
||||
+ this.contents.put(id, count);
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/inventory/recipe/package-info.java b/src/main/java/io/papermc/paper/inventory/recipe/package-info.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..413dfa52760db393ad6a8b5341200ee704a864fc
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/inventory/recipe/package-info.java
|
||||
@@ -0,0 +1,5 @@
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+package io.papermc.paper.inventory.recipe;
|
||||
+
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
diff --git a/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java b/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
index 0bd749af8014dd437229594ef6981a2ead803990..6d1f9c15dc99917a2ac966ea38ef1970f4f0289c 100644
|
||||
--- a/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
+++ b/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
@@ -31,6 +31,7 @@ public class ServerPlaceRecipe<I extends RecipeInput, R extends Recipe<I>> imple
|
||||
this.inventory = entity.getInventory();
|
||||
if (this.testClearGrid() || entity.isCreative()) {
|
||||
this.stackedContents.clear();
|
||||
+ this.stackedContents.initializeExtras(recipe.value(), null); // Paper - Improve exact choice recipe ingredients
|
||||
entity.getInventory().fillStackedContents(this.stackedContents);
|
||||
this.menu.fillCraftSlotsStackedContents(this.stackedContents);
|
||||
if (this.stackedContents.canCraft(recipe.value(), null)) {
|
||||
@@ -77,7 +78,7 @@ public class ServerPlaceRecipe<I extends RecipeInput, R extends Recipe<I>> imple
|
||||
int l = k;
|
||||
|
||||
for (int m : intList) {
|
||||
- ItemStack itemStack2 = StackedContents.fromStackingIndex(m);
|
||||
+ ItemStack itemStack2 = StackedContents.fromStackingIndexWithExtras(m, this.stackedContents); // Paper - Improve exact choice recipe ingredients
|
||||
if (!itemStack2.isEmpty()) {
|
||||
int n = itemStack2.getMaxStackSize();
|
||||
if (n < l) {
|
||||
@@ -96,12 +97,22 @@ public class ServerPlaceRecipe<I extends RecipeInput, R extends Recipe<I>> imple
|
||||
@Override
|
||||
public void addItemToSlot(Integer input, int slot, int amount, int gridX, int gridY) {
|
||||
Slot slot2 = this.menu.getSlot(slot);
|
||||
- ItemStack itemStack = StackedContents.fromStackingIndex(input);
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
+ ItemStack itemStack = null;
|
||||
+ boolean isExact = false;
|
||||
+ if (this.stackedContents.extrasMap != null && input >= net.minecraft.core.registries.BuiltInRegistries.ITEM.size()) {
|
||||
+ itemStack = StackedContents.fromStackingIndexExtras(input, this.stackedContents.extrasMap).copy();
|
||||
+ isExact = true;
|
||||
+ }
|
||||
+ if (itemStack == null) {
|
||||
+ itemStack = StackedContents.fromStackingIndex(input);
|
||||
+ }
|
||||
+ // Paper end - Improve exact choice recipe ingredients
|
||||
if (!itemStack.isEmpty()) {
|
||||
int i = amount;
|
||||
|
||||
while (i > 0) {
|
||||
- i = this.moveItemToGrid(slot2, itemStack, i);
|
||||
+ i = this.moveItemToGrid(slot2, itemStack, i, isExact); // Paper - Improve exact choice recipe ingredients
|
||||
if (i == -1) {
|
||||
return;
|
||||
}
|
||||
@@ -133,8 +144,15 @@ public class ServerPlaceRecipe<I extends RecipeInput, R extends Recipe<I>> imple
|
||||
return i;
|
||||
}
|
||||
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Improve exact choice recipe ingredients
|
||||
+
|
||||
protected int moveItemToGrid(Slot slot, ItemStack stack, int i) {
|
||||
- int j = this.inventory.findSlotMatchingUnusedItem(stack);
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
+ return this.moveItemToGrid(slot, stack, i, false);
|
||||
+ }
|
||||
+ protected int moveItemToGrid(Slot slot, ItemStack stack, int i, final boolean isExact) {
|
||||
+ int j = isExact ? this.inventory.findSlotMatchingItem(stack) : this.inventory.findSlotMatchingUnusedItem(stack);
|
||||
+ // Paper end - Improve exact choice recipe ingredients
|
||||
if (j == -1) {
|
||||
return -1;
|
||||
} else {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/StackedContents.java b/src/main/java/net/minecraft/world/entity/player/StackedContents.java
|
||||
index fa5576e41baec4b52c7ebb877924eb91d3775a2d..fcabf630ce1e4949d00f485a5bff66dd1e54a277 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/StackedContents.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/StackedContents.java
|
||||
@@ -22,8 +22,10 @@ import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
public class StackedContents {
|
||||
private static final int EMPTY = 0;
|
||||
public final Int2IntMap contents = new Int2IntOpenHashMap();
|
||||
+ @Nullable public io.papermc.paper.inventory.recipe.StackedContentsExtraMap extrasMap = null; // Paper - Improve exact choice recipe ingredients
|
||||
|
||||
public void accountSimpleStack(ItemStack stack) {
|
||||
+ if (this.extrasMap != null && !stack.getComponentsPatch().isEmpty() && this.extrasMap.accountStack(stack, Math.min(64, stack.getCount()))) return; // Paper - Improve exact choice recipe ingredients; max of 64 due to accountStack method below
|
||||
if (!stack.isDamaged() && !stack.isEnchanted() && !stack.has(DataComponents.CUSTOM_NAME)) {
|
||||
this.accountStack(stack);
|
||||
}
|
||||
@@ -37,6 +39,7 @@ public class StackedContents {
|
||||
if (!stack.isEmpty()) {
|
||||
int i = getStackingIndex(stack);
|
||||
int j = Math.min(maxCount, stack.getCount());
|
||||
+ if (this.extrasMap != null && !stack.getComponentsPatch().isEmpty() && this.extrasMap.accountStack(stack, j)) return; // Paper - Improve exact choice recipe ingredients; if an exact ingredient, don't include it
|
||||
this.put(i, j);
|
||||
}
|
||||
}
|
||||
@@ -83,6 +86,31 @@ public class StackedContents {
|
||||
return itemId == 0 ? ItemStack.EMPTY : new ItemStack(Item.byId(itemId));
|
||||
}
|
||||
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
+ public void initializeExtras(final Recipe<?> recipe, @Nullable final net.minecraft.world.item.crafting.CraftingInput input) {
|
||||
+ this.extrasMap = new io.papermc.paper.inventory.recipe.StackedContentsExtraMap(this, recipe);
|
||||
+ if (input != null) this.extrasMap.accountInput(input);
|
||||
+ }
|
||||
+
|
||||
+ public void resetExtras() {
|
||||
+ if (this.extrasMap != null && !this.contents.isEmpty()) {
|
||||
+ this.extrasMap.resetExtras();
|
||||
+ }
|
||||
+ this.extrasMap = null;
|
||||
+ }
|
||||
+
|
||||
+ public static ItemStack fromStackingIndexWithExtras(final int itemId, @Nullable final StackedContents contents) {
|
||||
+ if (contents != null && contents.extrasMap != null && itemId >= BuiltInRegistries.ITEM.size()) {
|
||||
+ return fromStackingIndexExtras(itemId, contents.extrasMap);
|
||||
+ }
|
||||
+ return fromStackingIndex(itemId);
|
||||
+ }
|
||||
+
|
||||
+ public static ItemStack fromStackingIndexExtras(final int itemId, final io.papermc.paper.inventory.recipe.StackedContentsExtraMap extrasMap) {
|
||||
+ return extrasMap.getById(itemId).copy();
|
||||
+ }
|
||||
+ // Paper end - Improve exact choice recipe ingredients
|
||||
+
|
||||
public void clear() {
|
||||
this.contents.clear();
|
||||
}
|
||||
@@ -106,7 +134,7 @@ public class StackedContents {
|
||||
this.data = new BitSet(this.ingredientCount + this.itemCount + this.ingredientCount + this.ingredientCount * this.itemCount);
|
||||
|
||||
for (int i = 0; i < this.ingredients.size(); i++) {
|
||||
- IntList intList = this.ingredients.get(i).getStackingIds();
|
||||
+ IntList intList = this.getStackingIds(this.ingredients.get(i)); // Paper - Improve exact choice recipe ingredients
|
||||
|
||||
for (int j = 0; j < this.itemCount; j++) {
|
||||
if (intList.contains(this.items[j])) {
|
||||
@@ -169,7 +197,7 @@ public class StackedContents {
|
||||
IntCollection intCollection = new IntAVLTreeSet();
|
||||
|
||||
for (Ingredient ingredient : this.ingredients) {
|
||||
- intCollection.addAll(ingredient.getStackingIds());
|
||||
+ intCollection.addAll(this.getStackingIds(ingredient)); // Paper - Improve exact choice recipe ingredients
|
||||
}
|
||||
|
||||
IntIterator intIterator = intCollection.iterator();
|
||||
@@ -298,7 +326,7 @@ public class StackedContents {
|
||||
for (Ingredient ingredient : this.ingredients) {
|
||||
int j = 0;
|
||||
|
||||
- for (int k : ingredient.getStackingIds()) {
|
||||
+ for (int k : this.getStackingIds(ingredient)) { // Paper - Improve exact choice recipe ingredients
|
||||
j = Math.max(j, StackedContents.this.contents.get(k));
|
||||
}
|
||||
|
||||
@@ -309,5 +337,17 @@ public class StackedContents {
|
||||
|
||||
return i;
|
||||
}
|
||||
+
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
+ private IntList getStackingIds(final Ingredient ingredient) {
|
||||
+ if (StackedContents.this.extrasMap != null) {
|
||||
+ final IntList ids = StackedContents.this.extrasMap.extraStackingIds.get(ingredient);
|
||||
+ if (ids != null) {
|
||||
+ return ids;
|
||||
+ }
|
||||
+ }
|
||||
+ return ingredient.getStackingIds();
|
||||
+ }
|
||||
+ // Paper end - Improve exact choice recipe ingredients
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java b/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java
|
||||
index f3b6466089ee8be59747a16aac2cac84be30617d..45c80500201aabc1e8643427ebfb8818ab966750 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java
|
||||
@@ -5,7 +5,7 @@ import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
-public abstract class AbstractCookingRecipe implements Recipe<SingleRecipeInput> {
|
||||
+public abstract class AbstractCookingRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<SingleRecipeInput> implements Recipe<SingleRecipeInput> { // Paper - improve exact recipe choices
|
||||
protected final RecipeType<?> type;
|
||||
protected final CookingBookCategory category;
|
||||
protected final String group;
|
||||
@@ -24,6 +24,7 @@ public abstract class AbstractCookingRecipe implements Recipe<SingleRecipeInput>
|
||||
this.result = result;
|
||||
this.experience = experience;
|
||||
this.cookingTime = cookingTime;
|
||||
+ this.checkExactIngredients(); // Paper - improve exact recipe choices
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/world/item/crafting/Recipe.java b/src/main/java/net/minecraft/world/item/crafting/Recipe.java
|
||||
index 3cab383e01c124349f3f96bcbcfe91356d51aa30..b57568d5e9c4c148a4b3c303c925a813fdd5dc67 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/crafting/Recipe.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/crafting/Recipe.java
|
||||
@@ -73,4 +73,10 @@ public interface Recipe<T extends RecipeInput> {
|
||||
}
|
||||
|
||||
org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id); // CraftBukkit
|
||||
+
|
||||
+ // Paper start - improved exact choice recipes
|
||||
+ default boolean hasExactIngredients() {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java
|
||||
index 59372daacd6fef45373c0557ccebb6ff5f16f174..63cf2b66f51df68aa3f6d98c69368ce454869d64 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java
|
||||
@@ -17,7 +17,7 @@ import org.bukkit.craftbukkit.inventory.CraftShapedRecipe;
|
||||
import org.bukkit.inventory.RecipeChoice;
|
||||
// CraftBukkit end
|
||||
|
||||
-public class ShapedRecipe implements CraftingRecipe {
|
||||
+public class ShapedRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<CraftingInput> implements CraftingRecipe { // Paper - improve exact recipe choices
|
||||
|
||||
final ShapedRecipePattern pattern;
|
||||
final ItemStack result;
|
||||
@@ -31,6 +31,7 @@ public class ShapedRecipe implements CraftingRecipe {
|
||||
this.pattern = raw;
|
||||
this.result = result;
|
||||
this.showNotification = showNotification;
|
||||
+ this.checkExactIngredients(); // Paper - improve exact recipe choices
|
||||
}
|
||||
|
||||
public ShapedRecipe(String group, CraftingBookCategory category, ShapedRecipePattern raw, ItemStack result) {
|
||||
diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
index 62401d045245ec7e303ec526c09b5e6fa4c9f17b..213ee4aa988dd4c2a5a7be99b1d13f67338e5209 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
@@ -19,7 +19,7 @@ import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe;
|
||||
// CraftBukkit end
|
||||
|
||||
-public class ShapelessRecipe implements CraftingRecipe {
|
||||
+public class ShapelessRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<CraftingInput> implements CraftingRecipe { // Paper - improve exact recipe choices
|
||||
|
||||
final String group;
|
||||
final CraftingBookCategory category;
|
||||
@@ -31,6 +31,7 @@ public class ShapelessRecipe implements CraftingRecipe {
|
||||
this.category = category;
|
||||
this.result = result;
|
||||
this.ingredients = ingredients;
|
||||
+ this.checkExactIngredients(); // Paper - improve exact recipe choices
|
||||
}
|
||||
|
||||
// CraftBukkit start
|
||||
@@ -75,7 +76,18 @@ public class ShapelessRecipe implements CraftingRecipe {
|
||||
}
|
||||
|
||||
public boolean matches(CraftingInput input, Level world) {
|
||||
- return input.ingredientCount() != this.ingredients.size() ? false : (input.size() == 1 && this.ingredients.size() == 1 ? ((Ingredient) this.ingredients.getFirst()).test(input.getItem(0)) : input.stackedContents().canCraft(this, (IntList) null));
|
||||
+ // Paper start - unwrap ternary & better exact choice recipes
|
||||
+ if (input.ingredientCount() != this.ingredients.size()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (input.size() == 1 && this.ingredients.size() == 1) {
|
||||
+ return this.ingredients.getFirst().test(input.getItem(0));
|
||||
+ }
|
||||
+ input.stackedContents().initializeExtras(this, input); // setup stacked contents for this recipe
|
||||
+ final boolean canCraft = input.stackedContents().canCraft(this, null);
|
||||
+ input.stackedContents().resetExtras();
|
||||
+ return canCraft;
|
||||
+ // Paper end - unwrap ternary & better exact choice recipes
|
||||
}
|
||||
|
||||
public ItemStack assemble(CraftingInput input, HolderLookup.Provider lookup) {
|
Loading…
Add table
Add a link
Reference in a new issue