From 69edea75be21a3020de2dd40190afc715975d736 Mon Sep 17 00:00:00 2001 From: Jeck Date: Thu, 16 Feb 2023 05:58:17 -0800 Subject: [PATCH] Changes the value stored by PlayerBlockListener to a local identifier for the player. --- .../java/com/willfp/eco/util/BlockUtils.java | 29 ++++++++++++++++ .../java/com/willfp/eco/util/PlayerUtils.java | 33 +++++++++++++++++++ .../java/com/willfp/eco/util/ServerUtils.java | 28 ++++++++++++++++ .../kotlin/com/willfp/eco/util/BlockUtils.kt | 5 +++ .../kotlin/com/willfp/eco/util/PlayerUtils.kt | 4 +++ .../spigot/data/PlayerBlockListener.kt | 33 ++++++++++++------- 6 files changed, 120 insertions(+), 12 deletions(-) diff --git a/eco-api/src/main/java/com/willfp/eco/util/BlockUtils.java b/eco-api/src/main/java/com/willfp/eco/util/BlockUtils.java index 37f9ec425..6cf96b0a2 100644 --- a/eco-api/src/main/java/com/willfp/eco/util/BlockUtils.java +++ b/eco-api/src/main/java/com/willfp/eco/util/BlockUtils.java @@ -3,6 +3,7 @@ import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -97,6 +98,34 @@ public static boolean isPlayerPlaced(@NotNull final Block block) { PersistentDataType.INTEGER ); } + /** + * Get who placed the block (as an internal ID). + * + * @param block The block. + * @return Internal ID of placing player, or 0 if not placed by a player. + */ + public static int placedByID(@NotNull final Block block) { + Chunk chunk = block.getChunk(); + + return chunk.getPersistentDataContainer().getOrDefault( + NamespacedKeyUtils.createEcoKey(Integer.toString(block.getLocation().hashCode(), 16)), + PersistentDataType.INTEGER, + 0 + ); + } + + /** + * Get whether a specific player placed the block. + * + * @param block The block. + * @param player The player to check. + * @return If placed by that specific player. + */ + public static boolean isPlacedBy(@NotNull final Block block, @NotNull final OfflinePlayer player) { + int placed_by = placedByID(block); + int local_id = PlayerUtils.getLocalID(player); + return placed_by == local_id; + } private BlockUtils() { throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); diff --git a/eco-api/src/main/java/com/willfp/eco/util/PlayerUtils.java b/eco-api/src/main/java/com/willfp/eco/util/PlayerUtils.java index f97db394b..200f158c5 100644 --- a/eco-api/src/main/java/com/willfp/eco/util/PlayerUtils.java +++ b/eco-api/src/main/java/com/willfp/eco/util/PlayerUtils.java @@ -33,6 +33,16 @@ public final class PlayerUtils { PersistentDataKeyType.STRING, "Unknown Player" ); + /** + * The data key for saved player local IDs. + * The default value of 1 means no local ID has been assigned; this is to allow the + * gradual migration of BlockUtils isPlayerPlaced values. + */ + private static final PersistentDataKey PLAYER_LOCAL_ID = new PersistentDataKey<>( + NamespacedKeyUtils.createEcoKey("player_local_id"), + PersistentDataKeyType.INT, + 1 + ); /** * Get the audience from a player. @@ -106,6 +116,29 @@ public static String getSavedDisplayName(@NotNull final OfflinePlayer player) { return saved; } + /** + * Get local ID for a player. + * Local IDs are more compact than UUIDs, but are local to our storage backing. + * They're useful in scenarios where we want to store a player identifier per-block, + * like in BlockUtils.isPlacedBy + * + * @param player The player. + * @return The player local ID. + */ + public static Integer getLocalID(@NotNull final OfflinePlayer player) { + PlayerProfile profile = PlayerProfile.load(player); + Integer local_id = profile.read(PLAYER_LOCAL_ID); + + // If we haven't gotten a player local ID, generate one here. + if (local_id.equals(PLAYER_LOCAL_ID.getDefaultValue())) { + Integer generatedID = ServerUtils.generateLocalID(); + profile.write(PLAYER_LOCAL_ID, generatedID); + return generatedID; + } + + return local_id; + } + /** * Update the saved display name for a player. * diff --git a/eco-api/src/main/java/com/willfp/eco/util/ServerUtils.java b/eco-api/src/main/java/com/willfp/eco/util/ServerUtils.java index 2f95d9f8b..404f6077c 100644 --- a/eco-api/src/main/java/com/willfp/eco/util/ServerUtils.java +++ b/eco-api/src/main/java/com/willfp/eco/util/ServerUtils.java @@ -1,11 +1,24 @@ package com.willfp.eco.util; import com.willfp.eco.core.Eco; +import com.willfp.eco.core.data.ServerProfile; +import com.willfp.eco.core.data.keys.PersistentDataKey; +import com.willfp.eco.core.data.keys.PersistentDataKeyType; /** * Utilities / API methods for the server. */ public final class ServerUtils { + /** + * The data key on the server profile which holds the top player local id. + * The default value is 1 to allow gradual migration of BlockUtils isPlayerPlaced values. + */ + private static final PersistentDataKey TOP_LOCAL_ID = new PersistentDataKey<>( + NamespacedKeyUtils.createEcoKey("top_player_local_id"), + PersistentDataKeyType.INT, + 1 + ); + /** * Get the current server TPS. * @@ -21,6 +34,21 @@ public static double getTps() { } } + + /** + * Generates a local ID for a player by incrementing the top value. + * Local IDs are more compact than UUIDs, but are local to our storage backing. + * + * @return The player local ID. + */ + public static Integer generateLocalID() { + ServerProfile profile = ServerProfile.load(); + Integer local_id = profile.read(TOP_LOCAL_ID); + local_id += 1; + profile.write(TOP_LOCAL_ID, local_id); + return local_id; + } + private ServerUtils() { throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); } diff --git a/eco-api/src/main/kotlin/com/willfp/eco/util/BlockUtils.kt b/eco-api/src/main/kotlin/com/willfp/eco/util/BlockUtils.kt index 841c2fa1c..1a770e79d 100644 --- a/eco-api/src/main/kotlin/com/willfp/eco/util/BlockUtils.kt +++ b/eco-api/src/main/kotlin/com/willfp/eco/util/BlockUtils.kt @@ -3,7 +3,12 @@ package com.willfp.eco.util import org.bukkit.block.Block +import org.bukkit.OfflinePlayer; /** @see ArrowUtils.getBow */ val Block.isPlayerPlaced: Boolean get() = BlockUtils.isPlayerPlaced(this) + +/** @see BlockUtils.IsPlacedBy */ +fun Block.isPlacedBy(player: OfflinePlayer) = + BlockUtils.isPlacedBy(this,player) diff --git a/eco-api/src/main/kotlin/com/willfp/eco/util/PlayerUtils.kt b/eco-api/src/main/kotlin/com/willfp/eco/util/PlayerUtils.kt index e6877a17c..503b736e8 100644 --- a/eco-api/src/main/kotlin/com/willfp/eco/util/PlayerUtils.kt +++ b/eco-api/src/main/kotlin/com/willfp/eco/util/PlayerUtils.kt @@ -12,6 +12,10 @@ import org.bukkit.entity.Player val OfflinePlayer.savedDisplayName: String get() = PlayerUtils.getSavedDisplayName(this) +/** @see PlayerUtils.getLocalID */ +val OfflinePlayer.localID: Int + get() = PlayerUtils.getLocalID(this) + /** @see PlayerUtils.getAudience */ fun Player.asAudience(): Audience = PlayerUtils.getAudience(this) diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/PlayerBlockListener.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/PlayerBlockListener.kt index ba6265e61..07a723753 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/PlayerBlockListener.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/PlayerBlockListener.kt @@ -2,6 +2,7 @@ package com.willfp.eco.internal.spigot.data import com.willfp.eco.core.EcoPlugin import com.willfp.eco.util.BlockUtils +import com.willfp.eco.util.PlayerUtils import org.bukkit.Location import org.bukkit.block.Block import org.bukkit.event.EventHandler @@ -21,15 +22,17 @@ class PlayerBlockListener( @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) fun onPlace(event: BlockPlaceEvent) { val block = event.blockPlaced + val player = event.player - writeKey(block) + writeKey(block, PlayerUtils.getLocalID(player)) } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) fun onPlace(event: BlockMultiPlaceEvent) { val block = event.blockPlaced + val player = event.player - writeKey(block) + writeKey(block, PlayerUtils.getLocalID(player)) } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -53,11 +56,14 @@ class PlayerBlockListener( @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) fun onExtend(event: BlockPistonExtendEvent) { val locs = mutableListOf() + val placers = mutableListOf() val toRemove = mutableListOf() for (block in event.blocks) { - if (BlockUtils.isPlayerPlaced(block)) { + val placedBy = BlockUtils.placedByID(block) + if (placedBy != 0) { locs.add(block.getRelative(event.direction).location) + placers.add(placedBy) toRemove.add(block.location) } } @@ -67,8 +73,8 @@ class PlayerBlockListener( removeKey(loc) } - for (loc in locs) { - writeKey(loc) + for (idx in locs.indices) { + writeKey(locs[idx], placers[idx]) } } } @@ -76,11 +82,14 @@ class PlayerBlockListener( @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) fun onRetract(event: BlockPistonRetractEvent) { val locs = mutableListOf() + val placers = mutableListOf() val toRemove = mutableListOf() for (block in event.blocks) { - if (BlockUtils.isPlayerPlaced(block)) { + val placedBy = BlockUtils.placedByID(block) + if (placedBy != 0) { locs.add(block.getRelative(event.direction).location) + placers.add(placedBy) toRemove.add(block.location) } } @@ -90,22 +99,22 @@ class PlayerBlockListener( removeKey(loc) } - for (loc in locs) { - writeKey(loc) + for (idx in locs.indices) { + writeKey(locs[idx], placers[idx]) } } } - private fun writeKey(block: Block) { - writeKey(block.location) + private fun writeKey(block: Block, placerID: Int) { + writeKey(block.location, placerID) } - private fun writeKey(location: Location) { + private fun writeKey(location: Location, placerID: Int) { val loc = location.hashCode().toString(16) location.chunk.persistentDataContainer.set( plugin.createNamespacedKey(loc.lowercase()), PersistentDataType.INTEGER, - 1 + placerID ) }