Update loot table and other patches

This commit is contained in:
Jason Penilla 2023-12-05 14:20:44 -07:00
parent 2a9a9c4cf0
commit fad3fa9bde
No known key found for this signature in database
GPG key ID: 0E75A301420E48F8
5 changed files with 90 additions and 72 deletions

View file

@ -0,0 +1,818 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 1 May 2016 21:19:14 -0400
Subject: [PATCH] LootTable API & Replenishable Lootables Feature
Provides an API to control the loot table for an object.
Also provides a feature that any Lootable Inventory (Chests in Structures)
can automatically replenish after a given time.
This feature is good for long term worlds so that newer players
do not suffer with "Every chest has been looted"
== AT ==
public org.bukkit.craftbukkit.block.CraftBlockEntityState getTileEntity()Lnet/minecraft/world/level/block/entity/BlockEntity;
public org.bukkit.craftbukkit.block.CraftLootable setLootTable(Lorg/bukkit/loot/LootTable;J)V
public org.bukkit.craftbukkit.entity.CraftMinecartContainer setLootTable(Lorg/bukkit/loot/LootTable;J)V
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ca389ca789dc54bba3542cac0aac2e1dc66c870
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
@@ -0,0 +1,63 @@
+package com.destroystokyo.paper.loottable;
+
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.vehicle.AbstractMinecartContainer;
+import net.minecraft.world.entity.vehicle.ContainerEntity;
+import net.minecraft.world.level.Level;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+
+public class PaperContainerEntityLootableInventory implements PaperLootableEntityInventory {
+
+ private final ContainerEntity entity;
+
+ public PaperContainerEntityLootableInventory(ContainerEntity entity) {
+ this.entity = entity;
+ }
+
+ @Override
+ public org.bukkit.loot.LootTable getLootTable() {
+ return entity.getLootTable() != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.getLootTable())) : null;
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table, long seed) {
+ setLootTable(table);
+ setSeed(seed);
+ }
+
+ @Override
+ public void setSeed(long seed) {
+ entity.setLootTableSeed(seed);
+ }
+
+ @Override
+ public long getSeed() {
+ return entity.getLootTableSeed();
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table) {
+ entity.setLootTable((table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey()));
+ }
+
+ @Override
+ public PaperLootableInventoryData getLootableData() {
+ return entity.getLootableData();
+ }
+
+ @Override
+ public Entity getHandle() {
+ return entity.getEntity();
+ }
+
+ @Override
+ public LootableInventory getAPILootableInventory() {
+ return (LootableInventory) entity.getEntity().getBukkitEntity();
+ }
+
+ @Override
+ public Level getNMSWorld() {
+ return entity.level();
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..24c6ff57cd25533e71f8a1d0b3c0ece2fdbbf87e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java
@@ -0,0 +1,33 @@
+package com.destroystokyo.paper.loottable;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
+import org.bukkit.Chunk;
+import org.bukkit.block.Block;
+
+public interface PaperLootableBlockInventory extends LootableBlockInventory, PaperLootableInventory {
+
+ RandomizableContainerBlockEntity getTileEntity();
+
+ @Override
+ default LootableInventory getAPILootableInventory() {
+ return this;
+ }
+
+ @Override
+ default Level getNMSWorld() {
+ return this.getTileEntity().getLevel();
+ }
+
+ default Block getBlock() {
+ final BlockPos position = this.getTileEntity().getBlockPos();
+ final Chunk bukkitChunk = this.getBukkitWorld().getChunkAt(org.bukkit.craftbukkit.block.CraftBlock.at(this.getNMSWorld(), position));
+ return bukkitChunk.getBlock(position.getX(), position.getY(), position.getZ());
+ }
+
+ @Override
+ default PaperLootableInventoryData getLootableData() {
+ return this.getTileEntity().lootableData;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..2fba5bc0f982e143ad5f5bda55d768edc5f847df
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java
@@ -0,0 +1,28 @@
+package com.destroystokyo.paper.loottable;
+
+import net.minecraft.world.level.Level;
+import org.bukkit.entity.Entity;
+
+public interface PaperLootableEntityInventory extends LootableEntityInventory, PaperLootableInventory {
+
+ net.minecraft.world.entity.Entity getHandle();
+
+ @Override
+ default LootableInventory getAPILootableInventory() {
+ return this;
+ }
+
+ default Entity getEntity() {
+ return getHandle().getBukkitEntity();
+ }
+
+ @Override
+ default Level getNMSWorld() {
+ return getHandle().getCommandSenderWorld();
+ }
+
+ @Override
+ default PaperLootableInventoryData getLootableData() {
+ return getHandle().lootableData;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e6dac2cef7af26ad74928eff631c1826c2980bb
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java
@@ -0,0 +1,75 @@
+package com.destroystokyo.paper.loottable;
+
+import org.bukkit.loot.Lootable;
+import java.util.UUID;
+import net.minecraft.world.level.Level;
+
+public interface PaperLootableInventory extends LootableInventory, Lootable {
+
+ PaperLootableInventoryData getLootableData();
+ LootableInventory getAPILootableInventory();
+
+ Level getNMSWorld();
+
+ default org.bukkit.World getBukkitWorld() {
+ return getNMSWorld().getWorld();
+ }
+
+ @Override
+ default boolean isRefillEnabled() {
+ return getNMSWorld().paperConfig().lootables.autoReplenish;
+ }
+
+ @Override
+ default boolean hasBeenFilled() {
+ return getLastFilled() != -1;
+ }
+
+ @Override
+ default boolean hasPlayerLooted(UUID player) {
+ return getLootableData().hasPlayerLooted(player);
+ }
+
+ @Override
+ default boolean canPlayerLoot(final UUID player) {
+ return getLootableData().canPlayerLoot(player, this.getNMSWorld().paperConfig());
+ }
+
+ @Override
+ default Long getLastLooted(UUID player) {
+ return getLootableData().getLastLooted(player);
+ }
+
+ @Override
+ default boolean setHasPlayerLooted(UUID player, boolean looted) {
+ final boolean hasLooted = hasPlayerLooted(player);
+ if (hasLooted != looted) {
+ getLootableData().setPlayerLootedState(player, looted);
+ }
+ return hasLooted;
+ }
+
+ @Override
+ default boolean hasPendingRefill() {
+ long nextRefill = getLootableData().getNextRefill();
+ return nextRefill != -1 && nextRefill > getLootableData().getLastFill();
+ }
+
+ @Override
+ default long getLastFilled() {
+ return getLootableData().getLastFill();
+ }
+
+ @Override
+ default long getNextRefill() {
+ return getLootableData().getNextRefill();
+ }
+
+ @Override
+ default long setNextRefill(long refillAt) {
+ if (refillAt < -1) {
+ refillAt = -1;
+ }
+ return getLootableData().setNextRefill(refillAt);
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
new file mode 100644
index 0000000000000000000000000000000000000000..5408cbc21fc7577a6100b5a1ca0463e899d2df8b
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
@@ -0,0 +1,188 @@
+package com.destroystokyo.paper.loottable;
+
+import io.papermc.paper.configuration.WorldConfiguration;
+import io.papermc.paper.configuration.type.DurationOrDisabled;
+import java.time.temporal.ChronoUnit;
+import java.util.concurrent.TimeUnit;
+import org.bukkit.entity.Player;
+import org.bukkit.loot.LootTable;
+import javax.annotation.Nullable;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.ListTag;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.UUID;
+
+public class PaperLootableInventoryData {
+
+ private static final Random RANDOM = new Random();
+
+ private long lastFill = -1;
+ private long nextRefill = -1;
+ private int numRefills = 0;
+ private Map<UUID, Long> lootedPlayers;
+ private final PaperLootableInventory lootable;
+
+ public PaperLootableInventoryData(PaperLootableInventory lootable) {
+ this.lootable = lootable;
+ }
+
+ long getLastFill() {
+ return this.lastFill;
+ }
+
+ long getNextRefill() {
+ return this.nextRefill;
+ }
+
+ long setNextRefill(long nextRefill) {
+ long prev = this.nextRefill;
+ this.nextRefill = nextRefill;
+ return prev;
+ }
+
+ public boolean shouldReplenish(@Nullable net.minecraft.world.entity.player.Player player) {
+ LootTable table = this.lootable.getLootTable();
+
+ // No Loot Table associated
+ if (table == null) {
+ return false;
+ }
+
+ // ALWAYS process the first fill or if the feature is disabled
+ if (this.lastFill == -1 || !this.lootable.getNMSWorld().paperConfig().lootables.autoReplenish) {
+ return true;
+ }
+
+ // Only process refills when a player is set
+ if (player == null) {
+ return false;
+ }
+
+ // Chest is not scheduled for refill
+ if (this.nextRefill == -1) {
+ return false;
+ }
+
+ final WorldConfiguration paperConfig = this.lootable.getNMSWorld().paperConfig();
+
+ // Check if max refills has been hit
+ if (paperConfig.lootables.maxRefills != -1 && this.numRefills >= paperConfig.lootables.maxRefills) {
+ return false;
+ }
+
+ // Refill has not been reached
+ if (this.nextRefill > System.currentTimeMillis()) {
+ return false;
+ }
+
+
+ final Player bukkitPlayer = (Player) player.getBukkitEntity();
+ LootableInventoryReplenishEvent event = new LootableInventoryReplenishEvent(bukkitPlayer, lootable.getAPILootableInventory());
+ event.setCancelled(!canPlayerLoot(player.getUUID(), paperConfig));
+ return event.callEvent();
+ }
+ public void processRefill(@Nullable net.minecraft.world.entity.player.Player player) {
+ this.lastFill = System.currentTimeMillis();
+ final WorldConfiguration paperConfig = this.lootable.getNMSWorld().paperConfig();
+ if (paperConfig.lootables.autoReplenish) {
+ long min = paperConfig.lootables.refreshMin.seconds();
+ long max = paperConfig.lootables.refreshMax.seconds();
+ this.nextRefill = this.lastFill + (min + RANDOM.nextLong(max - min + 1)) * 1000L;
+ this.numRefills++;
+ if (paperConfig.lootables.resetSeedOnFill) {
+ this.lootable.setSeed(0);
+ }
+ if (player != null) { // This means that numRefills can be incremented without a player being in the lootedPlayers list - Seems to be EntityMinecartChest specific
+ this.setPlayerLootedState(player.getUUID(), true);
+ }
+ } else {
+ this.lootable.clearLootTable();
+ }
+ }
+
+
+ public void loadNbt(CompoundTag base) {
+ if (!base.contains("Paper.LootableData", 10)) { // 10 = compound
+ return;
+ }
+ CompoundTag comp = base.getCompound("Paper.LootableData");
+ if (comp.contains("lastFill")) {
+ this.lastFill = comp.getLong("lastFill");
+ }
+ if (comp.contains("nextRefill")) {
+ this.nextRefill = comp.getLong("nextRefill");
+ }
+
+ if (comp.contains("numRefills")) {
+ this.numRefills = comp.getInt("numRefills");
+ }
+ if (comp.contains("lootedPlayers", 9)) { // 9 = list
+ ListTag list = comp.getList("lootedPlayers", 10); // 10 = compound
+ final int size = list.size();
+ if (size > 0) {
+ this.lootedPlayers = new HashMap<>(list.size());
+ }
+ for (int i = 0; i < size; i++) {
+ final CompoundTag cmp = list.getCompound(i);
+ lootedPlayers.put(cmp.getUUID("UUID"), cmp.getLong("Time"));
+ }
+ }
+ }
+ public void saveNbt(CompoundTag base) {
+ CompoundTag comp = new CompoundTag();
+ if (this.nextRefill != -1) {
+ comp.putLong("nextRefill", this.nextRefill);
+ }
+ if (this.lastFill != -1) {
+ comp.putLong("lastFill", this.lastFill);
+ }
+ if (this.numRefills != 0) {
+ comp.putInt("numRefills", this.numRefills);
+ }
+ if (this.lootedPlayers != null && !this.lootedPlayers.isEmpty()) {
+ ListTag list = new ListTag();
+ for (Map.Entry<UUID, Long> entry : this.lootedPlayers.entrySet()) {
+ CompoundTag cmp = new CompoundTag();
+ cmp.putUUID("UUID", entry.getKey());
+ cmp.putLong("Time", entry.getValue());
+ list.add(cmp);
+ }
+ comp.put("lootedPlayers", list);
+ }
+
+ if (!comp.isEmpty()) {
+ base.put("Paper.LootableData", comp);
+ }
+ }
+
+ void setPlayerLootedState(UUID player, boolean looted) {
+ if (looted && this.lootedPlayers == null) {
+ this.lootedPlayers = new HashMap<>();
+ }
+ if (looted) {
+ this.lootedPlayers.put(player, System.currentTimeMillis());
+ } else if (this.lootedPlayers != null) {
+ this.lootedPlayers.remove(player);
+ }
+ }
+
+ boolean canPlayerLoot(final UUID player, final WorldConfiguration worldConfiguration) {
+ final Long lastLooted = getLastLooted(player);
+ if (!worldConfiguration.lootables.restrictPlayerReloot || lastLooted == null) return true;
+
+ final DurationOrDisabled restrictPlayerRelootTime = worldConfiguration.lootables.restrictPlayerRelootTime;
+ if (restrictPlayerRelootTime.value().isEmpty()) return false;
+
+ return TimeUnit.SECONDS.toMillis(restrictPlayerRelootTime.value().get().seconds()) + lastLooted < System.currentTimeMillis();
+ }
+
+ boolean hasPlayerLooted(UUID player) {
+ return this.lootedPlayers != null && this.lootedPlayers.containsKey(player);
+ }
+
+ Long getLastLooted(UUID player) {
+ return lootedPlayers != null ? lootedPlayers.get(player) : null;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..9cfa5d36a6991067a3866e0d437749fafcc0158e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
@@ -0,0 +1,65 @@
+package com.destroystokyo.paper.loottable;
+
+import io.papermc.paper.util.MCUtil;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+
+public class PaperTileEntityLootableInventory implements PaperLootableBlockInventory {
+ private RandomizableContainerBlockEntity tileEntityLootable;
+
+ public PaperTileEntityLootableInventory(RandomizableContainerBlockEntity tileEntityLootable) {
+ this.tileEntityLootable = tileEntityLootable;
+ }
+
+ @Override
+ public org.bukkit.loot.LootTable getLootTable() {
+ return tileEntityLootable.lootTable != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null;
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table, long seed) {
+ setLootTable(table);
+ setSeed(seed);
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table) {
+ tileEntityLootable.lootTable = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
+ }
+
+ @Override
+ public void setSeed(long seed) {
+ tileEntityLootable.lootTableSeed = seed;
+ }
+
+ @Override
+ public long getSeed() {
+ return tileEntityLootable.lootTableSeed;
+ }
+
+ @Override
+ public PaperLootableInventoryData getLootableData() {
+ return tileEntityLootable.lootableData;
+ }
+
+ @Override
+ public RandomizableContainerBlockEntity getTileEntity() {
+ return tileEntityLootable;
+ }
+
+ @Override
+ public LootableInventory getAPILootableInventory() {
+ Level world = tileEntityLootable.getLevel();
+ if (world == null) {
+ return null;
+ }
+ return (LootableInventory) getBukkitWorld().getBlockAt(MCUtil.toLocation(world, tileEntityLootable.getBlockPos())).getState();
+ }
+
+ @Override
+ public Level getNMSWorld() {
+ return tileEntityLootable.getLevel();
+ }
+}
diff --git a/src/main/java/net/minecraft/world/RandomizableContainer.java b/src/main/java/net/minecraft/world/RandomizableContainer.java
index 22eba5982dd258e2f58a7a70fd25900364cc9448..0c80f97e74ee04e7eab24e35c752ded5586bed07 100644
--- a/src/main/java/net/minecraft/world/RandomizableContainer.java
+++ b/src/main/java/net/minecraft/world/RandomizableContainer.java
@@ -49,17 +49,29 @@ public interface RandomizableContainer extends Container {
}
+ // Paper start
+ private static net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity blockEntity(final RandomizableContainer container) {
+ return (net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity) container;
+ }
default boolean tryLoadLootTable(CompoundTag nbt) {
+ final net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity entity = blockEntity(this);
+ entity.lootableData.loadNbt(nbt);
if (nbt.contains("LootTable", 8)) {
this.setLootTable(new ResourceLocation(nbt.getString("LootTable")));
+ try { org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(entity.lootTable); } catch (IllegalArgumentException ex) { entity.lootTable = null; } // Paper - validate
this.setLootTableSeed(nbt.getLong("LootTableSeed"));
- return true;
+ return false; // Paper - always load the items, table may still remain
+ // Paper end
} else {
return false;
}
}
default boolean trySaveLootTable(CompoundTag nbt) {
+ // Paper start
+ final net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity entity = blockEntity(this);
+ entity.lootableData.saveNbt(nbt);
+ // Paper end
ResourceLocation resourceLocation = this.getLootTable();
if (resourceLocation == null) {
return false;
@@ -70,21 +82,22 @@ public interface RandomizableContainer extends Container {
nbt.putLong("LootTableSeed", l);
}
- return true;
+ return false; // Paper - always save the items, table may still remain
}
}
default void unpackLootTable(@Nullable Player player) {
+ final net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity entity = blockEntity(this); // Paper
Level level = this.getLevel();
BlockPos blockPos = this.getBlockPos();
ResourceLocation resourceLocation = this.getLootTable();
- if (resourceLocation != null && level != null && level.getServer() != null) {
+ if (entity.lootableData.shouldReplenish(player) && level != null) { // Paper
LootTable lootTable = level.getServer().getLootData().getLootTable(resourceLocation);
if (player instanceof ServerPlayer) {
CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer)player, resourceLocation);
}
- this.setLootTable((ResourceLocation)null);
+ entity.lootableData.processRefill(player); // Paper
LootParams.Builder builder = (new LootParams.Builder((ServerLevel)level)).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(blockPos));
if (player != null) {
builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player);
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index cc762d3eb68d2f8bf9529ecf07adfc343953c7a2..1b7b3114cd6ced0587a0e7e4a4c94584c72ed17f 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -236,6 +236,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
}
// Paper end
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper
private CraftEntity bukkitEntity;
public CraftEntity getBukkitEntity() {
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
index 364cfa220b5c7c5351f1eb909066bef933da2c08..6d23c39e4eadf23616080d6d08672e13b5d3c37d 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
@@ -32,6 +32,20 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
public ResourceLocation lootTable;
public long lootTableSeed;
+ // Paper start
+ {
+ this.lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperContainerEntityLootableInventory(this));
+ }
+ @Override
+ public Entity getEntity() {
+ return this;
+ }
+
+ @Override
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData getLootableData() {
+ return this.lootableData;
+ }
+ // Paper end
// CraftBukkit start
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
private int maxStack = MAX_STACK;
@@ -134,12 +148,14 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
@Override
protected void addAdditionalSaveData(CompoundTag nbt) {
super.addAdditionalSaveData(nbt);
+ this.lootableData.saveNbt(nbt); // Paper
this.addChestVehicleSaveData(nbt);
}
@Override
protected void readAdditionalSaveData(CompoundTag nbt) {
super.readAdditionalSaveData(nbt);
+ this.lootableData.loadNbt(nbt); // Paper
this.readChestVehicleSaveData(nbt);
}
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
index 7bfdffc9b3c637bd6ac8ac3eb10961abdc5b1a7a..bc3fe45d12ffc2069a03d1587b7623d31130565a 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
@@ -66,12 +66,14 @@ public class ChestBoat extends Boat implements HasCustomInventoryScreen, Contain
@Override
protected void addAdditionalSaveData(CompoundTag nbt) {
super.addAdditionalSaveData(nbt);
+ this.lootableData.saveNbt(nbt); // Paper
this.addChestVehicleSaveData(nbt);
}
@Override
protected void readAdditionalSaveData(CompoundTag nbt) {
super.readAdditionalSaveData(nbt);
+ this.lootableData.loadNbt(nbt); // Paper
this.readChestVehicleSaveData(nbt);
}
@@ -246,6 +248,20 @@ public class ChestBoat extends Boat implements HasCustomInventoryScreen, Contain
this.level().gameEvent(GameEvent.CONTAINER_CLOSE, this.position(), GameEvent.Context.of((Entity) player));
}
+ // Paper start
+ {
+ this.lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperContainerEntityLootableInventory(this));
+ }
+ @Override
+ public Entity getEntity() {
+ return this;
+ }
+
+ @Override
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData getLootableData() {
+ return this.lootableData;
+ }
+ // Paper end
// CraftBukkit start
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
private int maxStack = MAX_STACK;
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
index e0fbacd574e0c83c2e1d164ded8e9ccf4af30480..7529751afa2932fd16bc4591189b0358268a7b14 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
@@ -59,10 +59,9 @@ public interface ContainerEntity extends Container, MenuProvider {
if (this.getLootTableSeed() != 0L) {
nbt.putLong("LootTableSeed", this.getLootTableSeed());
}
- } else {
- ContainerHelper.saveAllItems(nbt, this.getItemStacks());
}
+ ContainerHelper.saveAllItems(nbt, this.getItemStacks()); // Paper - always save the items, table may still remain
}
default void readChestVehicleSaveData(CompoundTag nbt) {
@@ -70,10 +69,9 @@ public interface ContainerEntity extends Container, MenuProvider {
if (nbt.contains("LootTable", 8)) {
this.setLootTable(new ResourceLocation(nbt.getString("LootTable")));
this.setLootTableSeed(nbt.getLong("LootTableSeed"));
- } else {
- ContainerHelper.loadAllItems(nbt, this.getItemStacks());
}
+ ContainerHelper.loadAllItems(nbt, this.getItemStacks()); // Paper - always load the items, table may still remain
}
default void chestVehicleDestroyed(DamageSource source, Level world, Entity vehicle) {
@@ -96,13 +94,13 @@ public interface ContainerEntity extends Container, MenuProvider {
default void unpackChestVehicleLootTable(@Nullable Player player) {
MinecraftServer minecraftServer = this.level().getServer();
- if (this.getLootTable() != null && minecraftServer != null) {
+ if (this.getLootableData().shouldReplenish(player) && minecraftServer != null) { // Paper
LootTable lootTable = minecraftServer.getLootData().getLootTable(this.getLootTable());
if (player != null) {
CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer)player, this.getLootTable());
}
- this.setLootTable((ResourceLocation)null);
+ this.getLootableData().processRefill(player); // Paper
LootParams.Builder builder = (new LootParams.Builder((ServerLevel)this.level())).withParameter(LootContextParams.ORIGIN, this.position());
if (player != null) {
builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player);
@@ -176,4 +174,13 @@ public interface ContainerEntity extends Container, MenuProvider {
default boolean isChestVehicleStillValid(Player player) {
return !this.isRemoved() && this.position().closerThan(player.position(), 8.0D);
}
+ // Paper start
+ default Entity getEntity() {
+ throw new UnsupportedOperationException();
+ }
+
+ default com.destroystokyo.paper.loottable.PaperLootableInventoryData getLootableData() {
+ throw new UnsupportedOperationException();
+ }
+ // Paper end
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
index aa4181e59f88be04a3605352fa5ceb3e04149dd3..a7c9301cfb3e15ebea9b3ca23ce97a936f0e351c 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
@@ -17,6 +17,7 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
@Nullable
public ResourceLocation lootTable;
public long lootTableSeed;
+ public final com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperTileEntityLootableInventory(this)); // Paper
protected RandomizableContainerBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java
index 86076a9d2a3b1044c96518cbaeee66d60a8a22c6..c268513bc5719d80e1c3d73de53b85ec7f852fa9 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java
@@ -64,7 +64,7 @@ public class CraftBrushableBlock extends CraftBlockEntityState<BrushableBlockEnt
this.setLootTable(this.getLootTable(), seed);
}
- private void setLootTable(LootTable table, long seed) {
+ public void setLootTable(LootTable table, long seed) { // Paper - make public since it overrides a public method
ResourceLocation key = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
this.getSnapshot().setLootTable(key, seed);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
index 58bd3c4b328b5e792c9ed8dfcdfa0f5ddcc83092..b742d9d231bf79ed53d3fe4deaa81e64c6801c4c 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
@@ -12,8 +12,9 @@ import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest;
import org.bukkit.inventory.Inventory;
+import com.destroystokyo.paper.loottable.PaperLootableBlockInventory; // Paper
-public class CraftChest extends CraftLootable<ChestBlockEntity> implements Chest {
+public class CraftChest extends CraftLootable<ChestBlockEntity> implements Chest, PaperLootableBlockInventory { // Paper
public CraftChest(World world, ChestBlockEntity tileEntity) {
super(world, tileEntity);
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
index 2803e34bd29fd7a965093b507f11b5ee83bc5f09..f6942cb3ef1f9ef03708d4bc932ea9aeb1c13894 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
@@ -9,7 +9,7 @@ import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.loot.LootTable;
import org.bukkit.loot.Lootable;
-public abstract class CraftLootable<T extends RandomizableContainerBlockEntity> extends CraftContainer<T> implements Nameable, Lootable {
+public abstract class CraftLootable<T extends RandomizableContainerBlockEntity> extends CraftContainer<T> implements Nameable, Lootable, com.destroystokyo.paper.loottable.PaperLootableBlockInventory { // Paper
public CraftLootable(World world, T tileEntity) {
super(world, tileEntity);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
index cc3f70fafea2d5c3a878cfe3e0a2db39ae713bf6..f1844d697b91e61878ade5b922cf2a3a538365c7 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
@@ -10,8 +10,7 @@ import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.inventory.Inventory;
import org.bukkit.loot.LootTable;
-public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.ChestBoat {
-
+public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.ChestBoat, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
private final Inventory inventory;
public CraftChestBoat(CraftServer server, ChestBoat entity) {
@@ -60,7 +59,7 @@ public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.Chest
return this.getHandle().getLootTableSeed();
}
- private void setLootTable(LootTable table, long seed) {
+ public void setLootTable(LootTable table, long seed) { // Paper - change visibility since it overrides a public method
ResourceLocation newKey = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
this.getHandle().setLootTable(newKey);
this.getHandle().setLootTableSeed(seed);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
index fd42f0b20132d08039ca7735d31a61806a6b07dc..b1a708de6790bbe336202b13ab862ced78de084f 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
@@ -7,7 +7,7 @@ import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.inventory.Inventory;
@SuppressWarnings("deprecation")
-public class CraftMinecartChest extends CraftMinecartContainer implements StorageMinecart {
+public class CraftMinecartChest extends CraftMinecartContainer implements StorageMinecart, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
private final CraftInventory inventory;
public CraftMinecartChest(CraftServer server, MinecartChest entity) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
index 39427b4f284e9402663be2b160ccb5f03f8b91da..17f5684cba9d3ed22d9925d1951520cc4751dfe2 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
@@ -6,7 +6,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.inventory.Inventory;
-public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart {
+public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
private final CraftInventory inventory;
public CraftMinecartHopper(CraftServer server, MinecartHopper entity) {

View file

@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Thu, 12 May 2016 23:02:58 -0500
Subject: [PATCH] System property for disabling watchdoge
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
index b5a2cbc21165e80820d6f7e2690e6e18de54c420..e2bafc68e88c733873638ce7695b684d119f55da 100644
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
@@ -61,7 +61,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
while ( !this.stopping )
{
//
- if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.monotonicMillis() > this.lastTick + this.timeoutTime )
+ if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.monotonicMillis() > this.lastTick + this.timeoutTime && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
{
Logger log = Bukkit.getServer().getLogger();
log.log( Level.SEVERE, "------------------------------" );

View file

@ -0,0 +1,86 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 16 May 2016 20:47:41 -0400
Subject: [PATCH] Async GameProfileCache saving
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index ee751fb9580064682e650cf1c959a0e159a89bf2..e1849b879334bc9d17e6efeff061e1db6ab4ec7b 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -960,7 +960,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
} catch (java.lang.InterruptedException ignored) {} // Paper
if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) {
MinecraftServer.LOGGER.info("Saving usercache.json");
- this.getProfileCache().save();
+ this.getProfileCache().save(false); // Paper
}
// Spigot end
io.papermc.paper.chunk.system.io.RegionFileIOThread.close(true); // Paper // Paper - rewrite chunk system
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index a267ab0b217573373d7b6a1f48cadab0f431da40..772d7c1e398538b8bbbd70aedaba05199d11b358 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -242,7 +242,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
}
if (this.convertOldUsers()) {
- this.getProfileCache().save();
+ this.getProfileCache().save(false); // Paper
}
if (!OldUsersConverter.serverReadyAfterUserconversion(this)) {
diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java
index d5e83f14bb7809c8bb3c2bffe436fd7284896aff..ee43e87fca2a8ac3f63bc2f8ffcf15be373195e9 100644
--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java
+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java
@@ -118,7 +118,7 @@ public class GameProfileCache {
GameProfileCache.GameProfileInfo usercache_usercacheentry = new GameProfileCache.GameProfileInfo(profile, date);
this.safeAdd(usercache_usercacheentry);
- if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.save(); // Spigot - skip saving if disabled
+ if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.save(true); // Spigot - skip saving if disabled // Paper - async
}
private long getNextOperation() {
@@ -151,7 +151,7 @@ public class GameProfileCache {
}
if (flag && !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { // Spigot - skip saving if disabled
- this.save();
+ this.save(true); // Paper
}
return optional;
@@ -263,7 +263,7 @@ public class GameProfileCache {
return arraylist;
}
- public void save() {
+ public void save(boolean asyncSave) { // Paper
JsonArray jsonarray = new JsonArray();
DateFormat dateformat = GameProfileCache.createDateFormat();
@@ -271,6 +271,7 @@ public class GameProfileCache {
jsonarray.add(GameProfileCache.writeGameProfile(usercache_usercacheentry, dateformat));
});
String s = this.gson.toJson(jsonarray);
+ Runnable save = () -> { // Paper
try {
BufferedWriter bufferedwriter = Files.newWriter(this.file, StandardCharsets.UTF_8);
@@ -295,6 +296,14 @@ public class GameProfileCache {
} catch (IOException ioexception) {
;
}
+ // Paper start
+ };
+ if (asyncSave) {
+ io.papermc.paper.util.MCUtil.scheduleAsyncTask(save);
+ } else {
+ save.run();
+ }
+ // Paper end
}

View file

@ -0,0 +1,63 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Sun, 22 May 2016 20:20:55 -0500
Subject: [PATCH] Optional TNT doesn't move in water
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index fb16216b54eea81fceaf3edafa69b554ad01c807..90d2fa5b90d64ddb28075a50f4478b464a29a285 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -73,7 +73,7 @@ public class ServerEntity {
@Nullable
private List<SynchedEntityData.DataValue<?>> trackedDataValues;
// CraftBukkit start
- private final Set<ServerPlayerConnection> trackedPlayers;
+ final Set<ServerPlayerConnection> trackedPlayers; // Paper - private -> package
public ServerEntity(ServerLevel worldserver, Entity entity, int i, boolean flag, Consumer<Packet<?>> consumer, Set<ServerPlayerConnection> trackedPlayers) {
this.trackedPlayers = trackedPlayers;
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
index 5c3b86e2301079e775971aa4da6a8f2dc6a40d1f..d9ed22e9853eebdf6c517b41787a27a1a56a0871 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -106,6 +106,27 @@ public class PrimedTnt extends Entity implements TraceableEntity {
}
}
+ // Paper start - Optional prevent TNT from moving in water
+ if (!this.isRemoved() && this.wasTouchingWater && this.level().paperConfig().fixes.preventTntFromMovingInWater) {
+ /*
+ * Author: Jedediah Smith <jedediah@silencegreys.com>
+ */
+ // Send position and velocity updates to nearby players on every tick while the TNT is in water.
+ // This does pretty well at keeping their clients in sync with the server.
+ net.minecraft.server.level.ChunkMap.TrackedEntity ete = ((net.minecraft.server.level.ServerLevel)this.level()).getChunkSource().chunkMap.entityMap.get(this.getId());
+ if (ete != null) {
+ net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket velocityPacket = new net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket(this);
+ net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket positionPacket = new net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket(this);
+
+ ete.seenBy.stream()
+ .filter(viewer -> (viewer.getPlayer().getX() - this.getX()) * (viewer.getPlayer().getY() - this.getY()) * (viewer.getPlayer().getZ() - this.getZ()) < 16 * 16)
+ .forEach(viewer -> {
+ viewer.send(velocityPacket);
+ viewer.send(positionPacket);
+ });
+ }
+ }
+ // Paper end
}
private void explode() {
@@ -179,4 +200,11 @@ public class PrimedTnt extends Entity implements TraceableEntity {
public BlockState getBlockState() {
return (BlockState) this.entityData.get(PrimedTnt.DATA_BLOCK_STATE_ID);
}
+
+ // Paper start - Optional prevent TNT from moving in water
+ @Override
+ public boolean isPushedByFluid() {
+ return !level().paperConfig().fixes.preventTntFromMovingInWater && super.isPushedByFluid();
+ }
+ // Paper end
}

View file

@ -0,0 +1,68 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Panzer <postremus1996@googlemail.com>
Date: Mon, 23 May 2016 12:12:37 +0200
Subject: [PATCH] Faster redstone torch rapid clock removal
Only resize the the redstone torch list once, since resizing arrays / lists is costly
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 9bb380e7c8973b4728b5d4aad663af9e477dda0c..48d3da58820c1d9259bc023ddd74e9632b3f62d1 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -176,6 +176,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
private org.spigotmc.TickLimiter tileLimiter;
private int tileTickPosition;
public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
+ public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here
public CraftWorld getWorld() {
return this.world;
diff --git a/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java b/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java
index 68da47c3ec59518a4bbeb03c196ef0e7c6b5d049..6c49962e8f9e2a5fca50b33f3e3fff76fa36f907 100644
--- a/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java
@@ -24,7 +24,7 @@ public class RedstoneTorchBlock extends BaseTorchBlock {
public static final MapCodec<RedstoneTorchBlock> CODEC = simpleCodec(RedstoneTorchBlock::new);
public static final BooleanProperty LIT = BlockStateProperties.LIT;
- private static final Map<BlockGetter, List<RedstoneTorchBlock.Toggle>> RECENT_TOGGLES = new WeakHashMap();
+ // Paper - Move the mapped list to World
public static final int RECENT_TOGGLE_TIMER = 60;
public static final int MAX_RECENT_TOGGLES = 8;
public static final int RESTART_DELAY = 160;
@@ -80,11 +80,15 @@ public class RedstoneTorchBlock extends BaseTorchBlock {
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
boolean flag = this.hasNeighborSignal(world, pos, state);
- List list = (List) RedstoneTorchBlock.RECENT_TOGGLES.get(world);
-
- while (list != null && !list.isEmpty() && world.getGameTime() - ((RedstoneTorchBlock.Toggle) list.get(0)).when > 60L) {
- list.remove(0);
+ // Paper start
+ java.util.ArrayDeque<RedstoneTorchBlock.Toggle> redstoneUpdateInfos = world.redstoneUpdateInfos;
+ if (redstoneUpdateInfos != null) {
+ RedstoneTorchBlock.Toggle curr;
+ while ((curr = redstoneUpdateInfos.peek()) != null && world.getGameTime() - curr.when > 60L) {
+ redstoneUpdateInfos.poll();
+ }
}
+ // Paper end
// CraftBukkit start
org.bukkit.plugin.PluginManager manager = world.getCraftServer().getPluginManager();
@@ -160,9 +164,12 @@ public class RedstoneTorchBlock extends BaseTorchBlock {
}
private static boolean isToggledTooFrequently(Level world, BlockPos pos, boolean addNew) {
- List<RedstoneTorchBlock.Toggle> list = (List) RedstoneTorchBlock.RECENT_TOGGLES.computeIfAbsent(world, (iblockaccess) -> {
- return Lists.newArrayList();
- });
+ // Paper start
+ java.util.ArrayDeque<RedstoneTorchBlock.Toggle> list = world.redstoneUpdateInfos;
+ if (list == null) {
+ list = world.redstoneUpdateInfos = new java.util.ArrayDeque<>();
+ }
+
if (addNew) {
list.add(new RedstoneTorchBlock.Toggle(pos.immutable(), world.getGameTime()));