Skip to content

Commit e616498

Browse files
authored
Add Vault block API (#12068)
1 parent a06179a commit e616498

File tree

4 files changed

+360
-2
lines changed

4 files changed

+360
-2
lines changed

build-data/paper.at

+5
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,11 @@ public net.minecraft.world.level.block.entity.trialspawner.TrialSpawner stateAcc
628628
public net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData currentMobs
629629
public net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData detectedPlayers
630630
public net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData nextSpawnData
631+
public net.minecraft.world.level.block.entity.vault.VaultBlockEntity serverData
632+
public net.minecraft.world.level.block.entity.vault.VaultServerData getRewardedPlayers()Ljava/util/Set;
633+
public net.minecraft.world.level.block.entity.vault.VaultServerData pauseStateUpdatingUntil(J)V
634+
public net.minecraft.world.level.block.entity.vault.VaultServerData stateUpdatingResumesAt()J
635+
public net.minecraft.world.level.block.entity.vault.VaultSharedData getConnectedPlayers()Ljava/util/Set;
631636
public net.minecraft.world.level.block.state.BlockBehaviour getMenuProvider(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/MenuProvider;
632637
public net.minecraft.world.level.block.state.BlockBehaviour hasCollision
633638
public net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase destroySpeed
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,184 @@
11
package org.bukkit.block;
22

3+
import org.bukkit.World;
4+
import org.bukkit.inventory.ItemStack;
5+
import org.bukkit.loot.LootTable;
6+
import org.jetbrains.annotations.Unmodifiable;
7+
import org.jspecify.annotations.NullMarked;
8+
import org.jspecify.annotations.Nullable;
9+
import java.util.Collection;
10+
import java.util.Set;
11+
import java.util.UUID;
12+
313
/**
4-
* Represents a captured state of a trial spawner.
14+
* Represents a captured state of a vault.
515
*/
16+
@NullMarked
617
public interface Vault extends TileState {
18+
/**
19+
* Gets the range in blocks at which this vault will become active when a player is near.
20+
*
21+
* @return This vault's activation range.
22+
*/
23+
double getActivationRange();
24+
25+
/**
26+
* Sets the range in blocks at which the vault will become active when a player is near.
27+
*
28+
* @param activationRange The new activation range.
29+
* @throws IllegalArgumentException if the new range is not a number, or if the new range is more than {@link #getDeactivationRange()}.
30+
*/
31+
void setActivationRange(double activationRange);
32+
33+
/**
34+
* Gets the range in blocks at which this vault will become inactive when a player is not near.
35+
*
36+
* @return This vault's deactivation range.
37+
*/
38+
double getDeactivationRange();
39+
40+
/**
41+
* Sets the range in blocks at which this vault will become inactive when a player is not near.
42+
*
43+
* @param deactivationRange The new deactivation range
44+
* @throws IllegalArgumentException if the new range is not a number, or if the new range is less than {@link #getActivationRange()}.
45+
*/
46+
void setDeactivationRange(double deactivationRange);
47+
48+
/**
49+
* Gets the {@link ItemStack} that players must use to unlock this vault.
50+
*
51+
* @return The item that players must use to unlock this vault.
52+
*/
53+
ItemStack getKeyItem();
54+
55+
/**
56+
* Sets the {@link ItemStack} that players must use to unlock this vault.
57+
*
58+
* @param key The key item.
59+
*/
60+
void setKeyItem(ItemStack key);
61+
62+
/**
63+
* Gets the {@link LootTable} that this vault will select rewards from.
64+
*
65+
* @return The loot table.
66+
*/
67+
LootTable getLootTable();
68+
69+
/**
70+
* Sets the {@link LootTable} that this vault will select rewards from.
71+
*
72+
* @param lootTable The new loot table.
73+
*/
74+
void setLootTable(LootTable lootTable);
75+
76+
/**
77+
* Gets the loot table that this vault will display items from.
78+
* <p>
79+
* Falls back to the regular {@link #getLootTable() loot table} if unset.
80+
*
81+
* @return The {@link LootTable} that will be used to display items.
82+
*/
83+
@Nullable
84+
LootTable getDisplayedLootTable();
85+
86+
/**
87+
* Sets the loot table that this vault will display items from.
88+
*
89+
* @param lootTable The new loot table to display, or {@code null} to clear this display override.
90+
*/
91+
void setDisplayedLootTable(@Nullable LootTable lootTable);
92+
93+
/**
94+
* Gets the next time (in {@link World#getGameTime() game time}) that this vault block will be updated/ticked at.
95+
*
96+
* @return The next time that this vault block will be updated/ticked at.
97+
* @see World#getGameTime()
98+
*/
99+
long getNextStateUpdateTime();
100+
101+
/**
102+
* Sets the next time that this vault block will be updated/ticked at, if this value is less than or equals to the current
103+
* {@link World#getGameTime()}, then it will be updated in the first possible tick.
104+
*
105+
* @param nextStateUpdateTime The next time that this vault block will be updated/ticked at.
106+
* @see World#getGameTime()
107+
*/
108+
void setNextStateUpdateTime(long nextStateUpdateTime);
109+
110+
/**
111+
* Gets the players who have used a key on this vault and unlocked it.
112+
*
113+
* @return An unmodifiable collection of player uuids.
114+
*
115+
* @apiNote Only the most recent 128 player UUIDs will be stored by vault blocks.
116+
*/
117+
@Unmodifiable
118+
Collection<UUID> getRewardedPlayers();
119+
120+
/**
121+
* Adds a player as rewarded for this vault.
122+
*
123+
* @param playerUUID The player's uuid.
124+
* @return {@code true} if this player was previously not rewarded, and has been added as a result of this operation.
125+
*
126+
* @apiNote Only the most recent 128 player UUIDs will be stored by vault blocks. Attempting to add more will result in
127+
* the first player UUID being removed.
128+
*/
129+
boolean addRewardedPlayer(UUID playerUUID);
130+
131+
/**
132+
* Removes a player as rewarded for this vault, allowing them to use a {@link #getKeyItem() key item} again to receive rewards.
133+
*
134+
* @param playerUUID The player's uuid.
135+
* @return {@code true} if this player was previously rewarded, and has been removed as a result of this operation.
136+
*
137+
* @apiNote Only the most recent 128 player UUIDs will be stored by vault blocks.
138+
*/
139+
boolean removeRewardedPlayer(UUID playerUUID);
140+
141+
/**
142+
* Returns whether a given player has already been rewarded by this vault.
143+
*
144+
* @param playerUUID The player's uuid.
145+
* @return Whether this player was previously rewarded by this vault.
146+
*/
147+
boolean hasRewardedPlayer(UUID playerUUID);
148+
149+
/**
150+
* Gets an unmodifiable set of "connected players"; players who are inside this vault's activation range and who have not received rewards yet.
151+
*
152+
* @apiNote Vaults will only periodically scan for nearby players, so it may take until the next {@link #getNextStateUpdateTime() update time} for this
153+
* collection to be updated upon a player entering its range.
154+
*
155+
* @return An unmodifiable set of connected player uuids.
156+
*/
157+
@Unmodifiable
158+
Set<UUID> getConnectedPlayers();
159+
160+
/**
161+
* Returns whether a given player is currently connected to this vault.
162+
*
163+
* @param playerUUID the player's uuid
164+
* @return {@code true} if this player is currently connected to this vault.
165+
*
166+
* @see #getConnectedPlayers()
167+
*/
168+
boolean hasConnectedPlayer(UUID playerUUID);
169+
170+
/**
171+
* Gets the item currently being displayed inside this vault. Displayed items will automatically cycle between random items from the {@link #getDisplayedLootTable()}
172+
* or {@link #getLootTable()} loot tables while this vault is active.
173+
*
174+
* @return The item currently being displayed inside this vault.
175+
*/
176+
ItemStack getDisplayedItem();
177+
178+
/**
179+
* Sets the item to display inside this vault until the next cycle.
180+
*
181+
* @param displayedItem The item to display
182+
*/
183+
void setDisplayedItem(ItemStack displayedItem);
7184
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--- a/net/minecraft/world/level/block/entity/vault/VaultServerData.java
2+
+++ b/net/minecraft/world/level/block/entity/vault/VaultServerData.java
3+
@@ -66,7 +_,12 @@
4+
5+
@VisibleForTesting
6+
public void addToRewardedPlayers(Player player) {
7+
- this.rewardedPlayers.add(player.getUUID());
8+
+ // Paper start - Vault API
9+
+ addToRewardedPlayers(player.getUUID());
10+
+ }
11+
+ public boolean addToRewardedPlayers(final java.util.UUID player) {
12+
+ final boolean removed = this.rewardedPlayers.add(player);
13+
+ // Paper end - Vault API
14+
if (this.rewardedPlayers.size() > 128) {
15+
Iterator<UUID> iterator = this.rewardedPlayers.iterator();
16+
if (iterator.hasNext()) {
17+
@@ -76,6 +_,7 @@
18+
}
19+
20+
this.markChanged();
21+
+ return removed; // Paper - Vault API
22+
}
23+
24+
public long stateUpdatingResumesAt() {
25+
@@ -131,4 +_,15 @@
26+
public float ejectionProgress() {
27+
return this.totalEjectionsNeeded == 1 ? 1.0F : 1.0F - Mth.inverseLerp((float)this.getItemsToEject().size(), 1.0F, (float)this.totalEjectionsNeeded);
28+
}
29+
+
30+
+ // Paper start - Vault API
31+
+ public boolean removeFromRewardedPlayers(final UUID uuid) {
32+
+ if (this.rewardedPlayers.remove(uuid)) {
33+
+ this.markChanged();
34+
+ return true;
35+
+ }
36+
+
37+
+ return false;
38+
+ }
39+
+ // Paper end - Vault API
40+
}

paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftVault.java

+137-1
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,33 @@
11
package org.bukkit.craftbukkit.block;
22

3+
import com.google.common.base.Preconditions;
4+
import com.google.common.collect.ImmutableSet;
5+
import net.minecraft.resources.ResourceKey;
36
import net.minecraft.world.level.block.entity.vault.VaultBlockEntity;
7+
import net.minecraft.world.level.block.entity.vault.VaultConfig;
48
import org.bukkit.Location;
59
import org.bukkit.World;
610
import org.bukkit.block.Vault;
11+
import org.bukkit.craftbukkit.CraftLootTable;
12+
import org.bukkit.craftbukkit.inventory.CraftItemStack;
13+
import org.bukkit.inventory.ItemStack;
14+
import org.bukkit.loot.LootTable;
15+
import org.jetbrains.annotations.Unmodifiable;
16+
import org.jspecify.annotations.NullMarked;
17+
import org.jspecify.annotations.Nullable;
18+
import java.util.Collection;
19+
import java.util.Optional;
20+
import java.util.Set;
21+
import java.util.UUID;
722

23+
@NullMarked
824
public class CraftVault extends CraftBlockEntityState<VaultBlockEntity> implements Vault {
925

1026
public CraftVault(World world, VaultBlockEntity tileEntity) {
1127
super(world, tileEntity);
1228
}
1329

14-
protected CraftVault(CraftVault state, Location location) {
30+
protected CraftVault(CraftVault state, @Nullable Location location) {
1531
super(state, location);
1632
}
1733

@@ -24,4 +40,124 @@ public CraftVault copy() {
2440
public CraftVault copy(Location location) {
2541
return new CraftVault(this, location);
2642
}
43+
44+
@Override
45+
public double getActivationRange() {
46+
return this.getSnapshot().getConfig().activationRange();
47+
}
48+
49+
@Override
50+
public void setActivationRange(final double activationRange) {
51+
Preconditions.checkArgument(Double.isFinite(activationRange), "activation range must not be NaN or infinite");
52+
Preconditions.checkArgument(activationRange <= this.getDeactivationRange(), "New activation range (%s) must be less or equal to deactivation range (%s)", activationRange, this.getDeactivationRange());
53+
54+
final VaultConfig config = this.getSnapshot().getConfig();
55+
this.getSnapshot().setConfig(new VaultConfig(config.lootTable(), activationRange, config.deactivationRange(), config.keyItem(), config.overrideLootTableToDisplay()));
56+
}
57+
58+
@Override
59+
public double getDeactivationRange() {
60+
return this.getSnapshot().getConfig().deactivationRange();
61+
}
62+
63+
@Override
64+
public void setDeactivationRange(final double deactivationRange) {
65+
Preconditions.checkArgument(Double.isFinite(deactivationRange), "deactivation range must not be NaN or infinite");
66+
Preconditions.checkArgument(deactivationRange >= this.getActivationRange(), "New deactivation range (%s) must be more or equal to activation range (%s)", deactivationRange, this.getActivationRange());
67+
68+
final VaultConfig config = this.getSnapshot().getConfig();
69+
this.getSnapshot().setConfig(new VaultConfig(config.lootTable(), config.activationRange(), deactivationRange, config.keyItem(), config.overrideLootTableToDisplay()));
70+
}
71+
72+
@Override
73+
public ItemStack getKeyItem() {
74+
return this.getSnapshot().getConfig().keyItem().asBukkitCopy();
75+
}
76+
77+
@Override
78+
public void setKeyItem(final ItemStack key) {
79+
Preconditions.checkArgument(key != null, "key must not be null");
80+
81+
final VaultConfig config = this.getSnapshot().getConfig();
82+
this.getSnapshot().setConfig(new VaultConfig(config.lootTable(), config.activationRange(), config.deactivationRange(), CraftItemStack.asNMSCopy(key), config.overrideLootTableToDisplay()));
83+
}
84+
85+
@Override
86+
public LootTable getLootTable() {
87+
return CraftLootTable.minecraftToBukkit(this.getSnapshot().getConfig().lootTable());
88+
}
89+
90+
@Override
91+
public void setLootTable(final LootTable lootTable) {
92+
final ResourceKey<net.minecraft.world.level.storage.loot.LootTable> lootTableKey = CraftLootTable.bukkitToMinecraft(lootTable);
93+
Preconditions.checkArgument(lootTableKey != null, "lootTable must not be null");
94+
95+
final VaultConfig config = this.getSnapshot().getConfig();
96+
this.getSnapshot().setConfig(new VaultConfig(lootTableKey, config.activationRange(), config.deactivationRange(), config.keyItem(), config.overrideLootTableToDisplay()));
97+
}
98+
99+
@Override
100+
public @Nullable LootTable getDisplayedLootTable() {
101+
return this.getSnapshot().getConfig().overrideLootTableToDisplay().map(CraftLootTable::minecraftToBukkit).orElse(null);
102+
}
103+
104+
@Override
105+
public void setDisplayedLootTable(final @Nullable LootTable lootTable) {
106+
final VaultConfig config = this.getSnapshot().getConfig();
107+
108+
this.getSnapshot().setConfig(new VaultConfig(config.lootTable(), config.activationRange(), config.deactivationRange(), config.keyItem(), Optional.ofNullable(CraftLootTable.bukkitToMinecraft(lootTable))));
109+
}
110+
111+
@Override
112+
public long getNextStateUpdateTime() {
113+
return this.getSnapshot().serverData.stateUpdatingResumesAt();
114+
}
115+
116+
@Override
117+
public void setNextStateUpdateTime(final long nextStateUpdateTime) {
118+
this.getSnapshot().serverData.pauseStateUpdatingUntil(nextStateUpdateTime);
119+
}
120+
121+
@Override
122+
public @Unmodifiable Collection<UUID> getRewardedPlayers() {
123+
return ImmutableSet.copyOf(this.getSnapshot().serverData.getRewardedPlayers());
124+
}
125+
126+
@Override
127+
public boolean addRewardedPlayer(final UUID playerUUID) {
128+
Preconditions.checkArgument(playerUUID != null, "playerUUID must not be null");
129+
return this.getSnapshot().serverData.addToRewardedPlayers(playerUUID);
130+
}
131+
132+
@Override
133+
public boolean removeRewardedPlayer(final UUID playerUUID) {
134+
Preconditions.checkArgument(playerUUID != null, "playerUUID must not be null");
135+
return this.getSnapshot().serverData.removeFromRewardedPlayers(playerUUID);
136+
}
137+
138+
@Override
139+
public boolean hasRewardedPlayer(final UUID playerUUID) {
140+
return this.getSnapshot().serverData.getRewardedPlayers().contains(playerUUID);
141+
}
142+
143+
@Override
144+
public @Unmodifiable Set<UUID> getConnectedPlayers() {
145+
return ImmutableSet.copyOf(this.getSnapshot().getSharedData().getConnectedPlayers());
146+
}
147+
148+
@Override
149+
public boolean hasConnectedPlayer(final UUID playerUUID) {
150+
return this.getSnapshot().getSharedData().getConnectedPlayers().contains(playerUUID);
151+
}
152+
153+
@Override
154+
public ItemStack getDisplayedItem() {
155+
return CraftItemStack.asBukkitCopy(this.getSnapshot().getSharedData().getDisplayItem());
156+
}
157+
158+
@Override
159+
public void setDisplayedItem(final ItemStack displayedItem) {
160+
Preconditions.checkArgument(displayedItem != null, "displayedItem must not be null");
161+
this.getSnapshot().getSharedData().setDisplayItem(CraftItemStack.asNMSCopy(displayedItem));
162+
}
27163
}

0 commit comments

Comments
 (0)