From 54d089bf04b43cb2957e08cdb248ae83c93002d5 Mon Sep 17 00:00:00 2001 From: filoghost Date: Sat, 31 Jul 2021 17:27:21 +0200 Subject: [PATCH] Add item pickup functionality --- .../hologram/tracking/CollisionHelper.java | 75 +++++++++++++++++++ .../hologram/tracking/ItemLineTracker.java | 16 ++++ .../plugin/hologram/tracking/LineTracker.java | 9 ++- 3 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/CollisionHelper.java diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/CollisionHelper.java b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/CollisionHelper.java new file mode 100644 index 00000000..c5446fd8 --- /dev/null +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/CollisionHelper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.plugin.hologram.tracking; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class CollisionHelper { + + private static final double PLAYER_WIDTH_RADIUS = 0.6 / 2; + private static final double PLAYER_HEIGHT_RADIUS = 1.8 / 2; + + private static final double ITEM_WIDTH_RADIUS = 0.25 / 2; + private static final double ITEM_HEIGHT_RADIUS = 0.25 / 2; + + // The server increases the player's bounding box in all directions before checking if it intersects with an item + private static final double PLAYER_GROW_WIDTH = 1; + private static final double PLAYER_GROW_HEIGHT = 0.5; + + private static final double REQUIRED_DISTANCE_X = PLAYER_WIDTH_RADIUS + PLAYER_GROW_WIDTH + ITEM_WIDTH_RADIUS; + private static final double REQUIRED_DISTANCE_Z = REQUIRED_DISTANCE_X; + private static final double REQUIRED_DISTANCE_Y = PLAYER_HEIGHT_RADIUS + PLAYER_GROW_HEIGHT + ITEM_HEIGHT_RADIUS; + + public static boolean isInPickupRange(Player player, double itemX, double itemY, double itemZ) { + /* + * Normally, the server determines if a player is picking up a dropped item + * by checking if the bounding boxes of the player and the item intersect. + * + * This can be simplified: for each direction (X, Y, Z), check if the distance between the centers of the bounding boxes + * is lower than the sum of the radius (half the length) of each box. + * + * If the condition is satisfied for all directions, the bounding boxes intersect. Visual example: + * + * Box #1 + * ._____________. + * | | + * | | Box #2 + * | * .___|_______________. + * | | | | + * |_________|___| * | + * | | + * |___________________| + * + * *------> + * Radius #1 + * + * <---------* + * Radius #2 + * + * *------------* + * Distance between centers + * + * + * In the example above, the distance between the centers is lower than the sum of the two radii, + * so the boxes collide in that direction. + */ + Location playerLocation = player.getLocation(); + + // The Y position is on lowest point of the bounding box, not in the center + double playerCenterY = playerLocation.getY() + PLAYER_HEIGHT_RADIUS; + double itemCenterY = itemY + ITEM_HEIGHT_RADIUS; + + double xDiff = Math.abs(playerLocation.getX() - itemX); + double zDiff = Math.abs(playerLocation.getZ() - itemZ); + double yDiff = Math.abs(playerCenterY - itemCenterY); + + return xDiff <= REQUIRED_DISTANCE_X + && yDiff <= REQUIRED_DISTANCE_Y + && zDiff <= REQUIRED_DISTANCE_Z; + } + +} diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/ItemLineTracker.java b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/ItemLineTracker.java index b04f9e51..5ad1ea12 100644 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/ItemLineTracker.java +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/ItemLineTracker.java @@ -9,9 +9,11 @@ import me.filoghost.holographicdisplays.common.nms.EntityID; import me.filoghost.holographicdisplays.common.nms.NMSManager; import me.filoghost.holographicdisplays.common.nms.NMSPacketList; import me.filoghost.holographicdisplays.plugin.hologram.base.BaseItemLine; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.MustBeInvokedByOverriders; +import java.util.Collection; import java.util.Objects; public class ItemLineTracker extends ClickableLineTracker { @@ -31,6 +33,20 @@ public class ItemLineTracker extends ClickableLineTracker { this.itemEntityID = nmsManager.newEntityID(); } + @MustBeInvokedByOverriders + @Override + protected void update(Collection onlinePlayers) { + super.update(onlinePlayers); + + if (spawnItemEntities && hasTrackedPlayers()) { + for (Player trackedPlayer : getTrackedPlayers()) { + if (CollisionHelper.isInPickupRange(trackedPlayer, locationX, locationY, locationZ)) { + line.onPickup(trackedPlayer); + } + } + } + } + @Override protected boolean updatePlaceholders() { return false; diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/LineTracker.java b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/LineTracker.java index 2efd2771..38c3f3c4 100644 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/LineTracker.java +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/LineTracker.java @@ -46,7 +46,8 @@ public abstract class LineTracker { lineChanged = true; } - protected final void update(Collection onlinePlayers) { + @MustBeInvokedByOverriders + protected void update(Collection onlinePlayers) { boolean sendChangesPackets = false; // First, detect the changes if the flag is on and set it off @@ -115,10 +116,14 @@ public abstract class LineTracker { protected abstract boolean shouldTrackPlayer(Player player); - private boolean hasTrackedPlayers() { + protected final boolean hasTrackedPlayers() { return !trackedPlayers.isEmpty(); } + protected final Set getTrackedPlayers() { + return trackedPlayers; + } + public final boolean isTrackedPlayer(Player player) { return trackedPlayers.contains(player); }