Finish block entity
This commit is contained in:
@@ -1,356 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
||||
@@ -22,7 +22,6 @@
|
||||
import net.minecraft.world.ContainerHelper;
|
||||
import net.minecraft.world.WorldlyContainer;
|
||||
import net.minecraft.world.entity.ExperienceOrb;
|
||||
-import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.player.StackedItemContents;
|
||||
import net.minecraft.world.inventory.ContainerData;
|
||||
import net.minecraft.world.inventory.RecipeCraftingHolder;
|
||||
@@ -41,6 +40,20 @@
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemType;
|
||||
+import org.bukkit.entity.HumanEntity;
|
||||
+import org.bukkit.entity.Player;
|
||||
+import org.bukkit.event.block.BlockExpEvent;
|
||||
+import org.bukkit.event.inventory.FurnaceBurnEvent;
|
||||
+import org.bukkit.event.inventory.FurnaceExtractEvent;
|
||||
+import org.bukkit.event.inventory.FurnaceSmeltEvent;
|
||||
+import org.bukkit.event.inventory.FurnaceStartSmeltEvent;
|
||||
+import org.bukkit.inventory.CookingRecipe;
|
||||
+// CraftBukkit end
|
||||
|
||||
public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntity implements WorldlyContainer, RecipeCraftingHolder, StackedContentsCompatible {
|
||||
|
||||
@@ -65,6 +78,8 @@
|
||||
protected final ContainerData dataAccess;
|
||||
public final Reference2IntOpenHashMap<ResourceKey<Recipe<?>>> recipesUsed;
|
||||
private final RecipeManager.CachedCheck<SingleRecipeInput, ? extends AbstractCookingRecipe> quickCheck;
|
||||
+ public final RecipeType<? extends AbstractCookingRecipe> recipeType; // Paper - cook speed multiplier API
|
||||
+ public double cookSpeedMultiplier = 1.0; // Paper - cook speed multiplier API
|
||||
|
||||
protected AbstractFurnaceBlockEntity(BlockEntityType<?> blockEntityType, BlockPos pos, BlockState state, RecipeType<? extends AbstractCookingRecipe> recipeType) {
|
||||
super(blockEntityType, pos, state);
|
||||
@@ -110,9 +125,40 @@
|
||||
}
|
||||
};
|
||||
this.recipesUsed = new Reference2IntOpenHashMap();
|
||||
- this.quickCheck = RecipeManager.createCheck(recipeType);
|
||||
+ this.quickCheck = RecipeManager.createCheck((RecipeType<AbstractCookingRecipe>) recipeType); // CraftBukkit - decompile error // Eclipse fail
|
||||
+ this.recipeType = recipeType; // Paper - cook speed multiplier API
|
||||
}
|
||||
|
||||
+ // CraftBukkit start - add fields and methods
|
||||
+ private int maxStack = MAX_STACK;
|
||||
+ public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
||||
+
|
||||
+ public List<ItemStack> getContents() {
|
||||
+ return this.items;
|
||||
+ }
|
||||
+
|
||||
+ public void onOpen(CraftHumanEntity who) {
|
||||
+ this.transaction.add(who);
|
||||
+ }
|
||||
+
|
||||
+ public void onClose(CraftHumanEntity who) {
|
||||
+ this.transaction.remove(who);
|
||||
+ }
|
||||
+
|
||||
+ public List<HumanEntity> getViewers() {
|
||||
+ return this.transaction;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getMaxStackSize() {
|
||||
+ return this.maxStack;
|
||||
+ }
|
||||
+
|
||||
+ public void setMaxStackSize(int size) {
|
||||
+ this.maxStack = size;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
private boolean isLit() {
|
||||
return this.litTimeRemaining > 0;
|
||||
}
|
||||
@@ -132,9 +178,18 @@
|
||||
while (iterator.hasNext()) {
|
||||
String s = (String) iterator.next();
|
||||
|
||||
- this.recipesUsed.put(ResourceKey.create(Registries.RECIPE, ResourceLocation.parse(s)), nbttagcompound1.getInt(s));
|
||||
+ // Paper start - Validate ResourceLocation
|
||||
+ final ResourceLocation resourceLocation = ResourceLocation.tryParse(s);
|
||||
+ if (resourceLocation != null) {
|
||||
+ this.recipesUsed.put(ResourceKey.create(Registries.RECIPE, resourceLocation), nbttagcompound1.getInt(s));
|
||||
+ }
|
||||
}
|
||||
|
||||
+ // Paper start - cook speed multiplier API
|
||||
+ if (nbt.contains("Paper.CookSpeedMultiplier")) {
|
||||
+ this.cookSpeedMultiplier = nbt.getDouble("Paper.CookSpeedMultiplier");
|
||||
+ }
|
||||
+ // Paper end - cook speed multiplier API
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,6 +199,7 @@
|
||||
nbt.putShort("cooking_total_time", (short) this.cookingTotalTime);
|
||||
nbt.putShort("lit_time_remaining", (short) this.litTimeRemaining);
|
||||
nbt.putShort("lit_total_time", (short) this.litTotalTime);
|
||||
+ nbt.putDouble("Paper.CookSpeedMultiplier", this.cookSpeedMultiplier); // Paper - cook speed multiplier API
|
||||
ContainerHelper.saveAllItems(nbt, this.items, registries);
|
||||
CompoundTag nbttagcompound1 = new CompoundTag();
|
||||
|
||||
@@ -175,7 +231,7 @@
|
||||
RecipeHolder recipeholder;
|
||||
|
||||
if (flag2) {
|
||||
- recipeholder = (RecipeHolder) blockEntity.quickCheck.getRecipeFor(singlerecipeinput, world).orElse((Object) null);
|
||||
+ recipeholder = (RecipeHolder) blockEntity.quickCheck.getRecipeFor(singlerecipeinput, world).orElse(null); // CraftBukkit - decompile error
|
||||
} else {
|
||||
recipeholder = null;
|
||||
}
|
||||
@@ -183,11 +239,22 @@
|
||||
int i = blockEntity.getMaxStackSize();
|
||||
|
||||
if (!blockEntity.isLit() && AbstractFurnaceBlockEntity.canBurn(world.registryAccess(), recipeholder, singlerecipeinput, blockEntity.items, i)) {
|
||||
- blockEntity.litTimeRemaining = blockEntity.getBurnDuration(world.fuelValues(), itemstack);
|
||||
+ // CraftBukkit start
|
||||
+ CraftItemStack fuel = CraftItemStack.asCraftMirror(itemstack);
|
||||
+
|
||||
+ FurnaceBurnEvent furnaceBurnEvent = new FurnaceBurnEvent(CraftBlock.at(world, pos), fuel, blockEntity.getBurnDuration(world.fuelValues(), itemstack));
|
||||
+ world.getCraftServer().getPluginManager().callEvent(furnaceBurnEvent);
|
||||
+
|
||||
+ if (furnaceBurnEvent.isCancelled()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ blockEntity.litTimeRemaining = furnaceBurnEvent.getBurnTime();
|
||||
blockEntity.litTotalTime = blockEntity.litTimeRemaining;
|
||||
- if (blockEntity.isLit()) {
|
||||
+ if (blockEntity.isLit() && furnaceBurnEvent.isBurning()) {
|
||||
+ // CraftBukkit end
|
||||
flag1 = true;
|
||||
- if (flag3) {
|
||||
+ if (flag3 && furnaceBurnEvent.willConsumeFuel()) { // Paper - add consumeFuel to FurnaceBurnEvent
|
||||
Item item = itemstack.getItem();
|
||||
|
||||
itemstack.shrink(1);
|
||||
@@ -199,11 +266,23 @@
|
||||
}
|
||||
|
||||
if (blockEntity.isLit() && AbstractFurnaceBlockEntity.canBurn(world.registryAccess(), recipeholder, singlerecipeinput, blockEntity.items, i)) {
|
||||
+ // CraftBukkit start
|
||||
+ if (recipeholder != null && blockEntity.cookingTimer == 0) {
|
||||
+ CraftItemStack source = CraftItemStack.asCraftMirror(blockEntity.items.get(0));
|
||||
+ CookingRecipe<?> recipe = (CookingRecipe<?>) recipeholder.toBukkitRecipe();
|
||||
+
|
||||
+ FurnaceStartSmeltEvent event = new FurnaceStartSmeltEvent(CraftBlock.at(world, pos), source, recipe, AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity, blockEntity.recipeType, blockEntity.cookSpeedMultiplier)); // Paper - cook speed multiplier API
|
||||
+ world.getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ blockEntity.cookingTotalTime = event.getTotalCookTime();
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
++blockEntity.cookingTimer;
|
||||
- if (blockEntity.cookingTimer == blockEntity.cookingTotalTime) {
|
||||
+ if (blockEntity.cookingTimer >= blockEntity.cookingTotalTime) { // Paper - cook speed multiplier API
|
||||
blockEntity.cookingTimer = 0;
|
||||
- blockEntity.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity);
|
||||
- if (AbstractFurnaceBlockEntity.burn(world.registryAccess(), recipeholder, singlerecipeinput, blockEntity.items, i)) {
|
||||
+ blockEntity.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity, blockEntity.recipeType, blockEntity.cookSpeedMultiplier); // Paper - cook speed multiplier API
|
||||
+ if (AbstractFurnaceBlockEntity.burn(blockEntity.level, blockEntity.worldPosition, world.registryAccess(), recipeholder, singlerecipeinput, blockEntity.items, i)) { // CraftBukkit
|
||||
blockEntity.setRecipeUsed(recipeholder);
|
||||
}
|
||||
|
||||
@@ -242,20 +321,47 @@
|
||||
}
|
||||
}
|
||||
|
||||
- private static boolean burn(RegistryAccess dynamicRegistryManager, @Nullable RecipeHolder<? extends AbstractCookingRecipe> recipe, SingleRecipeInput input, NonNullList<ItemStack> inventory, int maxCount) {
|
||||
- if (recipe != null && AbstractFurnaceBlockEntity.canBurn(dynamicRegistryManager, recipe, input, inventory, maxCount)) {
|
||||
- ItemStack itemstack = (ItemStack) inventory.get(0);
|
||||
- ItemStack itemstack1 = ((AbstractCookingRecipe) recipe.value()).assemble(input, dynamicRegistryManager);
|
||||
- ItemStack itemstack2 = (ItemStack) inventory.get(2);
|
||||
+ private static boolean burn(Level world, BlockPos blockposition, RegistryAccess iregistrycustom, @Nullable RecipeHolder<? extends AbstractCookingRecipe> recipeholder, SingleRecipeInput singlerecipeinput, NonNullList<ItemStack> nonnulllist, int i) { // CraftBukkit
|
||||
+ if (recipeholder != null && AbstractFurnaceBlockEntity.canBurn(iregistrycustom, recipeholder, singlerecipeinput, nonnulllist, i)) {
|
||||
+ ItemStack itemstack = (ItemStack) nonnulllist.get(0);
|
||||
+ ItemStack itemstack1 = ((AbstractCookingRecipe) recipeholder.value()).assemble(singlerecipeinput, iregistrycustom);
|
||||
+ ItemStack itemstack2 = (ItemStack) nonnulllist.get(2);
|
||||
|
||||
+ // CraftBukkit start - fire FurnaceSmeltEvent
|
||||
+ CraftItemStack source = CraftItemStack.asCraftMirror(itemstack);
|
||||
+ org.bukkit.inventory.ItemStack result = CraftItemStack.asBukkitCopy(itemstack1);
|
||||
+
|
||||
+ FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(CraftBlock.at(world, blockposition), source, result, (org.bukkit.inventory.CookingRecipe<?>) recipeholder.toBukkitRecipe()); // Paper - Add recipe to cook events
|
||||
+ world.getCraftServer().getPluginManager().callEvent(furnaceSmeltEvent);
|
||||
+
|
||||
+ if (furnaceSmeltEvent.isCancelled()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ result = furnaceSmeltEvent.getResult();
|
||||
+ itemstack1 = CraftItemStack.asNMSCopy(result);
|
||||
+
|
||||
+ if (!itemstack1.isEmpty()) {
|
||||
+ if (itemstack2.isEmpty()) {
|
||||
+ nonnulllist.set(2, itemstack1.copy());
|
||||
+ } else if (CraftItemStack.asCraftMirror(itemstack2).isSimilar(result)) {
|
||||
+ itemstack2.grow(itemstack1.getCount());
|
||||
+ } else {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
if (itemstack2.isEmpty()) {
|
||||
- inventory.set(2, itemstack1.copy());
|
||||
+ nonnulllist.set(2, itemstack1.copy());
|
||||
} else if (ItemStack.isSameItemSameComponents(itemstack2, itemstack1)) {
|
||||
itemstack2.grow(1);
|
||||
}
|
||||
+ */
|
||||
+ // CraftBukkit end
|
||||
|
||||
- if (itemstack.is(Blocks.WET_SPONGE.asItem()) && !((ItemStack) inventory.get(1)).isEmpty() && ((ItemStack) inventory.get(1)).is(Items.BUCKET)) {
|
||||
- inventory.set(1, new ItemStack(Items.WATER_BUCKET));
|
||||
+ if (itemstack.is(Blocks.WET_SPONGE.asItem()) && !((ItemStack) nonnulllist.get(1)).isEmpty() && ((ItemStack) nonnulllist.get(1)).is(Items.BUCKET)) {
|
||||
+ nonnulllist.set(1, new ItemStack(Items.WATER_BUCKET));
|
||||
}
|
||||
|
||||
itemstack.shrink(1);
|
||||
@@ -269,12 +375,14 @@
|
||||
return fuelRegistry.burnDuration(stack);
|
||||
}
|
||||
|
||||
- public static int getTotalCookTime(ServerLevel world, AbstractFurnaceBlockEntity furnace) {
|
||||
+ public static int getTotalCookTime(@Nullable ServerLevel world, AbstractFurnaceBlockEntity furnace, RecipeType<? extends AbstractCookingRecipe> recipeType, double cookSpeedMultiplier) { // Paper - cook speed multiplier API
|
||||
SingleRecipeInput singlerecipeinput = new SingleRecipeInput(furnace.getItem(0));
|
||||
|
||||
- return (Integer) furnace.quickCheck.getRecipeFor(singlerecipeinput, world).map((recipeholder) -> {
|
||||
- return ((AbstractCookingRecipe) recipeholder.value()).cookingTime();
|
||||
- }).orElse(200);
|
||||
+ // Paper start - cook speed multiplier API
|
||||
+ /* Scale the recipe's cooking time to the current cookSpeedMultiplier */
|
||||
+ int cookTime = world != null ? furnace.quickCheck.getRecipeFor(singlerecipeinput, world).map(holder -> holder.value().cookingTime()).orElse(200) : (net.minecraft.server.MinecraftServer.getServer().getRecipeManager().getRecipeFor(recipeType, singlerecipeinput, world /* passing a null level here is safe. world is only used for map extending recipes which won't happen here */).map(holder -> holder.value().cookingTime()).orElse(200));
|
||||
+ return (int) Math.ceil (cookTime / cookSpeedMultiplier);
|
||||
+ // Paper end - cook speed multiplier API
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -320,12 +428,11 @@
|
||||
if (world instanceof ServerLevel) {
|
||||
ServerLevel worldserver = (ServerLevel) world;
|
||||
|
||||
- this.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(worldserver, this);
|
||||
+ this.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(worldserver, this, this.recipeType, this.cookSpeedMultiplier); // Paper - cook speed multiplier API
|
||||
this.cookingTimer = 0;
|
||||
this.setChanged();
|
||||
}
|
||||
}
|
||||
-
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -358,19 +465,19 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void awardUsedRecipes(Player player, List<ItemStack> ingredients) {}
|
||||
+ public void awardUsedRecipes(net.minecraft.world.entity.player.Player player, List<ItemStack> ingredients) {}
|
||||
|
||||
- public void awardUsedRecipesAndPopExperience(ServerPlayer player) {
|
||||
- List<RecipeHolder<?>> list = this.getRecipesToAwardAndPopExperience(player.serverLevel(), player.position());
|
||||
+ public void awardUsedRecipesAndPopExperience(ServerPlayer entityplayer, ItemStack itemstack, int amount) { // CraftBukkit
|
||||
+ List<RecipeHolder<?>> list = this.getRecipesToAwardAndPopExperience(entityplayer.serverLevel(), entityplayer.position(), this.worldPosition, entityplayer, itemstack, amount); // CraftBukkit
|
||||
|
||||
- player.awardRecipes(list);
|
||||
+ entityplayer.awardRecipes(list);
|
||||
Iterator iterator = list.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
RecipeHolder<?> recipeholder = (RecipeHolder) iterator.next();
|
||||
|
||||
if (recipeholder != null) {
|
||||
- player.triggerRecipeCrafted(recipeholder, this.items);
|
||||
+ entityplayer.triggerRecipeCrafted(recipeholder, this.items);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,41 +485,56 @@
|
||||
}
|
||||
|
||||
public List<RecipeHolder<?>> getRecipesToAwardAndPopExperience(ServerLevel world, Vec3 pos) {
|
||||
+ // CraftBukkit start
|
||||
+ return this.getRecipesToAwardAndPopExperience(world, pos, this.worldPosition, null, null, 0);
|
||||
+ }
|
||||
+
|
||||
+ public List<RecipeHolder<?>> getRecipesToAwardAndPopExperience(ServerLevel worldserver, Vec3 vec3d, BlockPos blockposition, ServerPlayer entityplayer, ItemStack itemstack, int amount) {
|
||||
+ // CraftBukkit end
|
||||
List<RecipeHolder<?>> list = Lists.newArrayList();
|
||||
ObjectIterator objectiterator = this.recipesUsed.reference2IntEntrySet().iterator();
|
||||
|
||||
while (objectiterator.hasNext()) {
|
||||
Entry<ResourceKey<Recipe<?>>> entry = (Entry) objectiterator.next();
|
||||
|
||||
- world.recipeAccess().byKey((ResourceKey) entry.getKey()).ifPresent((recipeholder) -> {
|
||||
+ worldserver.recipeAccess().byKey(entry.getKey()).ifPresent((recipeholder) -> { // CraftBukkit - decompile error
|
||||
+ if (!(recipeholder.value() instanceof AbstractCookingRecipe)) return; // Paper - don't process non-cooking recipes
|
||||
list.add(recipeholder);
|
||||
- AbstractFurnaceBlockEntity.createExperience(world, pos, entry.getIntValue(), ((AbstractCookingRecipe) recipeholder.value()).experience());
|
||||
+ AbstractFurnaceBlockEntity.createExperience(worldserver, vec3d, entry.getIntValue(), ((AbstractCookingRecipe) recipeholder.value()).experience(), blockposition, entityplayer, itemstack, amount); // CraftBukkit
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
- private static void createExperience(ServerLevel world, Vec3 pos, int multiplier, float experience) {
|
||||
- int j = Mth.floor((float) multiplier * experience);
|
||||
- float f1 = Mth.frac((float) multiplier * experience);
|
||||
+ private static void createExperience(ServerLevel worldserver, Vec3 vec3d, int i, float f, BlockPos blockposition, net.minecraft.world.entity.player.Player entityhuman, ItemStack itemstack, int amount) { // CraftBukkit
|
||||
+ int j = Mth.floor((float) i * f);
|
||||
+ float f1 = Mth.frac((float) i * f);
|
||||
|
||||
if (f1 != 0.0F && Math.random() < (double) f1) {
|
||||
++j;
|
||||
}
|
||||
|
||||
- ExperienceOrb.award(world, pos, j);
|
||||
+ // CraftBukkit start - fire FurnaceExtractEvent / BlockExpEvent
|
||||
+ BlockExpEvent event;
|
||||
+ if (amount != 0) {
|
||||
+ event = new FurnaceExtractEvent((Player) entityhuman.getBukkitEntity(), CraftBlock.at(worldserver, blockposition), CraftItemType.minecraftToBukkit(itemstack.getItem()), amount, j);
|
||||
+ } else {
|
||||
+ event = new BlockExpEvent(CraftBlock.at(worldserver, blockposition), j);
|
||||
+ }
|
||||
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
|
||||
+ j = event.getExpToDrop();
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ ExperienceOrb.award(worldserver, vec3d, j, org.bukkit.entity.ExperienceOrb.SpawnReason.FURNACE, entityhuman); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillStackedContents(StackedItemContents finder) {
|
||||
- Iterator iterator = this.items.iterator();
|
||||
+ // Paper start - don't account fuel stack (fixes MC-243057)
|
||||
+ finder.accountStack(this.items.get(SLOT_INPUT));
|
||||
+ finder.accountStack(this.items.get(SLOT_RESULT));
|
||||
+ // Paper end
|
||||
|
||||
- while (iterator.hasNext()) {
|
||||
- ItemStack itemstack = (ItemStack) iterator.next();
|
||||
-
|
||||
- finder.accountStack(itemstack);
|
||||
- }
|
||||
-
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/BannerBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BannerBlockEntity.java
|
||||
@@ -19,13 +19,17 @@
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import java.util.List;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class BannerBlockEntity extends BlockEntity implements Nameable {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final int MAX_PATTERNS = 6;
|
||||
private static final String TAG_PATTERNS = "patterns";
|
||||
@Nullable
|
||||
- private Component name;
|
||||
+ public Component name; // Paper - public
|
||||
public DyeColor baseColor;
|
||||
private BannerPatternLayers patterns;
|
||||
|
||||
@@ -53,7 +57,7 @@
|
||||
@Override
|
||||
protected void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
super.saveAdditional(nbt, registries);
|
||||
- if (!this.patterns.equals(BannerPatternLayers.EMPTY)) {
|
||||
+ if (!this.patterns.equals(BannerPatternLayers.EMPTY) || serialisingForNetwork.get()) { // Paper - always send patterns to client
|
||||
nbt.put("patterns", (Tag) BannerPatternLayers.CODEC.encodeStart(registries.createSerializationContext(NbtOps.INSTANCE), this.patterns).getOrThrow());
|
||||
}
|
||||
|
||||
@@ -74,7 +78,7 @@
|
||||
BannerPatternLayers.CODEC.parse(registries.createSerializationContext(NbtOps.INSTANCE), nbt.get("patterns")).resultOrPartial((s) -> {
|
||||
BannerBlockEntity.LOGGER.error("Failed to parse banner patterns: '{}'", s);
|
||||
}).ifPresent((bannerpatternlayers) -> {
|
||||
- this.patterns = bannerpatternlayers;
|
||||
+ this.setPatterns(bannerpatternlayers); // CraftBukkit - apply limits
|
||||
});
|
||||
}
|
||||
|
||||
@@ -85,9 +89,18 @@
|
||||
return ClientboundBlockEntityDataPacket.create(this);
|
||||
}
|
||||
|
||||
+ // Paper start - always send patterns to client
|
||||
+ ThreadLocal<Boolean> serialisingForNetwork = ThreadLocal.withInitial(() -> Boolean.FALSE);
|
||||
@Override
|
||||
public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
|
||||
+ final Boolean wasSerialisingForNetwork = serialisingForNetwork.get();
|
||||
+ try {
|
||||
+ serialisingForNetwork.set(Boolean.TRUE);
|
||||
return this.saveWithoutMetadata(registries);
|
||||
+ } finally {
|
||||
+ serialisingForNetwork.set(wasSerialisingForNetwork);
|
||||
+ }
|
||||
+ // Paper end - always send patterns to client
|
||||
}
|
||||
|
||||
public BannerPatternLayers getPatterns() {
|
||||
@@ -108,7 +121,7 @@
|
||||
@Override
|
||||
protected void applyImplicitComponents(BlockEntity.DataComponentInput components) {
|
||||
super.applyImplicitComponents(components);
|
||||
- this.patterns = (BannerPatternLayers) components.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY);
|
||||
+ this.setPatterns((BannerPatternLayers) components.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY)); // CraftBukkit - apply limits
|
||||
this.name = (Component) components.get(DataComponents.CUSTOM_NAME);
|
||||
}
|
||||
|
||||
@@ -124,4 +137,13 @@
|
||||
nbt.remove("patterns");
|
||||
nbt.remove("CustomName");
|
||||
}
|
||||
+
|
||||
+ // CraftBukkit start
|
||||
+ public void setPatterns(BannerPatternLayers bannerpatternlayers) {
|
||||
+ if (bannerpatternlayers.layers().size() > 20) {
|
||||
+ bannerpatternlayers = new BannerPatternLayers(List.copyOf(bannerpatternlayers.layers().subList(0, 20)));
|
||||
+ }
|
||||
+ this.patterns = bannerpatternlayers;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
@@ -1,259 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.minecraft.world.level.block.entity;
|
||||
|
||||
+import com.destroystokyo.paper.event.block.BeaconEffectEvent;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.Collection;
|
||||
@@ -45,6 +46,11 @@
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||
+import org.bukkit.craftbukkit.potion.CraftPotionUtil;
|
||||
+import org.bukkit.potion.PotionEffect;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Nameable {
|
||||
|
||||
@@ -71,7 +77,36 @@
|
||||
public Component name;
|
||||
public LockCode lockKey;
|
||||
private final ContainerData dataAccess;
|
||||
+ // CraftBukkit start - add fields and methods
|
||||
+ public PotionEffect getPrimaryEffect() {
|
||||
+ return (this.primaryPower != null) ? CraftPotionUtil.toBukkit(new MobEffectInstance(this.primaryPower, BeaconBlockEntity.getLevel(this.levels), BeaconBlockEntity.getAmplification(this.levels, this.primaryPower, this.secondaryPower), true, true)) : null;
|
||||
+ }
|
||||
|
||||
+ public PotionEffect getSecondaryEffect() {
|
||||
+ return (BeaconBlockEntity.hasSecondaryEffect(this.levels, this.primaryPower, this.secondaryPower)) ? CraftPotionUtil.toBukkit(new MobEffectInstance(this.secondaryPower, BeaconBlockEntity.getLevel(this.levels), BeaconBlockEntity.getAmplification(this.levels, this.primaryPower, this.secondaryPower), true, true)) : null;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ // Paper start - Custom beacon ranges
|
||||
+ private final String PAPER_RANGE_TAG = "Paper.Range";
|
||||
+ private double effectRange = -1;
|
||||
+
|
||||
+ public double getEffectRange() {
|
||||
+ if (this.effectRange < 0) {
|
||||
+ return this.levels * 10 + 10;
|
||||
+ } else {
|
||||
+ return effectRange;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void setEffectRange(double range) {
|
||||
+ this.effectRange = range;
|
||||
+ }
|
||||
+
|
||||
+ public void resetEffectRange() {
|
||||
+ this.effectRange = -1;
|
||||
+ }
|
||||
+ // Paper end - Custom beacon ranges
|
||||
+
|
||||
@Nullable
|
||||
static Holder<MobEffect> filterEffect(@Nullable Holder<MobEffect> effect) {
|
||||
return BeaconBlockEntity.VALID_EFFECTS.contains(effect) ? effect : null;
|
||||
@@ -186,10 +221,19 @@
|
||||
}
|
||||
|
||||
if (blockEntity.levels > 0 && !blockEntity.beamSections.isEmpty()) {
|
||||
- BeaconBlockEntity.applyEffects(world, pos, blockEntity.levels, blockEntity.primaryPower, blockEntity.secondaryPower);
|
||||
+ BeaconBlockEntity.applyEffects(world, pos, blockEntity.levels, blockEntity.primaryPower, blockEntity.secondaryPower, blockEntity); // Paper - Custom beacon ranges
|
||||
BeaconBlockEntity.playSound(world, pos, SoundEvents.BEACON_AMBIENT);
|
||||
}
|
||||
}
|
||||
+ // Paper start - beacon activation/deactivation events
|
||||
+ if (i1 <= 0 && blockEntity.levels > 0) {
|
||||
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, pos);
|
||||
+ new io.papermc.paper.event.block.BeaconActivatedEvent(block).callEvent();
|
||||
+ } else if (i1 > 0 && blockEntity.levels <= 0) {
|
||||
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, pos);
|
||||
+ new io.papermc.paper.event.block.BeaconDeactivatedEvent(block).callEvent();
|
||||
+ }
|
||||
+ // Paper end - beacon activation/deactivation events
|
||||
|
||||
if (blockEntity.lastCheckY >= l) {
|
||||
blockEntity.lastCheckY = world.getMinY() - 1;
|
||||
@@ -247,43 +291,123 @@
|
||||
|
||||
@Override
|
||||
public void setRemoved() {
|
||||
+ // Paper start - beacon activation/deactivation events
|
||||
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, worldPosition);
|
||||
+ new io.papermc.paper.event.block.BeaconDeactivatedEvent(block).callEvent();
|
||||
+ // Paper end - beacon activation/deactivation events
|
||||
+ // Paper start - fix MC-153086
|
||||
+ if (this.levels > 0 && !this.beamSections.isEmpty()) {
|
||||
BeaconBlockEntity.playSound(this.level, this.worldPosition, SoundEvents.BEACON_DEACTIVATE);
|
||||
+ }
|
||||
+ // Paper end
|
||||
super.setRemoved();
|
||||
}
|
||||
|
||||
- private static void applyEffects(Level world, BlockPos pos, int beaconLevel, @Nullable Holder<MobEffect> primaryEffect, @Nullable Holder<MobEffect> secondaryEffect) {
|
||||
- if (!world.isClientSide && primaryEffect != null) {
|
||||
- double d0 = (double) (beaconLevel * 10 + 10);
|
||||
+ // CraftBukkit start - split into components
|
||||
+ private static byte getAmplification(int i, @Nullable Holder<MobEffect> holder, @Nullable Holder<MobEffect> holder1) {
|
||||
+ {
|
||||
byte b0 = 0;
|
||||
|
||||
- if (beaconLevel >= 4 && Objects.equals(primaryEffect, secondaryEffect)) {
|
||||
+ if (i >= 4 && Objects.equals(holder, holder1)) {
|
||||
b0 = 1;
|
||||
}
|
||||
|
||||
- int j = (9 + beaconLevel * 2) * 20;
|
||||
- AABB axisalignedbb = (new AABB(pos)).inflate(d0).expandTowards(0.0D, (double) world.getHeight(), 0.0D);
|
||||
- List<Player> list = world.getEntitiesOfClass(Player.class, axisalignedbb);
|
||||
+ return b0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static int getLevel(int i) {
|
||||
+ {
|
||||
+ int j = (9 + i * 2) * 20;
|
||||
+ return j;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static List getHumansInRange(Level world, BlockPos blockposition, int i) {
|
||||
+ // Paper start - Custom beacon ranges
|
||||
+ return BeaconBlockEntity.getHumansInRange(world, blockposition, i, null);
|
||||
+ }
|
||||
+ public static List getHumansInRange(Level world, BlockPos blockposition, int i, @Nullable BeaconBlockEntity blockEntity) {
|
||||
+ // Paper end - Custom beacon ranges
|
||||
+ {
|
||||
+ double d0 = blockEntity != null ? blockEntity.getEffectRange() : (i * 10 + 10); // Paper - Custom beacon ranges
|
||||
+
|
||||
+ AABB axisalignedbb = (new AABB(blockposition)).inflate(d0).expandTowards(0.0D, (double) world.getHeight(), 0.0D);
|
||||
+ // Paper start - Perf: optimize player lookup for beacons
|
||||
+ List<Player> list;
|
||||
+ if (d0 <= 128.0) {
|
||||
+ list = world.getEntitiesOfClass(Player.class, axisalignedbb);
|
||||
+ } else {
|
||||
+ list = new java.util.ArrayList<>();
|
||||
+ for (Player player : world.players()) {
|
||||
+ if (player.isSpectator()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (player.getBoundingBox().intersects(axisalignedbb)) {
|
||||
+ list.add(player);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Perf: optimize player lookup for beacons
|
||||
+
|
||||
+ return list;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static void applyEffect(List list, @Nullable Holder<MobEffect> holder, int j, int b0, boolean isPrimary, BlockPos worldPosition) { // Paper - BeaconEffectEvent
|
||||
+ if (!list.isEmpty()) { // Paper - BeaconEffectEvent
|
||||
Iterator iterator = list.iterator();
|
||||
|
||||
Player entityhuman;
|
||||
+ // Paper start - BeaconEffectEvent
|
||||
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(((Player) list.get(0)).level(), worldPosition);
|
||||
+ PotionEffect effect = CraftPotionUtil.toBukkit(new MobEffectInstance(holder, j, b0, true, true));
|
||||
+ // Paper end - BeaconEffectEvent
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
- entityhuman = (Player) iterator.next();
|
||||
- entityhuman.addEffect(new MobEffectInstance(primaryEffect, j, b0, true, true));
|
||||
+ // Paper start - BeaconEffectEvent
|
||||
+ entityhuman = (ServerPlayer) iterator.next();
|
||||
+ BeaconEffectEvent event = new BeaconEffectEvent(block, effect, (org.bukkit.entity.Player) entityhuman.getBukkitEntity(), isPrimary);
|
||||
+ if (CraftEventFactory.callEvent(event).isCancelled()) continue;
|
||||
+ entityhuman.addEffect(new MobEffectInstance(CraftPotionUtil.fromBukkit(event.getEffect())), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.BEACON);
|
||||
+ // Paper end - BeaconEffectEvent
|
||||
}
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- if (beaconLevel >= 4 && !Objects.equals(primaryEffect, secondaryEffect) && secondaryEffect != null) {
|
||||
- iterator = list.iterator();
|
||||
-
|
||||
- while (iterator.hasNext()) {
|
||||
- entityhuman = (Player) iterator.next();
|
||||
- entityhuman.addEffect(new MobEffectInstance(secondaryEffect, j, 0, true, true));
|
||||
- }
|
||||
+ private static boolean hasSecondaryEffect(int i, @Nullable Holder<MobEffect> holder, @Nullable Holder<MobEffect> holder1) {
|
||||
+ {
|
||||
+ if (i >= 4 && !Objects.equals(holder, holder1) && holder1 != null) {
|
||||
+ return true;
|
||||
}
|
||||
|
||||
+ return false;
|
||||
}
|
||||
}
|
||||
|
||||
+ private static void applyEffects(Level world, BlockPos pos, int beaconLevel, @Nullable Holder<MobEffect> primaryEffect, @Nullable Holder<MobEffect> secondaryEffect) {
|
||||
+ // Paper start - Custom beacon ranges
|
||||
+ BeaconBlockEntity.applyEffects(world, pos, beaconLevel, primaryEffect, secondaryEffect, null);
|
||||
+ }
|
||||
+ private static void applyEffects(Level world, BlockPos pos, int beaconLevel, @Nullable Holder<MobEffect> primaryEffect, @Nullable Holder<MobEffect> secondaryEffect, @Nullable BeaconBlockEntity blockEntity) {
|
||||
+ // Paper end - Custom beacon ranges
|
||||
+ if (!world.isClientSide && primaryEffect != null) {
|
||||
+ double d0 = (double) (beaconLevel * 10 + 10);
|
||||
+ byte b0 = BeaconBlockEntity.getAmplification(beaconLevel, primaryEffect, secondaryEffect);
|
||||
+
|
||||
+ int j = BeaconBlockEntity.getLevel(beaconLevel);
|
||||
+ List list = BeaconBlockEntity.getHumansInRange(world, pos, beaconLevel, blockEntity); // Paper - Custom beacon ranges
|
||||
+
|
||||
+ BeaconBlockEntity.applyEffect(list, primaryEffect, j, b0, true, pos); // Paper - BeaconEffectEvent
|
||||
+
|
||||
+ if (BeaconBlockEntity.hasSecondaryEffect(beaconLevel, primaryEffect, secondaryEffect)) {
|
||||
+ BeaconBlockEntity.applyEffect(list, secondaryEffect, j, 0, false, pos); // Paper - BeaconEffectEvent
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public static void playSound(Level world, BlockPos pos, SoundEvent sound) {
|
||||
world.playSound((Player) null, pos, sound, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
}
|
||||
@@ -316,7 +440,7 @@
|
||||
if (nbt.contains(key, 8)) {
|
||||
ResourceLocation minecraftkey = ResourceLocation.tryParse(nbt.getString(key));
|
||||
|
||||
- return minecraftkey == null ? null : (Holder) BuiltInRegistries.MOB_EFFECT.get(minecraftkey).map(BeaconBlockEntity::filterEffect).orElse((Object) null);
|
||||
+ return minecraftkey == null ? null : (Holder) BuiltInRegistries.MOB_EFFECT.get(minecraftkey).orElse(null); // CraftBukkit - persist manually set non-default beacon effects (SPIGOT-3598)
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -327,11 +451,13 @@
|
||||
super.loadAdditional(nbt, registries);
|
||||
this.primaryPower = BeaconBlockEntity.loadEffect(nbt, "primary_effect");
|
||||
this.secondaryPower = BeaconBlockEntity.loadEffect(nbt, "secondary_effect");
|
||||
+ this.levels = nbt.getInt("Levels"); // CraftBukkit - SPIGOT-5053, use where available
|
||||
if (nbt.contains("CustomName", 8)) {
|
||||
this.name = parseCustomNameSafe(nbt.getString("CustomName"), registries);
|
||||
}
|
||||
|
||||
this.lockKey = LockCode.fromTag(nbt, registries);
|
||||
+ this.effectRange = nbt.contains(PAPER_RANGE_TAG, 6) ? nbt.getDouble(PAPER_RANGE_TAG) : -1; // Paper - Custom beacon ranges
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -345,6 +471,7 @@
|
||||
}
|
||||
|
||||
this.lockKey.addToTag(nbt, registries);
|
||||
+ nbt.putDouble(PAPER_RANGE_TAG, this.effectRange); // Paper - Custom beacon ranges
|
||||
}
|
||||
|
||||
public void setCustomName(@Nullable Component customName) {
|
||||
@@ -360,7 +487,7 @@
|
||||
@Nullable
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu(int syncId, Inventory playerInventory, Player player) {
|
||||
- return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName()) ? new BeaconMenu(syncId, playerInventory, this.dataAccess, ContainerLevelAccess.create(this.level, this.getBlockPos())) : null;
|
||||
+ return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName(), this) ? new BeaconMenu(syncId, playerInventory, this.dataAccess, ContainerLevelAccess.create(this.level, this.getBlockPos())) : null; // Paper - Add BlockLockCheckEvent
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1,306 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
|
||||
@@ -43,6 +43,10 @@
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.event.entity.EntityRemoveEvent;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class BeehiveBlockEntity extends BlockEntity {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
@@ -56,6 +60,7 @@
|
||||
private List<BeehiveBlockEntity.BeeData> stored = Lists.newArrayList();
|
||||
@Nullable
|
||||
public BlockPos savedFlowerPos;
|
||||
+ public int maxBees = 3; // CraftBukkit - allow setting max amount of bees a hive can hold
|
||||
|
||||
public BeehiveBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(BlockEntityType.BEEHIVE, pos, state);
|
||||
@@ -95,7 +100,7 @@
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
- return this.stored.size() == 3;
|
||||
+ return this.stored.size() == this.maxBees; // CraftBukkit
|
||||
}
|
||||
|
||||
public void emptyAllLivingFromHive(@Nullable Player player, BlockState state, BeehiveBlockEntity.BeeReleaseStatus beeState) {
|
||||
@@ -112,7 +117,7 @@
|
||||
|
||||
if (player.position().distanceToSqr(entity.position()) <= 16.0D) {
|
||||
if (!this.isSedated()) {
|
||||
- entitybee.setTarget(player);
|
||||
+ entitybee.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit
|
||||
} else {
|
||||
entitybee.setStayOutOfHiveCountdown(400);
|
||||
}
|
||||
@@ -124,10 +129,16 @@
|
||||
}
|
||||
|
||||
private List<Entity> releaseAllOccupants(BlockState state, BeehiveBlockEntity.BeeReleaseStatus beeState) {
|
||||
+ // CraftBukkit start - This allows us to bypass the night/rain/emergency check
|
||||
+ return this.releaseBees(state, beeState, false);
|
||||
+ }
|
||||
+
|
||||
+ public List<Entity> releaseBees(BlockState iblockdata, BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus, boolean force) {
|
||||
List<Entity> list = Lists.newArrayList();
|
||||
|
||||
this.stored.removeIf((tileentitybeehive_hivebee) -> {
|
||||
- return BeehiveBlockEntity.releaseOccupant(this.level, this.worldPosition, state, tileentitybeehive_hivebee.toOccupant(), list, beeState, this.savedFlowerPos);
|
||||
+ return BeehiveBlockEntity.releaseOccupant(this.level, this.worldPosition, iblockdata, tileentitybeehive_hivebee.toOccupant(), list, tileentitybeehive_releasestatus, this.savedFlowerPos, force);
|
||||
+ // CraftBukkit end
|
||||
});
|
||||
if (!list.isEmpty()) {
|
||||
super.setChanged();
|
||||
@@ -141,6 +152,11 @@
|
||||
return this.stored.size();
|
||||
}
|
||||
|
||||
+ // Paper start - Add EntityBlockStorage clearEntities
|
||||
+ public void clearBees() {
|
||||
+ this.stored.clear();
|
||||
+ }
|
||||
+ // Paper end - Add EntityBlockStorage clearEntities
|
||||
public static int getHoneyLevel(BlockState state) {
|
||||
return (Integer) state.getValue(BeehiveBlock.HONEY_LEVEL);
|
||||
}
|
||||
@@ -151,7 +167,17 @@
|
||||
}
|
||||
|
||||
public void addOccupant(Bee entity) {
|
||||
- if (this.stored.size() < 3) {
|
||||
+ if (this.stored.size() < this.maxBees) { // CraftBukkit
|
||||
+ // CraftBukkit start
|
||||
+ if (this.level != null) {
|
||||
+ org.bukkit.event.entity.EntityEnterBlockEvent event = new org.bukkit.event.entity.EntityEnterBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(this.level, this.getBlockPos()));
|
||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(event);
|
||||
+ if (event.isCancelled()) {
|
||||
+ entity.setStayOutOfHiveCountdown(400);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
entity.stopRiding();
|
||||
entity.ejectPassengers();
|
||||
entity.dropLeash();
|
||||
@@ -167,7 +193,7 @@
|
||||
this.level.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(entity, this.getBlockState()));
|
||||
}
|
||||
|
||||
- entity.discard();
|
||||
+ entity.discard(EntityRemoveEvent.Cause.ENTER_BLOCK); // CraftBukkit - add Bukkit remove cause
|
||||
super.setChanged();
|
||||
}
|
||||
}
|
||||
@@ -177,32 +203,50 @@
|
||||
}
|
||||
|
||||
private static boolean releaseOccupant(Level world, BlockPos pos, BlockState state, BeehiveBlockEntity.Occupant bee, @Nullable List<Entity> entities, BeehiveBlockEntity.BeeReleaseStatus beeState, @Nullable BlockPos flowerPos) {
|
||||
- if (Bee.isNightOrRaining(world) && beeState != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) {
|
||||
+ // CraftBukkit start - This allows us to bypass the night/rain/emergency check
|
||||
+ return BeehiveBlockEntity.releaseOccupant(world, pos, state, bee, entities, beeState, flowerPos, false);
|
||||
+ }
|
||||
+
|
||||
+ private static boolean releaseOccupant(Level world, BlockPos blockposition, BlockState iblockdata, BeehiveBlockEntity.Occupant tileentitybeehive_c, @Nullable List<Entity> list, BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus, @Nullable BlockPos blockposition1, boolean force) {
|
||||
+ if (!force && Bee.isNightOrRaining(world) && tileentitybeehive_releasestatus != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) {
|
||||
+ // CraftBukkit end
|
||||
return false;
|
||||
} else {
|
||||
- Direction enumdirection = (Direction) state.getValue(BeehiveBlock.FACING);
|
||||
- BlockPos blockposition2 = pos.relative(enumdirection);
|
||||
+ Direction enumdirection = (Direction) iblockdata.getValue(BeehiveBlock.FACING);
|
||||
+ BlockPos blockposition2 = blockposition.relative(enumdirection);
|
||||
boolean flag = !world.getBlockState(blockposition2).getCollisionShape(world, blockposition2).isEmpty();
|
||||
|
||||
- if (flag && beeState != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) {
|
||||
+ if (flag && tileentitybeehive_releasestatus != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) {
|
||||
return false;
|
||||
} else {
|
||||
- Entity entity = bee.createEntity(world, pos);
|
||||
+ Entity entity = tileentitybeehive_c.createEntity(world, blockposition);
|
||||
|
||||
if (entity != null) {
|
||||
+ // CraftBukkit start
|
||||
if (entity instanceof Bee) {
|
||||
+ float f = entity.getBbWidth();
|
||||
+ double d0 = flag ? 0.0D : 0.55D + (double) (f / 2.0F);
|
||||
+ double d1 = (double) blockposition.getX() + 0.5D + d0 * (double) enumdirection.getStepX();
|
||||
+ double d2 = (double) blockposition.getY() + 0.5D - (double) (entity.getBbHeight() / 2.0F);
|
||||
+ double d3 = (double) blockposition.getZ() + 0.5D + d0 * (double) enumdirection.getStepZ();
|
||||
+
|
||||
+ entity.moveTo(d1, d2, d3, entity.getYRot(), entity.getXRot());
|
||||
+ }
|
||||
+ if (!world.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BEEHIVE)) return false; // CraftBukkit - SpawnReason, moved from below
|
||||
+ // CraftBukkit end
|
||||
+ if (entity instanceof Bee) {
|
||||
Bee entitybee = (Bee) entity;
|
||||
|
||||
- if (flowerPos != null && !entitybee.hasSavedFlowerPos() && world.random.nextFloat() < 0.9F) {
|
||||
- entitybee.setSavedFlowerPos(flowerPos);
|
||||
+ if (blockposition1 != null && !entitybee.hasSavedFlowerPos() && world.random.nextFloat() < 0.9F) {
|
||||
+ entitybee.setSavedFlowerPos(blockposition1);
|
||||
}
|
||||
|
||||
- if (beeState == BeehiveBlockEntity.BeeReleaseStatus.HONEY_DELIVERED) {
|
||||
+ if (tileentitybeehive_releasestatus == BeehiveBlockEntity.BeeReleaseStatus.HONEY_DELIVERED) {
|
||||
entitybee.dropOffNectar();
|
||||
- if (state.is(BlockTags.BEEHIVES, (blockbase_blockdata) -> {
|
||||
+ if (iblockdata.is(BlockTags.BEEHIVES, (blockbase_blockdata) -> {
|
||||
return blockbase_blockdata.hasProperty(BeehiveBlock.HONEY_LEVEL);
|
||||
})) {
|
||||
- int i = BeehiveBlockEntity.getHoneyLevel(state);
|
||||
+ int i = BeehiveBlockEntity.getHoneyLevel(iblockdata);
|
||||
|
||||
if (i < 5) {
|
||||
int j = world.random.nextInt(100) == 0 ? 2 : 1;
|
||||
@@ -211,27 +255,35 @@
|
||||
--j;
|
||||
}
|
||||
|
||||
- world.setBlockAndUpdate(pos, (BlockState) state.setValue(BeehiveBlock.HONEY_LEVEL, i + j));
|
||||
+ // Paper start - Fire EntityChangeBlockEvent in more places
|
||||
+ BlockState newBlockState = iblockdata.setValue(BeehiveBlock.HONEY_LEVEL, i + j);
|
||||
+
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entitybee, blockposition, newBlockState)) {
|
||||
+ world.setBlockAndUpdate(blockposition, newBlockState);
|
||||
+ }
|
||||
+ // Paper end - Fire EntityChangeBlockEvent in more places
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- if (entities != null) {
|
||||
- entities.add(entitybee);
|
||||
+ if (list != null) {
|
||||
+ list.add(entitybee);
|
||||
}
|
||||
|
||||
+ /* // CraftBukkit start
|
||||
float f = entity.getBbWidth();
|
||||
double d0 = flag ? 0.0D : 0.55D + (double) (f / 2.0F);
|
||||
- double d1 = (double) pos.getX() + 0.5D + d0 * (double) enumdirection.getStepX();
|
||||
- double d2 = (double) pos.getY() + 0.5D - (double) (entity.getBbHeight() / 2.0F);
|
||||
- double d3 = (double) pos.getZ() + 0.5D + d0 * (double) enumdirection.getStepZ();
|
||||
+ double d1 = (double) blockposition.getX() + 0.5D + d0 * (double) enumdirection.getStepX();
|
||||
+ double d2 = (double) blockposition.getY() + 0.5D - (double) (entity.getBbHeight() / 2.0F);
|
||||
+ double d3 = (double) blockposition.getZ() + 0.5D + d0 * (double) enumdirection.getStepZ();
|
||||
|
||||
entity.moveTo(d1, d2, d3, entity.getYRot(), entity.getXRot());
|
||||
+ */ // CraftBukkit end
|
||||
}
|
||||
|
||||
- world.playSound((Player) null, pos, SoundEvents.BEEHIVE_EXIT, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
- world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(entity, world.getBlockState(pos)));
|
||||
- return world.addFreshEntity(entity);
|
||||
+ world.playSound((Player) null, blockposition, SoundEvents.BEEHIVE_EXIT, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
+ world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(entity, world.getBlockState(blockposition)));
|
||||
+ return true; // return this.world.addFreshEntity(entity); // CraftBukkit - moved up
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -256,6 +308,10 @@
|
||||
if (BeehiveBlockEntity.releaseOccupant(world, pos, state, tileentitybeehive_hivebee.toOccupant(), (List) null, tileentitybeehive_releasestatus, flowerPos)) {
|
||||
flag = true;
|
||||
iterator.remove();
|
||||
+ // CraftBukkit start
|
||||
+ } else {
|
||||
+ tileentitybeehive_hivebee.exitTickCounter = tileentitybeehive_hivebee.occupant.minTicksInHive / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable // Paper - Fix bees aging inside hives; use exitTickCounter to keep actual bee life
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -282,7 +338,7 @@
|
||||
@Override
|
||||
protected void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
super.loadAdditional(nbt, registries);
|
||||
- this.stored.clear();
|
||||
+ this.stored = Lists.newArrayList(); // CraftBukkit - SPIGOT-7790: create new copy (may be modified in physics event triggered by honey change)
|
||||
if (nbt.contains("bees")) {
|
||||
BeehiveBlockEntity.Occupant.LIST_CODEC.parse(NbtOps.INSTANCE, nbt.get("bees")).resultOrPartial((s) -> {
|
||||
BeehiveBlockEntity.LOGGER.error("Failed to parse bees: '{}'", s);
|
||||
@@ -291,7 +347,12 @@
|
||||
});
|
||||
}
|
||||
|
||||
- this.savedFlowerPos = (BlockPos) NbtUtils.readBlockPos(nbt, "flower_pos").orElse((Object) null);
|
||||
+ this.savedFlowerPos = (BlockPos) NbtUtils.readBlockPos(nbt, "flower_pos").orElse(null); // CraftBukkit - decompile error
|
||||
+ // CraftBukkit start
|
||||
+ if (nbt.contains("Bukkit.MaxEntities")) {
|
||||
+ this.maxBees = nbt.getInt("Bukkit.MaxEntities");
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -301,13 +362,14 @@
|
||||
if (this.hasSavedFlowerPos()) {
|
||||
nbt.put("flower_pos", NbtUtils.writeBlockPos(this.savedFlowerPos));
|
||||
}
|
||||
+ nbt.putInt("Bukkit.MaxEntities", this.maxBees); // CraftBukkit
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyImplicitComponents(BlockEntity.DataComponentInput components) {
|
||||
super.applyImplicitComponents(components);
|
||||
- this.stored.clear();
|
||||
+ this.stored = Lists.newArrayList(); // CraftBukkit - SPIGOT-7790: create new copy (may be modified in physics event triggered by honey change)
|
||||
List<BeehiveBlockEntity.Occupant> list = (List) components.getOrDefault(DataComponents.BEES, List.of());
|
||||
|
||||
list.forEach(this::storeBee);
|
||||
@@ -348,7 +410,7 @@
|
||||
CompoundTag nbttagcompound = new CompoundTag();
|
||||
|
||||
entity.save(nbttagcompound);
|
||||
- List list = BeehiveBlockEntity.IGNORED_BEE_TAGS;
|
||||
+ List<String> list = BeehiveBlockEntity.IGNORED_BEE_TAGS; // CraftBukkit - decompile error
|
||||
|
||||
Objects.requireNonNull(nbttagcompound);
|
||||
list.forEach(nbttagcompound::remove);
|
||||
@@ -367,7 +429,7 @@
|
||||
@Nullable
|
||||
public Entity createEntity(Level world, BlockPos pos) {
|
||||
CompoundTag nbttagcompound = this.entityData.copyTag();
|
||||
- List list = BeehiveBlockEntity.IGNORED_BEE_TAGS;
|
||||
+ List<String> list = BeehiveBlockEntity.IGNORED_BEE_TAGS; // CraftBukkit - decompile error
|
||||
|
||||
Objects.requireNonNull(nbttagcompound);
|
||||
list.forEach(nbttagcompound::remove);
|
||||
@@ -391,6 +453,7 @@
|
||||
}
|
||||
|
||||
private static void setBeeReleaseData(int ticksInHive, Bee beeEntity) {
|
||||
+ if (!beeEntity.ageLocked) { // Paper - Honor ageLock
|
||||
int j = beeEntity.getAge();
|
||||
|
||||
if (j < 0) {
|
||||
@@ -400,21 +463,25 @@
|
||||
}
|
||||
|
||||
beeEntity.setInLoveTime(Math.max(0, beeEntity.getInLoveTime() - ticksInHive));
|
||||
+ } // Paper - Honor ageLock
|
||||
}
|
||||
}
|
||||
|
||||
private static class BeeData {
|
||||
|
||||
private final BeehiveBlockEntity.Occupant occupant;
|
||||
+ private int exitTickCounter; // Paper - Fix bees aging inside hives; separate counter for checking if bee should exit to reduce exit attempts
|
||||
private int ticksInHive;
|
||||
|
||||
BeeData(BeehiveBlockEntity.Occupant data) {
|
||||
this.occupant = data;
|
||||
this.ticksInHive = data.ticksInHive();
|
||||
+ this.exitTickCounter = this.ticksInHive; // Paper - Fix bees aging inside hives
|
||||
}
|
||||
|
||||
public boolean tick() {
|
||||
- return this.ticksInHive++ > this.occupant.minTicksInHive;
|
||||
+ this.ticksInHive++; // Paper - Fix bees aging inside hives
|
||||
+ return this.exitTickCounter++ > this.occupant.minTicksInHive; // Paper - Fix bees aging inside hives
|
||||
}
|
||||
|
||||
public BeehiveBlockEntity.Occupant toOccupant() {
|
||||
@@ -1,153 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
@@ -26,8 +26,18 @@
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer;
|
||||
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry;
|
||||
+import org.bukkit.inventory.InventoryHolder;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public abstract class BlockEntity {
|
||||
|
||||
+ // CraftBukkit start - data containers
|
||||
+ private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
|
||||
+ public CraftPersistentDataContainer persistentDataContainer;
|
||||
+ // CraftBukkit end
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final BlockEntityType<?> type;
|
||||
@Nullable
|
||||
@@ -43,6 +53,7 @@
|
||||
this.worldPosition = pos.immutable();
|
||||
this.validateBlockState(state);
|
||||
this.blockState = state;
|
||||
+ this.persistentDataContainer = new CraftPersistentDataContainer(DATA_TYPE_REGISTRY); // Paper - always init
|
||||
}
|
||||
|
||||
private void validateBlockState(BlockState state) {
|
||||
@@ -74,7 +85,16 @@
|
||||
return this.level != null;
|
||||
}
|
||||
|
||||
- protected void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {}
|
||||
+ // CraftBukkit start - read container
|
||||
+ protected void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
+ this.persistentDataContainer.clear(); // Paper - clear instead of init
|
||||
+
|
||||
+ net.minecraft.nbt.Tag persistentDataTag = nbt.get("PublicBukkitValues");
|
||||
+ if (persistentDataTag instanceof CompoundTag) {
|
||||
+ this.persistentDataContainer.putAll((CompoundTag) persistentDataTag);
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
|
||||
public final void loadWithComponents(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
this.loadAdditional(nbt, registries);
|
||||
@@ -114,6 +134,11 @@
|
||||
}).ifPresent((nbtbase) -> {
|
||||
nbttagcompound.merge((CompoundTag) nbtbase);
|
||||
});
|
||||
+ // CraftBukkit start - store container
|
||||
+ if (this.persistentDataContainer != null && !this.persistentDataContainer.isEmpty()) {
|
||||
+ nbttagcompound.put("PublicBukkitValues", this.persistentDataContainer.toTagCompound());
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
return nbttagcompound;
|
||||
}
|
||||
|
||||
@@ -121,6 +146,11 @@
|
||||
CompoundTag nbttagcompound = new CompoundTag();
|
||||
|
||||
this.saveAdditional(nbttagcompound, registries);
|
||||
+ // Paper start - store PDC here as well
|
||||
+ if (this.persistentDataContainer != null && !this.persistentDataContainer.isEmpty()) {
|
||||
+ nbttagcompound.put("PublicBukkitValues", this.persistentDataContainer.toTagCompound());
|
||||
+ }
|
||||
+ // Paper end
|
||||
return nbttagcompound;
|
||||
}
|
||||
|
||||
@@ -234,7 +264,12 @@
|
||||
public void fillCrashReportCategory(CrashReportCategory crashReportSection) {
|
||||
crashReportSection.setDetail("Name", this::getNameForReporting);
|
||||
if (this.level != null) {
|
||||
- CrashReportCategory.populateBlockDetails(crashReportSection, this.level, this.worldPosition, this.getBlockState());
|
||||
+ // Paper start - Prevent block entity and entity crashes
|
||||
+ BlockState block = this.getBlockState();
|
||||
+ if (block != null) {
|
||||
+ CrashReportCategory.populateBlockDetails(crashReportSection, this.level, this.worldPosition, block);
|
||||
+ }
|
||||
+ // Paper end - Prevent block entity and entity crashes
|
||||
CrashReportCategory.populateBlockDetails(crashReportSection, this.level, this.worldPosition, this.level.getBlockState(this.worldPosition));
|
||||
}
|
||||
}
|
||||
@@ -263,13 +298,19 @@
|
||||
}
|
||||
|
||||
public final void applyComponents(DataComponentMap defaultComponents, DataComponentPatch components) {
|
||||
+ // CraftBukkit start
|
||||
+ this.applyComponentsSet(defaultComponents, components);
|
||||
+ }
|
||||
+
|
||||
+ public final Set<DataComponentType<?>> applyComponentsSet(DataComponentMap datacomponentmap, DataComponentPatch datacomponentpatch) {
|
||||
+ // CraftBukkit end
|
||||
final Set<DataComponentType<?>> set = new HashSet();
|
||||
|
||||
set.add(DataComponents.BLOCK_ENTITY_DATA);
|
||||
set.add(DataComponents.BLOCK_STATE);
|
||||
- final PatchedDataComponentMap patcheddatacomponentmap = PatchedDataComponentMap.fromPatch(defaultComponents, components);
|
||||
+ final PatchedDataComponentMap patcheddatacomponentmap = PatchedDataComponentMap.fromPatch(datacomponentmap, datacomponentpatch);
|
||||
|
||||
- this.applyImplicitComponents(new BlockEntity.DataComponentInput(this) {
|
||||
+ this.applyImplicitComponents(new BlockEntity.DataComponentInput() { // CraftBukkit - decompile error
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T get(DataComponentType<T> type) {
|
||||
@@ -284,9 +325,13 @@
|
||||
}
|
||||
});
|
||||
Objects.requireNonNull(set);
|
||||
- DataComponentPatch datacomponentpatch1 = components.forget(set::contains);
|
||||
+ DataComponentPatch datacomponentpatch1 = datacomponentpatch.forget(set::contains);
|
||||
|
||||
this.components = datacomponentpatch1.split().added();
|
||||
+ // CraftBukkit start
|
||||
+ set.remove(DataComponents.BLOCK_ENTITY_DATA); // Remove as never actually added by applyImplicitComponents
|
||||
+ return set;
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
protected void collectImplicitComponents(DataComponentMap.Builder builder) {}
|
||||
@@ -321,6 +366,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ // CraftBukkit start - add method
|
||||
+ public InventoryHolder getOwner() {
|
||||
+ // Paper start
|
||||
+ return getOwner(true);
|
||||
+ }
|
||||
+ public InventoryHolder getOwner(boolean useSnapshot) {
|
||||
+ // Paper end
|
||||
+ if (this.level == null) return null;
|
||||
+ org.bukkit.block.Block block = this.level.getWorld().getBlockAt(this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ());
|
||||
+ // if (block.getType() == org.bukkit.Material.AIR) return null; // Paper - actually get the tile entity if it still exists
|
||||
+ org.bukkit.block.BlockState state = block.getState(useSnapshot); // Paper
|
||||
+ if (state instanceof InventoryHolder) return (InventoryHolder) state;
|
||||
+ return null;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ // Paper start - Sanitize sent data
|
||||
+ public CompoundTag sanitizeSentNbt(CompoundTag tag) {
|
||||
+ tag.remove("PublicBukkitValues");
|
||||
+
|
||||
+ return tag;
|
||||
+ }
|
||||
+ // Paper end - Sanitize sent data
|
||||
+
|
||||
private static class ComponentHelper {
|
||||
|
||||
public static final Codec<DataComponentMap> COMPONENTS_CODEC = DataComponentMap.CODEC.optionalFieldOf("components", DataComponentMap.EMPTY).codec();
|
||||
@@ -1,20 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/BlockEntityType.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BlockEntityType.java
|
||||
@@ -66,7 +66,7 @@
|
||||
public static final BlockEntityType<CrafterBlockEntity> CRAFTER = BlockEntityType.register("crafter", CrafterBlockEntity::new, Blocks.CRAFTER);
|
||||
public static final BlockEntityType<TrialSpawnerBlockEntity> TRIAL_SPAWNER = BlockEntityType.register("trial_spawner", TrialSpawnerBlockEntity::new, Blocks.TRIAL_SPAWNER);
|
||||
public static final BlockEntityType<VaultBlockEntity> VAULT = BlockEntityType.register("vault", VaultBlockEntity::new, Blocks.VAULT);
|
||||
- private static final Set<BlockEntityType<?>> OP_ONLY_CUSTOM_DATA = Set.of(BlockEntityType.COMMAND_BLOCK, BlockEntityType.LECTERN, BlockEntityType.SIGN, BlockEntityType.HANGING_SIGN, BlockEntityType.MOB_SPAWNER, BlockEntityType.TRIAL_SPAWNER);
|
||||
+ private static final Set<BlockEntityType<?>> OP_ONLY_CUSTOM_DATA = Set.of(BlockEntityType.COMMAND_BLOCK, BlockEntityType.LECTERN, BlockEntityType.SIGN, BlockEntityType.HANGING_SIGN, BlockEntityType.MOB_SPAWNER, BlockEntityType.TRIAL_SPAWNER); // CraftBukkit // Paper - Allow chests to be placed with NBT data
|
||||
private final BlockEntityType.BlockEntitySupplier<? extends T> factory;
|
||||
public final Set<Block> validBlocks;
|
||||
private final Holder.Reference<BlockEntityType<?>> builtInRegistryHolder;
|
||||
@@ -110,7 +110,7 @@
|
||||
public T getBlockEntity(BlockGetter world, BlockPos pos) {
|
||||
BlockEntity tileentity = world.getBlockEntity(pos);
|
||||
|
||||
- return tileentity != null && tileentity.getType() == this ? tileentity : null;
|
||||
+ return tileentity != null && tileentity.getType() == this ? (T) tileentity : null; // CraftBukkit - decompile error
|
||||
}
|
||||
|
||||
public boolean onlyOpCanSetNbt() {
|
||||
@@ -1,232 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
|
||||
@@ -8,7 +8,6 @@
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
-import net.minecraft.tags.ItemTags;
|
||||
import net.minecraft.world.ContainerHelper;
|
||||
import net.minecraft.world.Containers;
|
||||
import net.minecraft.world.WorldlyContainer;
|
||||
@@ -23,6 +22,20 @@
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.BrewingStandBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
+// CraftBukkit start
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.List;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.tags.ItemTags;
|
||||
+import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.entity.HumanEntity;
|
||||
+import org.bukkit.event.block.BrewingStartEvent;
|
||||
+import org.bukkit.event.inventory.BrewEvent;
|
||||
+import org.bukkit.event.inventory.BrewingStandFuelEvent;
|
||||
+import org.bukkit.inventory.InventoryHolder;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements WorldlyContainer {
|
||||
|
||||
@@ -37,11 +50,42 @@
|
||||
public static final int NUM_DATA_VALUES = 2;
|
||||
private NonNullList<ItemStack> items;
|
||||
public int brewTime;
|
||||
+ public int recipeBrewTime = 400; // Paper - Add recipeBrewTime
|
||||
private boolean[] lastPotionCount;
|
||||
private Item ingredient;
|
||||
public int fuel;
|
||||
protected final ContainerData dataAccess;
|
||||
+ // CraftBukkit start - add fields and methods
|
||||
+ // private int lastTick = MinecraftServer.currentTick; // Paper - remove anti tick skipping measures / wall time
|
||||
+ public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
||||
+ private int maxStack = MAX_STACK;
|
||||
|
||||
+ public void onOpen(CraftHumanEntity who) {
|
||||
+ this.transaction.add(who);
|
||||
+ }
|
||||
+
|
||||
+ public void onClose(CraftHumanEntity who) {
|
||||
+ this.transaction.remove(who);
|
||||
+ }
|
||||
+
|
||||
+ public List<HumanEntity> getViewers() {
|
||||
+ return this.transaction;
|
||||
+ }
|
||||
+
|
||||
+ public List<ItemStack> getContents() {
|
||||
+ return this.items;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getMaxStackSize() {
|
||||
+ return this.maxStack;
|
||||
+ }
|
||||
+
|
||||
+ public void setMaxStackSize(int size) {
|
||||
+ this.maxStack = size;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public BrewingStandBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(BlockEntityType.BREWING_STAND, pos, state);
|
||||
this.items = NonNullList.withSize(5, ItemStack.EMPTY);
|
||||
@@ -57,6 +101,11 @@
|
||||
case 1:
|
||||
j = BrewingStandBlockEntity.this.fuel;
|
||||
break;
|
||||
+ // Paper start - Add recipeBrewTime
|
||||
+ case 2:
|
||||
+ j = BrewingStandBlockEntity.this.recipeBrewTime;
|
||||
+ break;
|
||||
+ // Paper end - Add recipeBrewTime
|
||||
default:
|
||||
j = 0;
|
||||
}
|
||||
@@ -72,13 +121,18 @@
|
||||
break;
|
||||
case 1:
|
||||
BrewingStandBlockEntity.this.fuel = value;
|
||||
+ // Paper start - Add recipeBrewTime
|
||||
+ case 2:
|
||||
+ BrewingStandBlockEntity.this.recipeBrewTime = value;
|
||||
+ break;
|
||||
+ // Paper end - Add recipeBrewTime
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
- return 2;
|
||||
+ return 3; // Paper - Add recipeBrewTime
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -107,8 +161,19 @@
|
||||
ItemStack itemstack = (ItemStack) blockEntity.items.get(4);
|
||||
|
||||
if (blockEntity.fuel <= 0 && itemstack.is(ItemTags.BREWING_FUEL)) {
|
||||
- blockEntity.fuel = 20;
|
||||
- itemstack.shrink(1);
|
||||
+ // CraftBukkit start
|
||||
+ BrewingStandFuelEvent event = new BrewingStandFuelEvent(CraftBlock.at(world, pos), CraftItemStack.asCraftMirror(itemstack), 20);
|
||||
+ world.getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ if (event.isCancelled()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ blockEntity.fuel = event.getFuelPower();
|
||||
+ if (blockEntity.fuel > 0 && event.isConsuming()) {
|
||||
+ itemstack.shrink(1);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
setChanged(world, pos, state);
|
||||
}
|
||||
|
||||
@@ -116,12 +181,15 @@
|
||||
boolean flag1 = blockEntity.brewTime > 0;
|
||||
ItemStack itemstack1 = (ItemStack) blockEntity.items.get(3);
|
||||
|
||||
+ // Paper - remove anti tick skipping measures / wall time
|
||||
+
|
||||
if (flag1) {
|
||||
- --blockEntity.brewTime;
|
||||
- boolean flag2 = blockEntity.brewTime == 0;
|
||||
+ --blockEntity.brewTime; // Paper - remove anti tick skipping measures / wall time - revert to vanilla
|
||||
+ boolean flag2 = blockEntity.brewTime <= 0; // == -> <=
|
||||
+ // CraftBukkit end
|
||||
|
||||
if (flag2 && flag) {
|
||||
- BrewingStandBlockEntity.doBrew(world, pos, blockEntity.items);
|
||||
+ BrewingStandBlockEntity.doBrew(world, pos, blockEntity.items, blockEntity); // CraftBukkit
|
||||
} else if (!flag || !itemstack1.is(blockEntity.ingredient)) {
|
||||
blockEntity.brewTime = 0;
|
||||
}
|
||||
@@ -129,7 +197,12 @@
|
||||
setChanged(world, pos, state);
|
||||
} else if (flag && blockEntity.fuel > 0) {
|
||||
--blockEntity.fuel;
|
||||
- blockEntity.brewTime = 400;
|
||||
+ // CraftBukkit start
|
||||
+ BrewingStartEvent event = new BrewingStartEvent(CraftBlock.at(world, pos), CraftItemStack.asCraftMirror(itemstack1), 400);
|
||||
+ world.getCraftServer().getPluginManager().callEvent(event);
|
||||
+ blockEntity.recipeBrewTime = event.getRecipeBrewTime(); // Paper - use recipe brew time from event
|
||||
+ blockEntity.brewTime = event.getBrewingTime(); // 400 -> event.getTotalBrewTime() // Paper - use brewing time from event
|
||||
+ // CraftBukkit end
|
||||
blockEntity.ingredient = itemstack1.getItem();
|
||||
setChanged(world, pos, state);
|
||||
}
|
||||
@@ -185,14 +258,36 @@
|
||||
}
|
||||
}
|
||||
|
||||
- private static void doBrew(Level world, BlockPos pos, NonNullList<ItemStack> slots) {
|
||||
- ItemStack itemstack = (ItemStack) slots.get(3);
|
||||
+ private static void doBrew(Level world, BlockPos blockposition, NonNullList<ItemStack> nonnulllist, BrewingStandBlockEntity tileentitybrewingstand) { // CraftBukkit
|
||||
+ ItemStack itemstack = (ItemStack) nonnulllist.get(3);
|
||||
PotionBrewing potionbrewer = world.potionBrewing();
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ InventoryHolder owner = tileentitybrewingstand.getOwner();
|
||||
+ List<org.bukkit.inventory.ItemStack> brewResults = new ArrayList<>(3);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
- slots.set(i, potionbrewer.mix(itemstack, (ItemStack) slots.get(i)));
|
||||
+ brewResults.add(i, CraftItemStack.asCraftMirror(potionbrewer.mix(itemstack, (ItemStack) nonnulllist.get(i))));
|
||||
}
|
||||
|
||||
+ if (owner != null) {
|
||||
+ BrewEvent event = new BrewEvent(CraftBlock.at(world, blockposition), (org.bukkit.inventory.BrewerInventory) owner.getInventory(), brewResults, tileentitybrewingstand.fuel);
|
||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(event);
|
||||
+ if (event.isCancelled()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ for (int i = 0; i < 3; ++i) {
|
||||
+ // CraftBukkit start - validate index in case it is cleared by plugins
|
||||
+ if (i < brewResults.size()) {
|
||||
+ nonnulllist.set(i, CraftItemStack.asNMSCopy(brewResults.get(i)));
|
||||
+ } else {
|
||||
+ nonnulllist.set(i, ItemStack.EMPTY);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ }
|
||||
+
|
||||
itemstack.shrink(1);
|
||||
ItemStack itemstack1 = itemstack.getItem().getCraftingRemainder();
|
||||
|
||||
@@ -200,12 +295,12 @@
|
||||
if (itemstack.isEmpty()) {
|
||||
itemstack = itemstack1;
|
||||
} else {
|
||||
- Containers.dropItemStack(world, (double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), itemstack1);
|
||||
+ Containers.dropItemStack(world, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), itemstack1);
|
||||
}
|
||||
}
|
||||
|
||||
- slots.set(3, itemstack);
|
||||
- world.levelEvent(1035, pos, 0);
|
||||
+ nonnulllist.set(3, itemstack);
|
||||
+ world.levelEvent(1035, blockposition, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -231,12 +326,12 @@
|
||||
|
||||
@Override
|
||||
public boolean canPlaceItem(int slot, ItemStack stack) {
|
||||
+ PotionBrewing potionbrewer = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY; // Paper - move up
|
||||
if (slot == 3) {
|
||||
- PotionBrewing potionbrewer = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY;
|
||||
|
||||
return potionbrewer.isIngredient(stack);
|
||||
} else {
|
||||
- return slot == 4 ? stack.is(ItemTags.BREWING_FUEL) : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE)) && this.getItem(slot).isEmpty();
|
||||
+ return slot == 4 ? stack.is(ItemTags.BREWING_FUEL) : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || potionbrewer.isCustomInput(stack)) && this.getItem(slot).isEmpty(); // Paper - Custom Potion Mixes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/BrushableBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BrushableBlockEntity.java
|
||||
@@ -31,6 +31,12 @@
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import java.util.Arrays;
|
||||
+import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class BrushableBlockEntity extends BlockEntity {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
@@ -151,7 +157,10 @@
|
||||
ItemEntity entityitem = new ItemEntity(world, d3, d4, d5, this.item.split(world.random.nextInt(21) + 10));
|
||||
|
||||
entityitem.setDeltaMovement(Vec3.ZERO);
|
||||
- world.addFreshEntity(entityitem);
|
||||
+ // CraftBukkit start
|
||||
+ org.bukkit.block.Block bblock = CraftBlock.at(this.level, this.worldPosition);
|
||||
+ CraftEventFactory.handleBlockDropItemEvent(bblock, bblock.getState(), (ServerPlayer) player, Arrays.asList(entityitem));
|
||||
+ // CraftBukkit end
|
||||
this.item = ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@@ -185,7 +194,7 @@
|
||||
|
||||
private boolean tryLoadLootTable(CompoundTag nbt) {
|
||||
if (nbt.contains("LootTable", 8)) {
|
||||
- this.lootTable = ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable")));
|
||||
+ this.lootTable = net.minecraft.Optionull.map(ResourceLocation.tryParse(nbt.getString("LootTable")), rl -> ResourceKey.create(Registries.LOOT_TABLE, rl)); // Paper - Validate ResourceLocation
|
||||
this.lootTableSeed = nbt.getLong("LootTableSeed");
|
||||
return true;
|
||||
} else {
|
||||
@@ -1,23 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java
|
||||
@@ -20,6 +20,12 @@
|
||||
public VibrationSystem.User createVibrationUser() {
|
||||
return new CalibratedSculkSensorBlockEntity.VibrationUser(this.getBlockPos());
|
||||
}
|
||||
+ // Paper start - Configurable sculk sensor listener range
|
||||
+ @Override
|
||||
+ protected void saveRangeOverride(final net.minecraft.nbt.CompoundTag nbt) {
|
||||
+ if (this.rangeOverride != null && this.rangeOverride != 16) nbt.putInt(PAPER_LISTENER_RANGE_NBT_KEY, this.rangeOverride); // only save if it's different from the default
|
||||
+ }
|
||||
+ // Paper end - Configurable sculk sensor listener range
|
||||
|
||||
protected class VibrationUser extends SculkSensorBlockEntity.VibrationUser {
|
||||
public VibrationUser(final BlockPos pos) {
|
||||
@@ -28,6 +34,7 @@
|
||||
|
||||
@Override
|
||||
public int getListenerRadius() {
|
||||
+ if (CalibratedSculkSensorBlockEntity.this.rangeOverride != null) return CalibratedSculkSensorBlockEntity.this.rangeOverride; // Paper - Configurable sculk sensor listener range
|
||||
return 16;
|
||||
}
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
|
||||
@@ -31,6 +31,14 @@
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.event.block.BlockCookEvent;
|
||||
+import org.bukkit.event.block.CampfireStartEvent;
|
||||
+import org.bukkit.inventory.CampfireRecipe;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class CampfireBlockEntity extends BlockEntity implements Clearable {
|
||||
|
||||
private static final int BURN_COOL_SPEED = 2;
|
||||
@@ -38,12 +46,14 @@
|
||||
private final NonNullList<ItemStack> items;
|
||||
public final int[] cookingProgress;
|
||||
public final int[] cookingTime;
|
||||
+ public final boolean[] stopCooking; // Paper - Add more Campfire API
|
||||
|
||||
public CampfireBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(BlockEntityType.CAMPFIRE, pos, state);
|
||||
this.items = NonNullList.withSize(4, ItemStack.EMPTY);
|
||||
this.cookingProgress = new int[4];
|
||||
this.cookingTime = new int[4];
|
||||
+ this.stopCooking = new boolean[4]; // Paper - Add more Campfire API
|
||||
}
|
||||
|
||||
public static void cookTick(ServerLevel world, BlockPos pos, BlockState state, CampfireBlockEntity blockEntity, RecipeManager.CachedCheck<SingleRecipeInput, CampfireCookingRecipe> recipeMatchGetter) {
|
||||
@@ -54,16 +64,42 @@
|
||||
|
||||
if (!itemstack.isEmpty()) {
|
||||
flag = true;
|
||||
+ if (!blockEntity.stopCooking[i]) { // Paper - Add more Campfire API
|
||||
int j = blockEntity.cookingProgress[i]++;
|
||||
+ } // Paper - Add more Campfire API
|
||||
|
||||
if (blockEntity.cookingProgress[i] >= blockEntity.cookingTime[i]) {
|
||||
SingleRecipeInput singlerecipeinput = new SingleRecipeInput(itemstack);
|
||||
- ItemStack itemstack1 = (ItemStack) recipeMatchGetter.getRecipeFor(singlerecipeinput, world).map((recipeholder) -> {
|
||||
+ // Paper start - add recipe to cook events
|
||||
+ final Optional<RecipeHolder<CampfireCookingRecipe>> recipeHolderOptional = recipeMatchGetter.getRecipeFor(singlerecipeinput, world);
|
||||
+ ItemStack itemstack1 = (ItemStack) recipeHolderOptional.map((recipeholder) -> {
|
||||
+ // Paper end - add recipe to cook events
|
||||
return ((CampfireCookingRecipe) recipeholder.value()).assemble(singlerecipeinput, world.registryAccess());
|
||||
}).orElse(itemstack);
|
||||
|
||||
if (itemstack1.isItemEnabled(world.enabledFeatures())) {
|
||||
- Containers.dropItemStack(world, (double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), itemstack1);
|
||||
+ // CraftBukkit start - fire BlockCookEvent
|
||||
+ CraftItemStack source = CraftItemStack.asCraftMirror(itemstack);
|
||||
+ org.bukkit.inventory.ItemStack result = CraftItemStack.asBukkitCopy(itemstack1);
|
||||
+
|
||||
+ BlockCookEvent blockCookEvent = new BlockCookEvent(CraftBlock.at(world, pos), source, result, (org.bukkit.inventory.CookingRecipe<?>) recipeHolderOptional.map(RecipeHolder::toBukkitRecipe).orElse(null)); // Paper - Add recipe to cook events
|
||||
+ world.getCraftServer().getPluginManager().callEvent(blockCookEvent);
|
||||
+
|
||||
+ if (blockCookEvent.isCancelled()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ result = blockCookEvent.getResult();
|
||||
+ itemstack1 = CraftItemStack.asNMSCopy(result);
|
||||
+ // CraftBukkit end
|
||||
+ // Paper start - Fix item locations dropped from campfires
|
||||
+ double deviation = 0.05F * RandomSource.GAUSSIAN_SPREAD_FACTOR;
|
||||
+ while (!itemstack1.isEmpty()) {
|
||||
+ net.minecraft.world.entity.item.ItemEntity droppedItem = new net.minecraft.world.entity.item.ItemEntity(world, pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, itemstack1.split(world.random.nextInt(21) + 10));
|
||||
+ droppedItem.setDeltaMovement(world.random.triangle(0.0D, deviation), world.random.triangle(0.2D, deviation), world.random.triangle(0.0D, deviation));
|
||||
+ world.addFreshEntity(droppedItem);
|
||||
+ }
|
||||
+ // Paper end - Fix item locations dropped from campfires
|
||||
blockEntity.items.set(i, ItemStack.EMPTY);
|
||||
world.sendBlockUpdated(pos, state, state, 3);
|
||||
world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(state));
|
||||
@@ -143,6 +179,16 @@
|
||||
System.arraycopy(aint, 0, this.cookingTime, 0, Math.min(this.cookingTime.length, aint.length));
|
||||
}
|
||||
|
||||
+ // Paper start - Add more Campfire API
|
||||
+ if (nbt.contains("Paper.StopCooking", org.bukkit.craftbukkit.util.CraftMagicNumbers.NBT.TAG_BYTE_ARRAY)) {
|
||||
+ byte[] abyte = nbt.getByteArray("Paper.StopCooking");
|
||||
+ boolean[] cookingState = new boolean[4];
|
||||
+ for (int index = 0; index < abyte.length; index++) {
|
||||
+ cookingState[index] = abyte[index] == 1;
|
||||
+ }
|
||||
+ System.arraycopy(cookingState, 0, this.stopCooking, 0, Math.min(this.stopCooking.length, abyte.length));
|
||||
+ }
|
||||
+ // Paper end - Add more Campfire API
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -151,6 +197,13 @@
|
||||
ContainerHelper.saveAllItems(nbt, this.items, true, registries);
|
||||
nbt.putIntArray("CookingTimes", this.cookingProgress);
|
||||
nbt.putIntArray("CookingTotalTimes", this.cookingTime);
|
||||
+ // Paper start - Add more Campfire API
|
||||
+ byte[] cookingState = new byte[4];
|
||||
+ for (int index = 0; index < cookingState.length; index++) {
|
||||
+ cookingState[index] = (byte) (this.stopCooking[index] ? 1 : 0);
|
||||
+ }
|
||||
+ nbt.putByteArray("Paper.StopCooking", cookingState);
|
||||
+ // Paper end - Add more Campfire API
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,7 +230,11 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
- this.cookingTime[i] = ((CampfireCookingRecipe) ((RecipeHolder) optional.get()).value()).cookingTime();
|
||||
+ // CraftBukkit start
|
||||
+ CampfireStartEvent event = new CampfireStartEvent(CraftBlock.at(this.level,this.worldPosition), CraftItemStack.asCraftMirror(stack), (CampfireRecipe) optional.get().toBukkitRecipe());
|
||||
+ this.level.getCraftServer().getPluginManager().callEvent(event);
|
||||
+ this.cookingTime[i] = event.getTotalCookTime(); // i -> event.getTotalCookTime()
|
||||
+ // CraftBukkit end
|
||||
this.cookingProgress[i] = 0;
|
||||
this.items.set(i, stack.consumeAndReturn(1, entity));
|
||||
world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, this.getBlockPos(), GameEvent.Context.of(entity, this.getBlockState()));
|
||||
@@ -1,108 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/ConduitBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/ConduitBlockEntity.java
|
||||
@@ -10,6 +10,7 @@
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
@@ -187,11 +188,23 @@
|
||||
}
|
||||
|
||||
private static void applyEffects(Level world, BlockPos pos, List<BlockPos> activatingBlocks) {
|
||||
- int i = activatingBlocks.size();
|
||||
+ // CraftBukkit start
|
||||
+ ConduitBlockEntity.applyEffects(world, pos, ConduitBlockEntity.getRange(activatingBlocks));
|
||||
+ }
|
||||
+
|
||||
+ public static int getRange(List<BlockPos> list) {
|
||||
+ // CraftBukkit end
|
||||
+ int i = list.size();
|
||||
int j = i / 7 * 16;
|
||||
- int k = pos.getX();
|
||||
- int l = pos.getY();
|
||||
- int i1 = pos.getZ();
|
||||
+ // CraftBukkit start
|
||||
+ return j;
|
||||
+ }
|
||||
+
|
||||
+ private static void applyEffects(Level world, BlockPos blockposition, int j) { // j = effect range in blocks
|
||||
+ // CraftBukkit end
|
||||
+ int k = blockposition.getX();
|
||||
+ int l = blockposition.getY();
|
||||
+ int i1 = blockposition.getZ();
|
||||
AABB axisalignedbb = (new AABB((double) k, (double) l, (double) i1, (double) (k + 1), (double) (l + 1), (double) (i1 + 1))).inflate((double) j).expandTowards(0.0D, (double) world.getHeight(), 0.0D);
|
||||
List<Player> list1 = world.getEntitiesOfClass(Player.class, axisalignedbb);
|
||||
|
||||
@@ -201,8 +214,8 @@
|
||||
while (iterator.hasNext()) {
|
||||
Player entityhuman = (Player) iterator.next();
|
||||
|
||||
- if (pos.closerThan(entityhuman.blockPosition(), (double) j) && entityhuman.isInWaterOrRain()) {
|
||||
- entityhuman.addEffect(new MobEffectInstance(MobEffects.CONDUIT_POWER, 260, 0, true, true));
|
||||
+ if (blockposition.closerThan(entityhuman.blockPosition(), (double) j) && entityhuman.isInWaterOrRain()) {
|
||||
+ entityhuman.addEffect(new MobEffectInstance(MobEffects.CONDUIT_POWER, 260, 0, true, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONDUIT); // CraftBukkit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,33 +223,42 @@
|
||||
}
|
||||
|
||||
private static void updateDestroyTarget(Level world, BlockPos pos, BlockState state, List<BlockPos> activatingBlocks, ConduitBlockEntity blockEntity) {
|
||||
- LivingEntity entityliving = blockEntity.destroyTarget;
|
||||
- int i = activatingBlocks.size();
|
||||
+ // CraftBukkit start - add "damageTarget" boolean
|
||||
+ ConduitBlockEntity.updateDestroyTarget(world, pos, state, activatingBlocks, blockEntity, true);
|
||||
+ }
|
||||
|
||||
+ public static void updateDestroyTarget(Level world, BlockPos blockposition, BlockState iblockdata, List<BlockPos> list, ConduitBlockEntity tileentityconduit, boolean damageTarget) {
|
||||
+ // CraftBukkit end
|
||||
+ LivingEntity entityliving = tileentityconduit.destroyTarget;
|
||||
+ int i = list.size();
|
||||
+
|
||||
if (i < 42) {
|
||||
- blockEntity.destroyTarget = null;
|
||||
- } else if (blockEntity.destroyTarget == null && blockEntity.destroyTargetUUID != null) {
|
||||
- blockEntity.destroyTarget = ConduitBlockEntity.findDestroyTarget(world, pos, blockEntity.destroyTargetUUID);
|
||||
- blockEntity.destroyTargetUUID = null;
|
||||
- } else if (blockEntity.destroyTarget == null) {
|
||||
- List<LivingEntity> list1 = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(pos), (entityliving1) -> {
|
||||
+ tileentityconduit.destroyTarget = null;
|
||||
+ } else if (tileentityconduit.destroyTarget == null && tileentityconduit.destroyTargetUUID != null) {
|
||||
+ tileentityconduit.destroyTarget = ConduitBlockEntity.findDestroyTarget(world, blockposition, tileentityconduit.destroyTargetUUID);
|
||||
+ tileentityconduit.destroyTargetUUID = null;
|
||||
+ } else if (tileentityconduit.destroyTarget == null) {
|
||||
+ List<LivingEntity> list1 = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(blockposition), (entityliving1) -> {
|
||||
return entityliving1 instanceof Enemy && entityliving1.isInWaterOrRain();
|
||||
});
|
||||
|
||||
if (!list1.isEmpty()) {
|
||||
- blockEntity.destroyTarget = (LivingEntity) list1.get(world.random.nextInt(list1.size()));
|
||||
+ tileentityconduit.destroyTarget = (LivingEntity) list1.get(world.random.nextInt(list1.size()));
|
||||
}
|
||||
- } else if (!blockEntity.destroyTarget.isAlive() || !pos.closerThan(blockEntity.destroyTarget.blockPosition(), 8.0D)) {
|
||||
- blockEntity.destroyTarget = null;
|
||||
+ } else if (!tileentityconduit.destroyTarget.isAlive() || !blockposition.closerThan(tileentityconduit.destroyTarget.blockPosition(), 8.0D)) {
|
||||
+ tileentityconduit.destroyTarget = null;
|
||||
}
|
||||
|
||||
- if (blockEntity.destroyTarget != null) {
|
||||
- world.playSound((Player) null, blockEntity.destroyTarget.getX(), blockEntity.destroyTarget.getY(), blockEntity.destroyTarget.getZ(), SoundEvents.CONDUIT_ATTACK_TARGET, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
- blockEntity.destroyTarget.hurt(world.damageSources().magic(), 4.0F);
|
||||
+ // CraftBukkit start
|
||||
+ if (damageTarget && tileentityconduit.destroyTarget != null) {
|
||||
+ if (tileentityconduit.destroyTarget.hurtServer((ServerLevel) world, world.damageSources().magic().directBlock(world, blockposition), 4.0F)) {
|
||||
+ world.playSound(null, tileentityconduit.destroyTarget.getX(), tileentityconduit.destroyTarget.getY(), tileentityconduit.destroyTarget.getZ(), SoundEvents.CONDUIT_ATTACK_TARGET, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
- if (entityliving != blockEntity.destroyTarget) {
|
||||
- world.sendBlockUpdated(pos, state, state, 2);
|
||||
+ if (entityliving != tileentityconduit.destroyTarget) {
|
||||
+ world.sendBlockUpdated(blockposition, iblockdata, iblockdata, 2);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java
|
||||
+++ b/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java
|
||||
@@ -17,6 +17,7 @@
|
||||
private static final int CHECK_TICK_DELAY = 5;
|
||||
private int openCount;
|
||||
private double maxInteractionRange;
|
||||
+ public boolean opened; // CraftBukkit
|
||||
|
||||
public ContainerOpenersCounter() {}
|
||||
|
||||
@@ -26,11 +27,36 @@
|
||||
|
||||
protected abstract void openerCountChanged(Level world, BlockPos pos, BlockState state, int oldViewerCount, int newViewerCount);
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ public void onAPIOpen(Level world, BlockPos blockposition, BlockState iblockdata) {
|
||||
+ this.onOpen(world, blockposition, iblockdata);
|
||||
+ }
|
||||
+
|
||||
+ public void onAPIClose(Level world, BlockPos blockposition, BlockState iblockdata) {
|
||||
+ this.onClose(world, blockposition, iblockdata);
|
||||
+ }
|
||||
+
|
||||
+ public void openerAPICountChanged(Level world, BlockPos blockposition, BlockState iblockdata, int i, int j) {
|
||||
+ this.openerCountChanged(world, blockposition, iblockdata, i, j);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
protected abstract boolean isOwnContainer(Player player);
|
||||
|
||||
public void incrementOpeners(Player player, Level world, BlockPos pos, BlockState state) {
|
||||
+ int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added
|
||||
int i = this.openCount++;
|
||||
|
||||
+ // CraftBukkit start - Call redstone event
|
||||
+ if (world.getBlockState(pos).is(net.minecraft.world.level.block.Blocks.TRAPPED_CHEST)) {
|
||||
+ int newPower = Math.max(0, Math.min(15, this.openCount));
|
||||
+
|
||||
+ if (oldPower != newPower) {
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(world, pos, oldPower, newPower);
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
if (i == 0) {
|
||||
this.onOpen(world, pos, state);
|
||||
world.gameEvent((Entity) player, (Holder) GameEvent.CONTAINER_OPEN, pos);
|
||||
@@ -42,8 +68,20 @@
|
||||
}
|
||||
|
||||
public void decrementOpeners(Player player, Level world, BlockPos pos, BlockState state) {
|
||||
+ int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added
|
||||
+ if (this.openCount == 0) return; // Paper - Prevent ContainerOpenersCounter openCount from going negative
|
||||
int i = this.openCount--;
|
||||
|
||||
+ // CraftBukkit start - Call redstone event
|
||||
+ if (world.getBlockState(pos).is(net.minecraft.world.level.block.Blocks.TRAPPED_CHEST)) {
|
||||
+ int newPower = Math.max(0, Math.min(15, this.openCount));
|
||||
+
|
||||
+ if (oldPower != newPower) {
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(world, pos, oldPower, newPower);
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
if (this.openCount == 0) {
|
||||
this.onClose(world, pos, state);
|
||||
world.gameEvent((Entity) player, (Holder) GameEvent.CONTAINER_CLOSE, pos);
|
||||
@@ -72,6 +110,7 @@
|
||||
}
|
||||
|
||||
int i = list.size();
|
||||
+ if (this.opened) i++; // CraftBukkit - add dummy count from API
|
||||
int j = this.openCount;
|
||||
|
||||
if (j != i) {
|
||||
@@ -1,68 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/CrafterBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/CrafterBlockEntity.java
|
||||
@@ -22,6 +22,11 @@
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.CrafterBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.Location;
|
||||
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
+import org.bukkit.entity.HumanEntity;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class CrafterBlockEntity extends RandomizableContainerBlockEntity implements CraftingContainer {
|
||||
|
||||
@@ -35,12 +40,52 @@
|
||||
private NonNullList<ItemStack> items;
|
||||
public int craftingTicksRemaining;
|
||||
protected final ContainerData containerData;
|
||||
+ // CraftBukkit start - add fields and methods
|
||||
+ public List<HumanEntity> transaction = new java.util.ArrayList<>();
|
||||
+ private int maxStack = MAX_STACK;
|
||||
|
||||
+ @Override
|
||||
+ public List<ItemStack> getContents() {
|
||||
+ return this.items;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onOpen(CraftHumanEntity who) {
|
||||
+ this.transaction.add(who);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onClose(CraftHumanEntity who) {
|
||||
+ this.transaction.remove(who);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<HumanEntity> getViewers() {
|
||||
+ return this.transaction;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getMaxStackSize() {
|
||||
+ return this.maxStack;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setMaxStackSize(int size) {
|
||||
+ this.maxStack = size;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Location getLocation() {
|
||||
+ if (this.level == null) return null;
|
||||
+ return new org.bukkit.Location(this.level.getWorld(), this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ());
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public CrafterBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(BlockEntityType.CRAFTER, pos, state);
|
||||
this.items = NonNullList.withSize(9, ItemStack.EMPTY);
|
||||
this.craftingTicksRemaining = 0;
|
||||
- this.containerData = new ContainerData(this) {
|
||||
+ this.containerData = new ContainerData() { // CraftBukkit - decompile error
|
||||
private final int[] slotStates = new int[9];
|
||||
private int triggered = 0;
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/DecoratedPotBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/DecoratedPotBlockEntity.java
|
||||
@@ -20,8 +20,59 @@
|
||||
import net.minecraft.world.level.storage.loot.LootTable;
|
||||
import net.minecraft.world.ticks.ContainerSingleItem;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Arrays;
|
||||
+import java.util.List;
|
||||
+import org.bukkit.Location;
|
||||
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
+import org.bukkit.craftbukkit.util.CraftLocation;
|
||||
+import org.bukkit.entity.HumanEntity;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class DecoratedPotBlockEntity extends BlockEntity implements RandomizableContainer, ContainerSingleItem.BlockContainerSingleItem {
|
||||
|
||||
+ // CraftBukkit start - add fields and methods
|
||||
+ public List<HumanEntity> transaction = new ArrayList<>();
|
||||
+ private int maxStack = MAX_STACK;
|
||||
+
|
||||
+ @Override
|
||||
+ public List<ItemStack> getContents() {
|
||||
+ return Arrays.asList(this.item);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onOpen(CraftHumanEntity who) {
|
||||
+ this.transaction.add(who);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onClose(CraftHumanEntity who) {
|
||||
+ this.transaction.remove(who);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<HumanEntity> getViewers() {
|
||||
+ return this.transaction;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getMaxStackSize() {
|
||||
+ return this.maxStack;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setMaxStackSize(int i) {
|
||||
+ this.maxStack = i;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Location getLocation() {
|
||||
+ if (this.level == null) return null;
|
||||
+ return CraftLocation.toBukkit(this.worldPosition, this.level.getWorld());
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public static final String TAG_SHERDS = "sherds";
|
||||
public static final String TAG_ITEM = "item";
|
||||
public static final int EVENT_POT_WOBBLES = 1;
|
||||
@@ -1,50 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/DispenserBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/DispenserBlockEntity.java
|
||||
@@ -13,12 +13,47 @@
|
||||
import net.minecraft.world.inventory.DispenserMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
+// CraftBukkit start
|
||||
+import java.util.List;
|
||||
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
+import org.bukkit.entity.HumanEntity;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class DispenserBlockEntity extends RandomizableContainerBlockEntity {
|
||||
|
||||
public static final int CONTAINER_SIZE = 9;
|
||||
private NonNullList<ItemStack> items;
|
||||
|
||||
+ // CraftBukkit start - add fields and methods
|
||||
+ public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
||||
+ private int maxStack = MAX_STACK;
|
||||
+
|
||||
+ public List<ItemStack> getContents() {
|
||||
+ return this.items;
|
||||
+ }
|
||||
+
|
||||
+ public void onOpen(CraftHumanEntity who) {
|
||||
+ this.transaction.add(who);
|
||||
+ }
|
||||
+
|
||||
+ public void onClose(CraftHumanEntity who) {
|
||||
+ this.transaction.remove(who);
|
||||
+ }
|
||||
+
|
||||
+ public List<HumanEntity> getViewers() {
|
||||
+ return this.transaction;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getMaxStackSize() {
|
||||
+ return this.maxStack;
|
||||
+ }
|
||||
+
|
||||
+ public void setMaxStackSize(int size) {
|
||||
+ this.maxStack = size;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
protected DispenserBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
this.items = NonNullList.withSize(9, ItemStack.EMPTY);
|
||||
@@ -1,16 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/JigsawBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/JigsawBlockEntity.java
|
||||
@@ -131,7 +131,12 @@
|
||||
public void generate(ServerLevel world, int maxDepth, boolean keepJigsaws) {
|
||||
BlockPos blockPos = this.getBlockPos().relative(this.getBlockState().getValue(JigsawBlock.ORIENTATION).front());
|
||||
Registry<StructureTemplatePool> registry = world.registryAccess().lookupOrThrow(Registries.TEMPLATE_POOL);
|
||||
- Holder<StructureTemplatePool> holder = registry.getOrThrow(this.pool);
|
||||
+ // Paper start - Replace getHolderOrThrow with a null check
|
||||
+ Holder<StructureTemplatePool> holder = registry.get(this.pool).orElse(null);
|
||||
+ if (holder == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Replace getHolderOrThrow with a null check
|
||||
JigsawPlacement.generateJigsaw(world, holder, this.target, maxDepth, blockPos, keepJigsaws);
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java
|
||||
@@ -19,13 +19,57 @@
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.ticks.ContainerSingleItem;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import java.util.Collections;
|
||||
+import java.util.List;
|
||||
+import org.bukkit.Location;
|
||||
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
+import org.bukkit.entity.HumanEntity;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class JukeboxBlockEntity extends BlockEntity implements ContainerSingleItem.BlockContainerSingleItem {
|
||||
|
||||
public static final String SONG_ITEM_TAG_ID = "RecordItem";
|
||||
public static final String TICKS_SINCE_SONG_STARTED_TAG_ID = "ticks_since_song_started";
|
||||
private ItemStack item;
|
||||
private final JukeboxSongPlayer jukeboxSongPlayer;
|
||||
+ // CraftBukkit start - add fields and methods
|
||||
+ public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
||||
+ private int maxStack = MAX_STACK;
|
||||
+ public boolean opened;
|
||||
|
||||
+ @Override
|
||||
+ public List<ItemStack> getContents() {
|
||||
+ return Collections.singletonList(this.item);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onOpen(CraftHumanEntity who) {
|
||||
+ this.transaction.add(who);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onClose(CraftHumanEntity who) {
|
||||
+ this.transaction.remove(who);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<HumanEntity> getViewers() {
|
||||
+ return this.transaction;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setMaxStackSize(int size) {
|
||||
+ this.maxStack = size;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Location getLocation() {
|
||||
+ if (this.level == null) return null;
|
||||
+ return new org.bukkit.Location(this.level.getWorld(), this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ());
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public JukeboxBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(BlockEntityType.JUKEBOX, pos, state);
|
||||
this.item = ItemStack.EMPTY;
|
||||
@@ -137,7 +181,7 @@
|
||||
|
||||
@Override
|
||||
public int getMaxStackSize() {
|
||||
- return 1;
|
||||
+ return this.maxStack; // CraftBukkit
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -156,12 +200,17 @@
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
- public void setSongItemWithoutPlaying(ItemStack stack) {
|
||||
- this.item = stack;
|
||||
- JukeboxSong.fromStack(this.level.registryAccess(), stack).ifPresent((holder) -> {
|
||||
- this.jukeboxSongPlayer.setSongWithoutPlaying(holder, 0L);
|
||||
+ public void setSongItemWithoutPlaying(ItemStack itemstack, long ticksSinceSongStarted) { // CraftBukkit - add argument
|
||||
+ this.item = itemstack;
|
||||
+ this.jukeboxSongPlayer.song = null; // CraftBukkit - reset
|
||||
+ JukeboxSong.fromStack(this.level != null ? this.level.registryAccess() : org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry(), itemstack).ifPresent((holder) -> { // Paper - fallback to other RegistyrAccess if no level
|
||||
+ this.jukeboxSongPlayer.setSongWithoutPlaying(holder, ticksSinceSongStarted); // CraftBukkit - add argument
|
||||
});
|
||||
- this.level.updateNeighborsAt(this.getBlockPos(), this.getBlockState().getBlock());
|
||||
+ // CraftBukkit start - add null check for level
|
||||
+ if (this.level != null) {
|
||||
+ this.level.updateNeighborsAt(this.getBlockPos(), this.getBlockState().getBlock());
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
this.setChanged();
|
||||
}
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/LecternBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/LecternBlockEntity.java
|
||||
@@ -28,6 +28,17 @@
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec2;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
+// CraftBukkit start
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Arrays;
|
||||
+import java.util.List;
|
||||
+import org.bukkit.Location;
|
||||
+import org.bukkit.block.Lectern;
|
||||
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
+import org.bukkit.craftbukkit.util.CraftLocation;
|
||||
+import org.bukkit.entity.HumanEntity;
|
||||
+import org.bukkit.inventory.InventoryHolder;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class LecternBlockEntity extends BlockEntity implements Clearable, MenuProvider {
|
||||
|
||||
@@ -35,8 +46,55 @@
|
||||
public static final int NUM_DATA = 1;
|
||||
public static final int SLOT_BOOK = 0;
|
||||
public static final int NUM_SLOTS = 1;
|
||||
- public final Container bookAccess = new Container() {
|
||||
+ // CraftBukkit start - add fields and methods
|
||||
+ public final Container bookAccess = new LecternInventory();
|
||||
+ public class LecternInventory implements Container {
|
||||
+
|
||||
+ public List<HumanEntity> transaction = new ArrayList<>();
|
||||
+ private int maxStack = 1;
|
||||
+
|
||||
@Override
|
||||
+ public List<ItemStack> getContents() {
|
||||
+ return Arrays.asList(LecternBlockEntity.this.book);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onOpen(CraftHumanEntity who) {
|
||||
+ this.transaction.add(who);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onClose(CraftHumanEntity who) {
|
||||
+ this.transaction.remove(who);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<HumanEntity> getViewers() {
|
||||
+ return this.transaction;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setMaxStackSize(int i) {
|
||||
+ this.maxStack = i;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Location getLocation() {
|
||||
+ if (LecternBlockEntity.this.level == null) return null;
|
||||
+ return CraftLocation.toBukkit(LecternBlockEntity.this.worldPosition, LecternBlockEntity.this.level.getWorld());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public InventoryHolder getOwner() {
|
||||
+ return (Lectern) LecternBlockEntity.this.getOwner();
|
||||
+ }
|
||||
+
|
||||
+ public LecternBlockEntity getLectern() {
|
||||
+ return LecternBlockEntity.this;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ @Override
|
||||
public int getContainerSize() {
|
||||
return 1;
|
||||
}
|
||||
@@ -80,11 +138,20 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void setItem(int slot, ItemStack stack) {}
|
||||
+ // CraftBukkit start
|
||||
+ public void setItem(int slot, ItemStack stack) {
|
||||
+ if (slot == 0) {
|
||||
+ LecternBlockEntity.this.setBook(stack);
|
||||
+ if (LecternBlockEntity.this.getLevel() != null) {
|
||||
+ LecternBlock.resetBookState(null, LecternBlockEntity.this.getLevel(), LecternBlockEntity.this.getBlockPos(), LecternBlockEntity.this.getBlockState(), LecternBlockEntity.this.hasBook());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
|
||||
@Override
|
||||
public int getMaxStackSize() {
|
||||
- return 1;
|
||||
+ return this.maxStack; // CraftBukkit
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -164,7 +231,7 @@
|
||||
if (j != this.page) {
|
||||
this.page = j;
|
||||
this.setChanged();
|
||||
- LecternBlock.signalPageChange(this.getLevel(), this.getBlockPos(), this.getBlockState());
|
||||
+ if (this.level != null) LecternBlock.signalPageChange(this.getLevel(), this.getBlockPos(), this.getBlockState()); // CraftBukkit
|
||||
}
|
||||
|
||||
}
|
||||
@@ -189,6 +256,35 @@
|
||||
return book;
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ private final CommandSource commandSource = new CommandSource() {
|
||||
+
|
||||
+ @Override
|
||||
+ public void sendSystemMessage(Component message) {
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper) {
|
||||
+ return wrapper.getEntity() != null ? wrapper.getEntity().getBukkitEntity() : new org.bukkit.craftbukkit.command.CraftBlockCommandSender(wrapper, LecternBlockEntity.this);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean acceptsSuccess() {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean acceptsFailure() {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean shouldInformAdmins() {
|
||||
+ return false;
|
||||
+ }
|
||||
+ };
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
private CommandSourceStack createCommandSourceStack(@Nullable Player player, ServerLevel world) {
|
||||
String s;
|
||||
Object object;
|
||||
@@ -203,7 +299,8 @@
|
||||
|
||||
Vec3 vec3d = Vec3.atCenterOf(this.worldPosition);
|
||||
|
||||
- return new CommandSourceStack(CommandSource.NULL, vec3d, Vec2.ZERO, world, 2, s, (Component) object, world.getServer(), player);
|
||||
+ // CraftBukkit - commandSource
|
||||
+ return new CommandSourceStack(this.commandSource, vec3d, Vec2.ZERO, world, 2, s, (Component) object, world.getServer(), player);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -236,7 +333,7 @@
|
||||
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu(int syncId, Inventory playerInventory, Player player) {
|
||||
- return new LecternMenu(syncId, this.bookAccess, this.dataAccess);
|
||||
+ return new LecternMenu(syncId, this.bookAccess, this.dataAccess, playerInventory); // CraftBukkit
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1,16 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
@@ -115,4 +115,13 @@
|
||||
nbt.remove("LootTable");
|
||||
nbt.remove("LootTableSeed");
|
||||
}
|
||||
+
|
||||
+ // Paper start - LootTable API
|
||||
+ final com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(); // Paper
|
||||
+
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData() {
|
||||
+ return this.lootableData;
|
||||
+ }
|
||||
+ // Paper end - LootTable API
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java
|
||||
@@ -26,6 +26,7 @@
|
||||
private final VibrationSystem.Listener vibrationListener;
|
||||
private final VibrationSystem.User vibrationUser = this.createVibrationUser();
|
||||
public int lastVibrationFrequency;
|
||||
+ @Nullable public Integer rangeOverride = null; // Paper - Configurable sculk sensor listener range
|
||||
|
||||
protected SculkSensorBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
@@ -52,8 +53,16 @@
|
||||
.resultOrPartial(string -> LOGGER.error("Failed to parse vibration listener for Sculk Sensor: '{}'", string))
|
||||
.ifPresent(listener -> this.vibrationData = listener);
|
||||
}
|
||||
+ // Paper start - Configurable sculk sensor listener range
|
||||
+ if (nbt.contains(PAPER_LISTENER_RANGE_NBT_KEY)) {
|
||||
+ this.rangeOverride = nbt.getInt(PAPER_LISTENER_RANGE_NBT_KEY);
|
||||
+ } else {
|
||||
+ this.rangeOverride = null;
|
||||
+ }
|
||||
+ // Paper end - Configurable sculk sensor listener range
|
||||
}
|
||||
|
||||
+ protected static final String PAPER_LISTENER_RANGE_NBT_KEY = "Paper.ListenerRange"; // Paper - Configurable sculk sensor listener range
|
||||
@Override
|
||||
protected void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
super.saveAdditional(nbt, registries);
|
||||
@@ -63,7 +72,13 @@
|
||||
.encodeStart(registryOps, this.vibrationData)
|
||||
.resultOrPartial(string -> LOGGER.error("Failed to encode vibration listener for Sculk Sensor: '{}'", string))
|
||||
.ifPresent(listenerNbt -> nbt.put("listener", listenerNbt));
|
||||
+ this.saveRangeOverride(nbt); // Paper - Configurable sculk sensor listener range
|
||||
}
|
||||
+ // Paper start - Configurable sculk sensor listener range
|
||||
+ protected void saveRangeOverride(CompoundTag nbt) {
|
||||
+ if (this.rangeOverride != null && this.rangeOverride != VibrationUser.LISTENER_RANGE) nbt.putInt(PAPER_LISTENER_RANGE_NBT_KEY, this.rangeOverride); // only save if it's different from the default
|
||||
+ }
|
||||
+ // Paper end - Configurable sculk sensor listener range
|
||||
|
||||
@Override
|
||||
public VibrationSystem.Data getVibrationData() {
|
||||
@@ -100,6 +115,7 @@
|
||||
|
||||
@Override
|
||||
public int getListenerRadius() {
|
||||
+ if (SculkSensorBlockEntity.this.rangeOverride != null) return SculkSensorBlockEntity.this.rangeOverride; // Paper - Configurable sculk sensor listener range
|
||||
return 8;
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java
|
||||
@@ -105,6 +105,13 @@
|
||||
|
||||
@Nullable
|
||||
public static ServerPlayer tryGetPlayer(@Nullable Entity entity) {
|
||||
+ // Paper start - check global player list where appropriate; ensure level is the same for sculk events
|
||||
+ final ServerPlayer player = tryGetPlayer0(entity);
|
||||
+ return player != null && player.level() == entity.level() ? player : null;
|
||||
+ }
|
||||
+ @Nullable
|
||||
+ private static ServerPlayer tryGetPlayer0(@Nullable Entity entity) {
|
||||
+ // Paper end - check global player list where appropriate
|
||||
if (entity instanceof ServerPlayer) {
|
||||
return (ServerPlayer)entity;
|
||||
} else {
|
||||
@@ -190,7 +197,7 @@
|
||||
private boolean trySummonWarden(ServerLevel world) {
|
||||
return this.warningLevel >= 4
|
||||
&& SpawnUtil.trySpawnMob(
|
||||
- EntityType.WARDEN, EntitySpawnReason.TRIGGERED, world, this.getBlockPos(), 20, 5, 6, SpawnUtil.Strategy.ON_TOP_OF_COLLIDER, false
|
||||
+ EntityType.WARDEN, EntitySpawnReason.TRIGGERED, world, this.getBlockPos(), 20, 5, 6, SpawnUtil.Strategy.ON_TOP_OF_COLLIDER, false, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL, null // Paper - Entity#getEntitySpawnReason
|
||||
)
|
||||
.isPresent();
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java
|
||||
@@ -33,6 +33,10 @@
|
||||
import net.minecraft.world.level.material.PushReaction;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
+import org.bukkit.entity.HumanEntity;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class ShulkerBoxBlockEntity extends RandomizableContainerBlockEntity implements WorldlyContainer {
|
||||
|
||||
@@ -52,6 +56,37 @@
|
||||
@Nullable
|
||||
private final DyeColor color;
|
||||
|
||||
+ // CraftBukkit start - add fields and methods
|
||||
+ public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
||||
+ private int maxStack = MAX_STACK;
|
||||
+ public boolean opened;
|
||||
+
|
||||
+ public List<ItemStack> getContents() {
|
||||
+ return this.itemStacks;
|
||||
+ }
|
||||
+
|
||||
+ public void onOpen(CraftHumanEntity who) {
|
||||
+ this.transaction.add(who);
|
||||
+ }
|
||||
+
|
||||
+ public void onClose(CraftHumanEntity who) {
|
||||
+ this.transaction.remove(who);
|
||||
+ }
|
||||
+
|
||||
+ public List<HumanEntity> getViewers() {
|
||||
+ return this.transaction;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getMaxStackSize() {
|
||||
+ return this.maxStack;
|
||||
+ }
|
||||
+
|
||||
+ public void setMaxStackSize(int size) {
|
||||
+ this.maxStack = size;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public ShulkerBoxBlockEntity(@Nullable DyeColor color, BlockPos pos, BlockState state) {
|
||||
super(BlockEntityType.SHULKER_BOX, pos, state);
|
||||
this.itemStacks = NonNullList.withSize(27, ItemStack.EMPTY);
|
||||
@@ -184,6 +219,7 @@
|
||||
}
|
||||
|
||||
++this.openCount;
|
||||
+ if (this.opened) return; // CraftBukkit - only animate if the ShulkerBox hasn't been forced open already by an API call.
|
||||
this.level.blockEvent(this.worldPosition, this.getBlockState().getBlock(), 1, this.openCount);
|
||||
if (this.openCount == 1) {
|
||||
this.level.gameEvent((Entity) player, (Holder) GameEvent.CONTAINER_OPEN, this.worldPosition);
|
||||
@@ -197,6 +233,7 @@
|
||||
public void stopOpen(Player player) {
|
||||
if (!this.remove && !player.isSpectator()) {
|
||||
--this.openCount;
|
||||
+ if (this.opened) return; // CraftBukkit - only animate if the ShulkerBox hasn't been forced open already by an API call.
|
||||
this.level.blockEvent(this.worldPosition, this.getBlockState().getBlock(), 1, this.openCount);
|
||||
if (this.openCount <= 0) {
|
||||
this.level.gameEvent((Entity) player, (Holder) GameEvent.CONTAINER_CLOSE, this.worldPosition);
|
||||
@@ -1,269 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/SignBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/SignBlockEntity.java
|
||||
@@ -22,12 +22,12 @@
|
||||
import net.minecraft.network.chat.Style;
|
||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.FilteredText;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
-import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.SignBlock;
|
||||
@@ -35,6 +35,12 @@
|
||||
import net.minecraft.world.phys.Vec2;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.slf4j.Logger;
|
||||
+import org.bukkit.block.sign.Side;
|
||||
+import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
+import org.bukkit.craftbukkit.util.CraftChatMessage;
|
||||
+import org.bukkit.entity.Player;
|
||||
+import org.bukkit.event.block.SignChangeEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class SignBlockEntity extends BlockEntity {
|
||||
|
||||
@@ -61,13 +67,18 @@
|
||||
return new SignText();
|
||||
}
|
||||
|
||||
- public boolean isFacingFrontText(Player player) {
|
||||
+ public boolean isFacingFrontText(net.minecraft.world.entity.player.Player player) {
|
||||
+ // Paper start - More Sign Block API
|
||||
+ return this.isFacingFrontText(player.getX(), player.getZ());
|
||||
+ }
|
||||
+ public boolean isFacingFrontText(double x, double z) {
|
||||
+ // Paper end - More Sign Block API
|
||||
Block block = this.getBlockState().getBlock();
|
||||
|
||||
if (block instanceof SignBlock blocksign) {
|
||||
Vec3 vec3d = blocksign.getSignHitboxCenterPosition(this.getBlockState());
|
||||
- double d0 = player.getX() - ((double) this.getBlockPos().getX() + vec3d.x);
|
||||
- double d1 = player.getZ() - ((double) this.getBlockPos().getZ() + vec3d.z);
|
||||
+ double d0 = x - ((double) this.getBlockPos().getX() + vec3d.x); // Paper - More Sign Block API
|
||||
+ double d1 = z - ((double) this.getBlockPos().getZ() + vec3d.z); // Paper - More Sign Block API
|
||||
float f = blocksign.getYRotationDegrees(this.getBlockState());
|
||||
float f1 = (float) (Mth.atan2(d1, d0) * 57.2957763671875D) - 90.0F;
|
||||
|
||||
@@ -101,7 +112,7 @@
|
||||
protected void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
super.saveAdditional(nbt, registries);
|
||||
DynamicOps<Tag> dynamicops = registries.createSerializationContext(NbtOps.INSTANCE);
|
||||
- DataResult dataresult = SignText.DIRECT_CODEC.encodeStart(dynamicops, this.frontText);
|
||||
+ DataResult<Tag> dataresult = SignText.DIRECT_CODEC.encodeStart(dynamicops, this.frontText); // CraftBukkit - decompile error
|
||||
Logger logger = SignBlockEntity.LOGGER;
|
||||
|
||||
Objects.requireNonNull(logger);
|
||||
@@ -121,7 +132,7 @@
|
||||
protected void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
super.loadAdditional(nbt, registries);
|
||||
DynamicOps<Tag> dynamicops = registries.createSerializationContext(NbtOps.INSTANCE);
|
||||
- DataResult dataresult;
|
||||
+ DataResult<SignText> dataresult; // CraftBukkit - decompile error
|
||||
Logger logger;
|
||||
|
||||
if (nbt.contains("front_text")) {
|
||||
@@ -161,7 +172,7 @@
|
||||
|
||||
if (world instanceof ServerLevel worldserver) {
|
||||
try {
|
||||
- return ComponentUtils.updateForEntity(SignBlockEntity.createCommandSourceStack((Player) null, worldserver, this.worldPosition), text, (Entity) null, 0);
|
||||
+ return ComponentUtils.updateForEntity(this.createCommandSourceStack((net.minecraft.world.entity.player.Player) null, worldserver, this.worldPosition), text, (Entity) null, 0);
|
||||
} catch (CommandSyntaxException commandsyntaxexception) {
|
||||
;
|
||||
}
|
||||
@@ -170,15 +181,17 @@
|
||||
return text;
|
||||
}
|
||||
|
||||
- public void updateSignText(Player player, boolean front, List<FilteredText> messages) {
|
||||
+ public void updateSignText(net.minecraft.world.entity.player.Player player, boolean front, List<FilteredText> messages) {
|
||||
if (!this.isWaxed() && player.getUUID().equals(this.getPlayerWhoMayEdit()) && this.level != null) {
|
||||
this.updateText((signtext) -> {
|
||||
- return this.setMessages(player, messages, signtext);
|
||||
+ return this.setMessages(player, messages, signtext, front); // CraftBukkit
|
||||
}, front);
|
||||
this.setAllowedPlayerEditor((UUID) null);
|
||||
this.level.sendBlockUpdated(this.getBlockPos(), this.getBlockState(), this.getBlockState(), 3);
|
||||
} else {
|
||||
SignBlockEntity.LOGGER.warn("Player {} just tried to change non-editable sign", player.getName().getString());
|
||||
+ if (player.distanceToSqr(this.getBlockPos().getX(), this.getBlockPos().getY(), this.getBlockPos().getZ()) < 32 * 32) // Paper - Dont send far away sign update
|
||||
+ ((ServerPlayer) player).connection.send(this.getUpdatePacket()); // CraftBukkit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,19 +201,43 @@
|
||||
return this.setText((SignText) textChanger.apply(signtext), front);
|
||||
}
|
||||
|
||||
- private SignText setMessages(Player player, List<FilteredText> messages, SignText text) {
|
||||
- for (int i = 0; i < messages.size(); ++i) {
|
||||
- FilteredText filteredtext = (FilteredText) messages.get(i);
|
||||
- Style chatmodifier = text.getMessage(i, player.isTextFilteringEnabled()).getStyle();
|
||||
+ private SignText setMessages(net.minecraft.world.entity.player.Player entityhuman, List<FilteredText> list, SignText signtext, boolean front) { // CraftBukkit
|
||||
+ SignText originalText = signtext; // CraftBukkit
|
||||
+ for (int i = 0; i < list.size(); ++i) {
|
||||
+ FilteredText filteredtext = (FilteredText) list.get(i);
|
||||
+ Style chatmodifier = signtext.getMessage(i, entityhuman.isTextFilteringEnabled()).getStyle();
|
||||
|
||||
- if (player.isTextFilteringEnabled()) {
|
||||
- text = text.setMessage(i, Component.literal(filteredtext.filteredOrEmpty()).setStyle(chatmodifier));
|
||||
+ if (entityhuman.isTextFilteringEnabled()) {
|
||||
+ signtext = signtext.setMessage(i, Component.literal(net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty())).setStyle(chatmodifier)); // Paper - filter sign text to chat only
|
||||
} else {
|
||||
- text = text.setMessage(i, Component.literal(filteredtext.raw()).setStyle(chatmodifier), Component.literal(filteredtext.filteredOrEmpty()).setStyle(chatmodifier));
|
||||
+ signtext = signtext.setMessage(i, Component.literal(net.minecraft.util.StringUtil.filterText(filteredtext.raw())).setStyle(chatmodifier), Component.literal(net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty())).setStyle(chatmodifier)); // Paper - filter sign text to chat only
|
||||
}
|
||||
}
|
||||
|
||||
- return text;
|
||||
+ // CraftBukkit start
|
||||
+ Player player = ((ServerPlayer) entityhuman).getBukkitEntity();
|
||||
+ List<net.kyori.adventure.text.Component> lines = new java.util.ArrayList<>(); // Paper - adventure
|
||||
+
|
||||
+ for (int i = 0; i < list.size(); ++i) {
|
||||
+ lines.add(io.papermc.paper.adventure.PaperAdventure.asAdventure(signtext.getMessage(i, entityhuman.isTextFilteringEnabled()))); // Paper - Adventure
|
||||
+ }
|
||||
+
|
||||
+ SignChangeEvent event = new SignChangeEvent(CraftBlock.at(this.level, this.worldPosition), player, new java.util.ArrayList<>(lines), (front) ? Side.FRONT : Side.BACK); // Paper - Adventure
|
||||
+ entityhuman.level().getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ if (event.isCancelled()) {
|
||||
+ return originalText;
|
||||
+ }
|
||||
+
|
||||
+ Component[] components = org.bukkit.craftbukkit.block.CraftSign.sanitizeLines(event.lines()); // Paper - Adventure
|
||||
+ for (int i = 0; i < components.length; i++) {
|
||||
+ if (!Objects.equals(lines.get(i), event.line(i))) { // Paper - Adventure
|
||||
+ signtext = signtext.setMessage(i, components[i]);
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ return signtext;
|
||||
}
|
||||
|
||||
public boolean setText(SignText text, boolean front) {
|
||||
@@ -227,11 +264,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
- public boolean canExecuteClickCommands(boolean front, Player player) {
|
||||
+ public boolean canExecuteClickCommands(boolean front, net.minecraft.world.entity.player.Player player) {
|
||||
return this.isWaxed() && this.getText(front).hasAnyClickCommands(player);
|
||||
}
|
||||
|
||||
- public boolean executeClickCommandsIfPresent(Player player, Level world, BlockPos pos, boolean front) {
|
||||
+ public boolean executeClickCommandsIfPresent(net.minecraft.world.entity.player.Player player, Level world, BlockPos pos, boolean front) {
|
||||
boolean flag1 = false;
|
||||
Component[] aichatbasecomponent = this.getText(front).getMessages(player.isTextFilteringEnabled());
|
||||
int i = aichatbasecomponent.length;
|
||||
@@ -242,7 +279,17 @@
|
||||
ClickEvent chatclickable = chatmodifier.getClickEvent();
|
||||
|
||||
if (chatclickable != null && chatclickable.getAction() == ClickEvent.Action.RUN_COMMAND) {
|
||||
- player.getServer().getCommands().performPrefixedCommand(SignBlockEntity.createCommandSourceStack(player, world, pos), chatclickable.getValue());
|
||||
+ // Paper start - Fix commands from signs not firing command events
|
||||
+ String command = chatclickable.getValue().startsWith("/") ? chatclickable.getValue() : "/" + chatclickable.getValue();
|
||||
+ if (org.spigotmc.SpigotConfig.logCommands) {
|
||||
+ LOGGER.info("{} issued server command: {}", player.getScoreboardName(), command);
|
||||
+ }
|
||||
+ io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent event = new io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent((org.bukkit.entity.Player) player.getBukkitEntity(), command, new org.bukkit.craftbukkit.util.LazyPlayerSet(player.getServer()), (org.bukkit.block.Sign) CraftBlock.at(this.level, this.worldPosition).getState(), front ? Side.FRONT : Side.BACK);
|
||||
+ if (!event.callEvent()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ player.getServer().getCommands().performPrefixedCommand(this.createCommandSourceStack(((org.bukkit.craftbukkit.entity.CraftPlayer) event.getPlayer()).getHandle(), world, pos), event.getMessage());
|
||||
+ // Paper end - Fix commands from signs not firing command events
|
||||
flag1 = true;
|
||||
}
|
||||
}
|
||||
@@ -250,11 +297,55 @@
|
||||
return flag1;
|
||||
}
|
||||
|
||||
- private static CommandSourceStack createCommandSourceStack(@Nullable Player player, Level world, BlockPos pos) {
|
||||
+ // CraftBukkit start
|
||||
+ private final CommandSource commandSource = new CommandSource() {
|
||||
+
|
||||
+ @Override
|
||||
+ public void sendSystemMessage(Component message) {}
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper) {
|
||||
+ return wrapper.getEntity() != null ? wrapper.getEntity().getBukkitEntity() : new org.bukkit.craftbukkit.command.CraftBlockCommandSender(wrapper, SignBlockEntity.this);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean acceptsSuccess() {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean acceptsFailure() {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean shouldInformAdmins() {
|
||||
+ return false;
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ private CommandSourceStack createCommandSourceStack(@Nullable net.minecraft.world.entity.player.Player player, Level world, BlockPos pos) {
|
||||
+ // CraftBukkit end
|
||||
String s = player == null ? "Sign" : player.getName().getString();
|
||||
Object object = player == null ? Component.literal("Sign") : player.getDisplayName();
|
||||
|
||||
- return new CommandSourceStack(CommandSource.NULL, Vec3.atCenterOf(pos), Vec2.ZERO, (ServerLevel) world, 2, s, (Component) object, world.getServer(), player);
|
||||
+ // Paper start - Fix commands from signs not firing command events
|
||||
+ CommandSource commandSource = this.level.paperConfig().misc.showSignClickCommandFailureMsgsToPlayer ? new io.papermc.paper.commands.DelegatingCommandSource(this.commandSource) {
|
||||
+ @Override
|
||||
+ public void sendSystemMessage(Component message) {
|
||||
+ if (player instanceof final ServerPlayer serverPlayer) {
|
||||
+ serverPlayer.sendSystemMessage(message);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean acceptsFailure() {
|
||||
+ return true;
|
||||
+ }
|
||||
+ } : this.commandSource;
|
||||
+ // Paper end - Fix commands from signs not firing command events
|
||||
+ // CraftBukkit - this
|
||||
+ return new CommandSourceStack(commandSource, Vec3.atCenterOf(pos), Vec2.ZERO, (ServerLevel) world, 2, s, (Component) object, world.getServer(), player); // Paper - Fix commands from signs not firing command events
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -273,12 +364,17 @@
|
||||
|
||||
@Nullable
|
||||
public UUID getPlayerWhoMayEdit() {
|
||||
+ // CraftBukkit start - unnecessary sign ticking removed, so do this lazily
|
||||
+ if (this.level != null && this.playerWhoMayEdit != null) {
|
||||
+ this.clearInvalidPlayerWhoMayEdit(this, this.level, this.playerWhoMayEdit);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
return this.playerWhoMayEdit;
|
||||
}
|
||||
|
||||
private void markUpdated() {
|
||||
this.setChanged();
|
||||
- this.level.sendBlockUpdated(this.getBlockPos(), this.getBlockState(), this.getBlockState(), 3);
|
||||
+ if (this.level != null) this.level.sendBlockUpdated(this.getBlockPos(), this.getBlockState(), this.getBlockState(), 3); // CraftBukkit - skip notify if world is null (SPIGOT-5122)
|
||||
}
|
||||
|
||||
public boolean isWaxed() {
|
||||
@@ -296,7 +392,7 @@
|
||||
}
|
||||
|
||||
public boolean playerIsTooFarAwayToEdit(UUID uuid) {
|
||||
- Player entityhuman = this.level.getPlayerByUUID(uuid);
|
||||
+ net.minecraft.world.entity.player.Player entityhuman = this.level.getPlayerByUUID(uuid);
|
||||
|
||||
return entityhuman == null || !entityhuman.canInteractWithBlock(this.getBlockPos(), 4.0D);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
--- a/net/minecraft/world/level/block/entity/SkullBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/SkullBlockEntity.java
|
||||
@@ -41,7 +41,7 @@
|
||||
@Nullable
|
||||
private static LoadingCache<String, CompletableFuture<Optional<GameProfile>>> profileCacheByName;
|
||||
@Nullable
|
||||
- private static LoadingCache<UUID, CompletableFuture<Optional<GameProfile>>> profileCacheById;
|
||||
+ private static LoadingCache<com.mojang.datafixers.util.Pair<java.util.UUID, @org.jetbrains.annotations.Nullable GameProfile>, CompletableFuture<Optional<GameProfile>>> profileCacheById; // Paper - player profile events
|
||||
public static final Executor CHECKED_MAIN_THREAD_EXECUTOR = runnable -> {
|
||||
Executor executor = mainThreadExecutor;
|
||||
if (executor != null) {
|
||||
@@ -76,9 +76,9 @@
|
||||
profileCacheById = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(Duration.ofMinutes(10L))
|
||||
.maximumSize(256L)
|
||||
- .build(new CacheLoader<UUID, CompletableFuture<Optional<GameProfile>>>() {
|
||||
+ .build(new CacheLoader<>() { // Paper - player profile events
|
||||
@Override
|
||||
- public CompletableFuture<Optional<GameProfile>> load(UUID uUID) {
|
||||
+ public CompletableFuture<Optional<GameProfile>> load(com.mojang.datafixers.util.Pair<java.util.UUID, @org.jetbrains.annotations.Nullable GameProfile> uUID) { // Paper - player profile events
|
||||
return SkullBlockEntity.fetchProfileById(uUID, apiServices, booleanSupplier);
|
||||
}
|
||||
});
|
||||
@@ -89,23 +89,29 @@
|
||||
.getAsync(name)
|
||||
.thenCompose(
|
||||
optional -> {
|
||||
- LoadingCache<UUID, CompletableFuture<Optional<GameProfile>>> loadingCache = profileCacheById;
|
||||
+ LoadingCache<com.mojang.datafixers.util.Pair<java.util.UUID, @org.jetbrains.annotations.Nullable GameProfile>, CompletableFuture<Optional<GameProfile>>> loadingCache = profileCacheById; // Paper - player profile events
|
||||
return loadingCache != null && !optional.isEmpty()
|
||||
- ? loadingCache.getUnchecked(optional.get().getId()).thenApply(optional2 -> optional2.or(() -> optional))
|
||||
+ ? loadingCache.getUnchecked(new com.mojang.datafixers.util.Pair<>(optional.get().getId(), optional.get())).thenApply(optional2 -> optional2.or(() -> optional)) // Paper - player profile events
|
||||
: CompletableFuture.completedFuture(Optional.empty());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
- static CompletableFuture<Optional<GameProfile>> fetchProfileById(UUID uuid, Services apiServices, BooleanSupplier booleanSupplier) {
|
||||
+ static CompletableFuture<Optional<GameProfile>> fetchProfileById(com.mojang.datafixers.util.Pair<java.util.UUID, @org.jetbrains.annotations.Nullable GameProfile> pair, Services apiServices, BooleanSupplier booleanSupplier) { // Paper
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
if (booleanSupplier.getAsBoolean()) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
- ProfileResult profileResult = apiServices.sessionService().fetchProfile(uuid, true);
|
||||
+ // Paper start - fill player profile events
|
||||
+ if (apiServices.sessionService() instanceof com.destroystokyo.paper.profile.PaperMinecraftSessionService paperService) {
|
||||
+ final GameProfile profile = pair.getSecond() != null ? pair.getSecond() : new com.mojang.authlib.GameProfile(pair.getFirst(), "");
|
||||
+ return Optional.ofNullable(paperService.fetchProfile(profile, true)).map(ProfileResult::profile);
|
||||
+ }
|
||||
+ ProfileResult profileResult = apiServices.sessionService().fetchProfile(pair.getFirst(), true);
|
||||
+ // Paper end - fill player profile events
|
||||
return Optional.ofNullable(profileResult).map(ProfileResult::profile);
|
||||
}
|
||||
- }, Util.backgroundExecutor().forName("fetchProfile"));
|
||||
+ }, Util.PROFILE_EXECUTOR); // Paper - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
@@ -210,9 +216,11 @@
|
||||
: CompletableFuture.completedFuture(Optional.empty());
|
||||
}
|
||||
|
||||
- public static CompletableFuture<Optional<GameProfile>> fetchGameProfile(UUID uuid) {
|
||||
- LoadingCache<UUID, CompletableFuture<Optional<GameProfile>>> loadingCache = profileCacheById;
|
||||
- return loadingCache != null ? loadingCache.getUnchecked(uuid) : CompletableFuture.completedFuture(Optional.empty());
|
||||
+ // Paper start - player profile events
|
||||
+ public static CompletableFuture<Optional<GameProfile>> fetchGameProfile(UUID uuid, @Nullable String name) {
|
||||
+ LoadingCache<com.mojang.datafixers.util.Pair<java.util.UUID, @org.jetbrains.annotations.Nullable GameProfile>, CompletableFuture<Optional<GameProfile>>> loadingCache = profileCacheById;
|
||||
+ return loadingCache != null ? loadingCache.getUnchecked(new com.mojang.datafixers.util.Pair<>(uuid, name != null ? new com.mojang.authlib.GameProfile(uuid, name) : null)) : CompletableFuture.completedFuture(Optional.empty());
|
||||
+ // Paper end - player profile events
|
||||
}
|
||||
|
||||
@Override
|
||||
Reference in New Issue
Block a user