diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/HologramOwner.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/HologramOwner.java index ff1baee9c..a1b539afd 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/HologramOwner.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/HologramOwner.java @@ -1,12 +1,15 @@ package io.github.thebusybiscuit.slimefun4.core.attributes; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.bukkit.Location; import org.bukkit.block.Block; +import org.bukkit.entity.ArmorStand; import org.bukkit.util.Vector; import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; +import io.github.thebusybiscuit.slimefun4.core.services.holograms.HologramsService; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.HologramProjector; @@ -16,18 +19,53 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.HologramPr * @author TheBusyBiscuit * * @see HologramProjector + * @see HologramsService * */ public interface HologramOwner extends ItemAttribute { + /** + * This will update the hologram text for the given {@link Block}. + * + * @param b + * The {@link Block} to which the hologram belongs + * + * @param text + * The nametag for the hologram + */ default void updateHologram(@Nonnull Block b, @Nonnull String text) { Location loc = b.getLocation().add(getHologramOffset()); + SlimefunPlugin.getHologramsService().updateHologram(loc, hologram -> { hologram.setCustomName(ChatColors.color(text)); hologram.setCustomNameVisible(true); }); } + @Nullable + default ArmorStand getHologram(@Nonnull Block b, boolean createIfNoneExists) { + Location loc = b.getLocation().add(getHologramOffset()); + return SlimefunPlugin.getHologramsService().getHologram(loc, createIfNoneExists); + } + + /** + * This will remove the hologram for the given {@link Block}. + * + * @param b + * The {@link Block} to which the hologram blocks + */ + default void removeHologram(@Nonnull Block b) { + Location loc = b.getLocation().add(getHologramOffset()); + SlimefunPlugin.getHologramsService().removeHologram(loc); + } + + /** + * This returns the offset of the hologram as a {@link Vector}. + * This offset is applied to {@link Block#getLocation()} when spawning + * the hologram. + * + * @return The hologram offset + */ @Nonnull default Vector getHologramOffset() { return new Vector(0.5, 0.75, 0.5); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNet.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNet.java index ba0d14a10..fef648831 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNet.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNet.java @@ -17,8 +17,8 @@ import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.slimefun4.api.network.Network; import io.github.thebusybiscuit.slimefun4.api.network.NetworkComponent; +import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; -import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram; import me.mrCookieSlime.Slimefun.api.BlockStorage; /** @@ -36,7 +36,7 @@ import me.mrCookieSlime.Slimefun.api.BlockStorage; * @author DNx5 * */ -public class CargoNet extends AbstractItemNetwork { +public class CargoNet extends AbstractItemNetwork implements HologramOwner { private static final int RANGE = 5; private static final int TICK_DELAY = SlimefunPlugin.getCfg().getInt("networks.cargo-ticker-delay"); @@ -142,16 +142,16 @@ public class CargoNet extends AbstractItemNetwork { public void tick(Block b) { if (!regulator.equals(b.getLocation())) { - SimpleHologram.update(b, "&4Multiple Cargo Regulators connected"); + updateHologram(b, "&4Multiple Cargo Regulators connected"); return; } super.tick(); if (connectorNodes.isEmpty() && terminusNodes.isEmpty()) { - SimpleHologram.update(b, "&cNo Cargo Nodes found"); + updateHologram(b, "&cNo Cargo Nodes found"); } else { - SimpleHologram.update(b, "&7Status: &a&lONLINE"); + updateHologram(b, "&7Status: &a&lONLINE"); // Skip ticking if the threshold is not reached. The delay is not same as minecraft tick, // but it's based on 'custom-ticker-delay' config. diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java index 0e659e474..8ce46472d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java @@ -20,10 +20,10 @@ import io.github.thebusybiscuit.slimefun4.api.network.Network; import io.github.thebusybiscuit.slimefun4.api.network.NetworkComponent; import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent; import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetProvider; +import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; -import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.api.BlockStorage; @@ -41,7 +41,7 @@ import me.mrCookieSlime.Slimefun.api.BlockStorage; * @see EnergyNetComponentType * */ -public class EnergyNet extends Network { +public class EnergyNet extends Network implements HologramOwner { private static final int RANGE = 6; @@ -116,7 +116,7 @@ public class EnergyNet extends Network { AtomicLong timestamp = new AtomicLong(SlimefunPlugin.getProfiler().newEntry()); if (!regulator.equals(b.getLocation())) { - SimpleHologram.update(b, "&4Multiple Energy Regulators connected"); + updateHologram(b, "&4Multiple Energy Regulators connected"); SlimefunPlugin.getProfiler().closeEntry(b.getLocation(), SlimefunItems.ENERGY_REGULATOR.getItem(), timestamp.get()); return; } @@ -124,7 +124,7 @@ public class EnergyNet extends Network { super.tick(); if (connectorNodes.isEmpty() && terminusNodes.isEmpty()) { - SimpleHologram.update(b, "&4No Energy Network found"); + updateHologram(b, "&4No Energy Network found"); } else { int supply = tickAllGenerators(timestamp::getAndAdd) + tickAllCapacitors(); int remainingEnergy = supply; @@ -258,10 +258,10 @@ public class EnergyNet extends Network { private void updateHologram(@Nonnull Block b, double supply, double demand) { if (demand > supply) { String netLoss = NumberUtils.getCompactDouble(demand - supply); - SimpleHologram.update(b, "&4&l- &c" + netLoss + " &7J &e\u26A1"); + updateHologram(b, "&4&l- &c" + netLoss + " &7J &e\u26A1"); } else { String netGain = NumberUtils.getCompactDouble(supply - demand); - SimpleHologram.update(b, "&2&l+ &a" + netGain + " &7J &e\u26A1"); + updateHologram(b, "&2&l+ &a" + netGain + " &7J &e\u26A1"); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/HologramsService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/HologramsService.java deleted file mode 100644 index ff68d8b82..000000000 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/HologramsService.java +++ /dev/null @@ -1,138 +0,0 @@ -package io.github.thebusybiscuit.slimefun4.core.services; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.function.Consumer; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataType; -import org.bukkit.plugin.Plugin; - -import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition; -import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; - -/** - * This service is responsible for handling holograms. - * This includes error management when something goes wrong. - * - * @author TheBusyBiscuit - * - * @see HologramOwner - */ -public class HologramsService { - - /** - * The radius in which we scan for holograms. - */ - private static final double RADIUS = 0.45; - - /** - * The {@link NamespacedKey} used to store data on a hologram - */ - private final NamespacedKey persistentDataKey; - - /** - * Our cache to save {@link Entity} lookups - */ - private final Map entityCache = new HashMap<>(); - - public HologramsService(@Nonnull Plugin plugin) { - // Null-Validation is performed in the NamespacedKey constructor - persistentDataKey = new NamespacedKey(plugin, "hologram_id"); - } - - @Nullable - public ArmorStand getHologram(@Nonnull Location loc, boolean createIfNoneExists) { - Validate.notNull(loc, "Location cannot be null"); - - BlockPosition position = new BlockPosition(loc); - UUID uuid = entityCache.get(position); - - if (uuid != null) { - Entity entity = Bukkit.getEntity(uuid); - - if (entity instanceof ArmorStand) { - return (ArmorStand) entity; - } - } - - Collection holograms = loc.getWorld().getNearbyEntities(loc, RADIUS, RADIUS, RADIUS, this::isHologram); - - for (Entity n : holograms) { - if (n instanceof ArmorStand) { - PersistentDataContainer container = n.getPersistentDataContainer(); - - if (container.has(persistentDataKey, PersistentDataType.LONG)) { - // Check if it is ours or a different one. - if (container.get(persistentDataKey, PersistentDataType.LONG).equals(position.getPosition())) { - return (ArmorStand) n; - } - } else { - // Set a persistent tag to re-identify the correct hologram later - container.set(persistentDataKey, PersistentDataType.LONG, position.getPosition()); - return (ArmorStand) n; - } - } - } - - if (createIfNoneExists) { - // Spawn a new ArmorStand - ArmorStand hologram = (ArmorStand) loc.getWorld().spawnEntity(loc, EntityType.ARMOR_STAND); - - // Set a persistent tag to re-identify the correct hologram later - PersistentDataContainer container = hologram.getPersistentDataContainer(); - container.set(persistentDataKey, PersistentDataType.LONG, position.getPosition()); - - hologram.setSilent(true); - hologram.setMarker(true); - hologram.setAI(false); - hologram.setGravity(false); - - return hologram; - } else { - return null; - } - } - - public boolean removeHologram(@Nonnull Location loc) { - Validate.notNull(loc, "Location cannot be null"); - - ArmorStand hologram = getHologram(loc, false); - - if (hologram != null) { - hologram.remove(); - return true; - } else { - return false; - } - } - - private boolean isHologram(@Nonnull Entity n) { - if (n instanceof ArmorStand) { - ArmorStand armorstand = (ArmorStand) n; - return armorstand.isValid() && armorstand.isSilent() && armorstand.isMarker() && !armorstand.hasAI() && !armorstand.hasGravity(); - } else { - return false; - } - } - - public void updateHologram(@Nonnull Location loc, @Nonnull Consumer consumer) { - Validate.notNull(loc, "Location cannot be null"); - Validate.notNull(consumer, "Callbacks must not be null"); - - consumer.accept(getHologram(loc, true)); - } - -} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/holograms/CachedArmorStand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/holograms/CachedArmorStand.java new file mode 100644 index 000000000..e49703e1f --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/holograms/CachedArmorStand.java @@ -0,0 +1,79 @@ +package io.github.thebusybiscuit.slimefun4.core.services.holograms; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.bukkit.Bukkit; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; + +/** + * This represents an {@link ArmorStand} or hologram that can expire. + * + * @author TheBusyBiscuit + * + */ +class CachedArmorStand { + + /** + * This is the minimum duration after which the {@link CachedArmorStand} will expire. + */ + private static final long EXPIRES_AFTER = TimeUnit.MINUTES.toMillis(10); + + /** + * The {@link UUID} of the {@link ArmorStand}. + */ + private final UUID uniqueId; + + /** + * The timestamp of when the {@link ArmorStand} was last accessed. + */ + private long lastAccess; + + /** + * This creates a new {@link CachedArmorStand} for the given {@link UUID}. + * + * @param uniqueId + * The {@link UUID} of the corresponding {@link ArmorStand} + */ + public CachedArmorStand(@Nonnull UUID uniqueId) { + this.uniqueId = uniqueId; + this.lastAccess = System.currentTimeMillis(); + } + + /** + * This returns the corresponding {@link ArmorStand} + * and also updates the "lastAccess" timestamp. + *

+ * If the {@link ArmorStand} was removed, it will return null. + * + * @return The {@link ArmorStand} or null. + */ + @Nullable + public ArmorStand getArmorStand() { + Entity n = Bukkit.getEntity(uniqueId); + + if (n instanceof ArmorStand && n.isValid()) { + this.lastAccess = System.currentTimeMillis(); + return (ArmorStand) n; + } else { + this.lastAccess = 0; + return null; + } + } + + /** + * This returns whether this {@link CachedArmorStand} has expired. + * The armorstand will expire if the last access has been more than 10 + * minutes ago. + * + * @return Whether this {@link CachedArmorStand} has expired + */ + public boolean isExpired() { + return System.currentTimeMillis() - lastAccess > EXPIRES_AFTER; + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/holograms/HologramsService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/holograms/HologramsService.java new file mode 100644 index 000000000..59b1b5049 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/holograms/HologramsService.java @@ -0,0 +1,236 @@ +package io.github.thebusybiscuit.slimefun4.core.services.holograms; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.function.Consumer; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.Server; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.Plugin; + +import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition; +import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; + +/** + * This service is responsible for handling holograms. + * This includes error management when something goes wrong. + * + * @author TheBusyBiscuit + * + * @see HologramOwner + */ +public class HologramsService { + + /** + * The radius in which we scan for holograms + */ + private static final double RADIUS = 0.45; + + /** + * The frequency at which to purge + */ + private static final long PURGE_RATE = 60L * 20L; + + /** + * Our {@link Plugin} instance + */ + private final Plugin plugin; + + /** + * The {@link NamespacedKey} used to store data on a hologram + */ + private final NamespacedKey persistentDataKey; + + /** + * Our cache to save {@link Entity} lookups + */ + private final Map cache = new HashMap<>(); + + /** + * This constructs a new {@link HologramsService}. + * + * @param plugin + * Our {@link Plugin} instance + */ + public HologramsService(@Nonnull Plugin plugin) { + this.plugin = plugin; + + // Null-Validation is performed in the NamespacedKey constructor + persistentDataKey = new NamespacedKey(plugin, "hologram_id"); + } + + /** + * This will start the {@link HologramsService} and schedule a repeating + * purge-task. + */ + public void start() { + plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, this::purge, PURGE_RATE, PURGE_RATE); + } + + /** + * This purges all expired {@link CachedArmorStand CachedArmorStands}. + */ + private void purge() { + Iterator iterator = cache.values().iterator(); + + while (iterator.hasNext()) { + if (iterator.next().isExpired()) { + iterator.remove(); + } + } + } + + /** + * This returns the hologram associated with the given {@link Location}. + * If createIfNoneExists is set to true a new {@link ArmorStand} will be spawned + * if no existing one could be found. + * + * @param loc + * The {@link Location} + * @param createIfNoneExists + * Whether to create a new {@link ArmorStand} if none was found + * + * @return The existing (or newly created) hologram + */ + @Nullable + public ArmorStand getHologram(@Nonnull Location loc, boolean createIfNoneExists) { + Validate.notNull(loc, "Location cannot be null"); + + if (!Bukkit.isPrimaryThread()) { + throw new UnsupportedOperationException("A hologram cannot be accessed asynchronously."); + } + + BlockPosition position = new BlockPosition(loc); + CachedArmorStand cachedEntity = cache.get(position); + + // Check if the ArmorStand was cached + if (cachedEntity != null) { + ArmorStand armorstand = cachedEntity.getArmorStand(); + + // If the Entity still exists, return it + if (armorstand != null) { + return armorstand; + } + } + + // Scan all nearby entities which could be possible holograms + Collection holograms = loc.getWorld().getNearbyEntities(loc, RADIUS, RADIUS, RADIUS, this::isHologram); + + for (Entity n : holograms) { + if (n instanceof ArmorStand) { + PersistentDataContainer container = n.getPersistentDataContainer(); + + if (container.has(persistentDataKey, PersistentDataType.LONG)) { + // Check if it is ours or a different one. + if (container.get(persistentDataKey, PersistentDataType.LONG).equals(position.getPosition())) { + return (ArmorStand) n; + } + } else { + // Set a persistent tag to re-identify the correct hologram later + container.set(persistentDataKey, PersistentDataType.LONG, position.getPosition()); + return (ArmorStand) n; + } + } + } + + if (createIfNoneExists) { + // Spawn a new ArmorStand + ArmorStand hologram = (ArmorStand) loc.getWorld().spawnEntity(loc, EntityType.ARMOR_STAND); + + // Set a persistent tag to re-identify the correct hologram later + PersistentDataContainer container = hologram.getPersistentDataContainer(); + container.set(persistentDataKey, PersistentDataType.LONG, position.getPosition()); + + hologram.setSilent(true); + hologram.setMarker(true); + hologram.setAI(false); + hologram.setGravity(false); + + return hologram; + } else { + return null; + } + } + + /** + * This removes the hologram at that given {@link Location}. + *

+ * This method must be executed on the main {@link Server} {@link Thread}. + * + * @param loc + * The {@link Location} + * + * @return Whether the hologram could be removed, false if the hologram does not exist or was already removed + */ + public boolean removeHologram(@Nonnull Location loc) { + Validate.notNull(loc, "Location cannot be null"); + + if (Bukkit.isPrimaryThread()) { + ArmorStand hologram = getHologram(loc, false); + + if (hologram != null) { + hologram.remove(); + return true; + } else { + return false; + } + } else { + throw new UnsupportedOperationException("You cannot remove a hologram asynchronously."); + } + } + + /** + * This updates the hologram. + * You can use it to set the nametag or other properties. + *

+ * This method must be executed on the main {@link Server} {@link Thread}. + * + * @param loc + * The {@link Location} + * @param consumer + * The callback to run + */ + public void updateHologram(@Nonnull Location loc, @Nonnull Consumer consumer) { + Validate.notNull(loc, "Location must not be null"); + Validate.notNull(consumer, "Callbacks must not be null"); + + if (Bukkit.isPrimaryThread()) { + consumer.accept(getHologram(loc, true)); + } else { + SlimefunPlugin.runSync(() -> consumer.accept(getHologram(loc, true))); + } + } + + /** + * This checks if a given {@link Entity} is an {@link ArmorStand} + * and whether it has the correct attributes to be considered a hologram. + * + * @param n + * The {@link Entity} to check + * + * @return Whether this could be a hologram + */ + private boolean isHologram(@Nonnull Entity n) { + if (n instanceof ArmorStand) { + ArmorStand armorstand = (ArmorStand) n; + return armorstand.isValid() && armorstand.isSilent() && armorstand.isMarker() && !armorstand.hasAI() && !armorstand.hasGravity(); + } else { + return false; + } + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/holograms/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/holograms/package-info.java new file mode 100644 index 000000000..d081769ee --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/holograms/package-info.java @@ -0,0 +1,5 @@ +/** + * This package contains everything related to the + * {@link io.github.thebusybiscuit.slimefun4.core.services.holograms.HologramsService}. + */ +package io.github.thebusybiscuit.slimefun4.core.services.holograms; \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java index fedb40544..fb36a0da2 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java @@ -43,7 +43,6 @@ import io.github.thebusybiscuit.slimefun4.core.services.BackupService; import io.github.thebusybiscuit.slimefun4.core.services.BlockDataService; import io.github.thebusybiscuit.slimefun4.core.services.CustomItemDataService; import io.github.thebusybiscuit.slimefun4.core.services.CustomTextureService; -import io.github.thebusybiscuit.slimefun4.core.services.HologramsService; import io.github.thebusybiscuit.slimefun4.core.services.LocalizationService; import io.github.thebusybiscuit.slimefun4.core.services.MetricsService; import io.github.thebusybiscuit.slimefun4.core.services.MinecraftRecipeService; @@ -51,6 +50,7 @@ import io.github.thebusybiscuit.slimefun4.core.services.PerWorldSettingsService; import io.github.thebusybiscuit.slimefun4.core.services.PermissionsService; import io.github.thebusybiscuit.slimefun4.core.services.UpdaterService; import io.github.thebusybiscuit.slimefun4.core.services.github.GitHubService; +import io.github.thebusybiscuit.slimefun4.core.services.holograms.HologramsService; import io.github.thebusybiscuit.slimefun4.core.services.profiler.SlimefunProfiler; import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientAltar; import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientPedestal; @@ -348,6 +348,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { // Starting our tasks autoSavingService.start(this, config.getInt("options.auto-save-delay-in-minutes")); + hologramsService.start(); ticker.start(this); // Loading integrations diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java index be0a3496b..508d70ddd 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java @@ -2,15 +2,17 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.cargo; import java.util.Optional; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.ChatColor; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent; +import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet; -import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; @@ -19,13 +21,14 @@ import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; -public class CargoManager extends SlimefunItem { +public class CargoManager extends SlimefunItem implements HologramOwner { + @ParametersAreNonnullByDefault public CargoManager(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(category, item, recipeType, recipe); registerBlockHandler(getId(), (p, b, tool, reason) -> { - SimpleHologram.remove(b); + removeHologram(b); return true; }); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java index 6a3711aa4..f8735c063 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java @@ -8,9 +8,9 @@ import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent; +import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet; -import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; @@ -28,14 +28,14 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; * @see EnergyNetComponent * */ -public class EnergyRegulator extends SlimefunItem { +public class EnergyRegulator extends SlimefunItem implements HologramOwner { @ParametersAreNonnullByDefault public EnergyRegulator(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(category, item, recipeType, recipe); SlimefunItem.registerBlockHandler(getId(), (p, b, stack, reason) -> { - SimpleHologram.remove(b); + removeHologram(b); return true; }); } @@ -46,7 +46,7 @@ public class EnergyRegulator extends SlimefunItem { @Override public void onPlayerPlace(BlockPlaceEvent e) { - SimpleHologram.update(e.getBlock(), "&7Connecting..."); + updateHologram(e.getBlock(), "&7Connecting..."); } }; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/NetherStarReactor.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/NetherStarReactor.java index 227ecbde7..5e7763058 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/NetherStarReactor.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/NetherStarReactor.java @@ -14,7 +14,6 @@ import org.bukkit.potion.PotionEffectType; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; -import io.github.thebusybiscuit.slimefun4.utils.holograms.ReactorHologram; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel; @@ -44,7 +43,8 @@ public abstract class NetherStarReactor extends Reactor { @Override public void extraTick(@Nonnull Location l) { SlimefunPlugin.runSync(() -> { - ArmorStand hologram = ReactorHologram.getArmorStand(l, true); + ArmorStand hologram = getHologram(l.getBlock(), true); + for (Entity entity : hologram.getNearbyEntities(5, 5, 5)) { if (entity instanceof LivingEntity && entity.isValid()) { ((LivingEntity) entity).addPotionEffect(new PotionEffect(PotionEffectType.WITHER, 60, 1)); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java index 46aa72c8f..012a8ead2 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java @@ -23,14 +23,13 @@ import io.github.thebusybiscuit.cscorelib2.item.CustomItem; import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; import io.github.thebusybiscuit.slimefun4.api.events.AsyncReactorProcessCompleteEvent; import io.github.thebusybiscuit.slimefun4.api.events.ReactorExplodeEvent; +import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.items.cargo.ReactorAccessPort; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.AbstractEnergyProvider; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; -import io.github.thebusybiscuit.slimefun4.utils.holograms.ReactorHologram; -import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram; import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.Slimefun.Lists.RecipeType; @@ -56,7 +55,7 @@ import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow; * @see NetherStarReactor * */ -public abstract class Reactor extends AbstractEnergyProvider { +public abstract class Reactor extends AbstractEnergyProvider implements HologramOwner { public static Map processing = new HashMap<>(); public static Map progress = new HashMap<>(); @@ -118,7 +117,7 @@ public abstract class Reactor extends AbstractEnergyProvider { progress.remove(b.getLocation()); processing.remove(b.getLocation()); - SimpleHologram.remove(b); + removeHologram(b); return true; }); @@ -332,7 +331,7 @@ public abstract class Reactor extends AbstractEnergyProvider { Bukkit.getPluginManager().callEvent(event); BlockStorage.getInventory(l).close(); - SimpleHologram.remove(l.getBlock()); + removeHologram(l.getBlock()); }); explosionsQueue.remove(l); @@ -427,14 +426,14 @@ public abstract class Reactor extends AbstractEnergyProvider { for (int slot : getCoolantSlots()) { if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), coolant, true, false)) { menu.consumeItem(slot); - ReactorHologram.update(reactor, "&b\u2744 &7100%"); + updateHologram(reactor.getBlock(), "&b\u2744 &7100%"); return true; } } return false; } else { - ReactorHologram.update(reactor, "&b\u2744 &7" + getPercentage(timeleft, processing.get(reactor).getTicks()) + "%"); + updateHologram(reactor.getBlock(), "&b\u2744 &7" + getPercentage(timeleft, processing.get(reactor).getTicks()) + "%"); } return true; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java index ca0cc1162..0000cb448 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java @@ -14,11 +14,11 @@ import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.item.CustomItem; import io.github.thebusybiscuit.slimefun4.api.geo.GEOResource; +import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; -import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction; import me.mrCookieSlime.Slimefun.Lists.RecipeType; @@ -30,7 +30,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset; -public class GEOMiner extends AContainer implements RecipeDisplayItem { +public class GEOMiner extends AContainer implements RecipeDisplayItem, HologramOwner { private static final int[] BORDER = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 26, 27, 35, 36, 44, 45, 53 }; private static final int[] OUTPUT_BORDER = { 19, 20, 21, 22, 23, 24, 25, 28, 34, 37, 43, 46, 47, 48, 49, 50, 51, 52 }; @@ -42,7 +42,7 @@ public class GEOMiner extends AContainer implements RecipeDisplayItem { addItemHandler(onPlace()); registerBlockHandler(getId(), (p, b, stack, reason) -> { - SimpleHologram.remove(b); + removeHologram(b); BlockMenu inv = BlockStorage.getInventory(b); @@ -61,7 +61,7 @@ public class GEOMiner extends AContainer implements RecipeDisplayItem { @Override public void onPlayerPlace(BlockPlaceEvent e) { - SimpleHologram.update(e.getBlock(), "&7Idling..."); + updateHologram(e.getBlock(), "&7Idling..."); } }; } @@ -156,7 +156,7 @@ public class GEOMiner extends AContainer implements RecipeDisplayItem { processing.remove(b); } } else if (!BlockStorage.hasChunkInfo(b.getWorld(), b.getX() >> 4, b.getZ() >> 4)) { - SimpleHologram.update(b, "&4GEO-Scan required!"); + updateHologram(b, "&4GEO-Scan required!"); } else { start(b, inv); } @@ -168,7 +168,7 @@ public class GEOMiner extends AContainer implements RecipeDisplayItem { OptionalInt optional = SlimefunPlugin.getGPSNetwork().getResourceManager().getSupplies(resource, b.getWorld(), b.getX() >> 4, b.getZ() >> 4); if (!optional.isPresent()) { - SimpleHologram.update(b, "&4GEO-Scan required!"); + updateHologram(b, "&4GEO-Scan required!"); return; } @@ -183,13 +183,13 @@ public class GEOMiner extends AContainer implements RecipeDisplayItem { processing.put(b, r); progress.put(b, r.getTicks()); SlimefunPlugin.getGPSNetwork().getResourceManager().setSupplies(resource, b.getWorld(), b.getX() >> 4, b.getZ() >> 4, supplies - 1); - SimpleHologram.update(b, "&7Mining: &r" + resource.getName()); + updateHologram(b, "&7Mining: &r" + resource.getName()); return; } } } - SimpleHologram.update(b, "&7Finished"); + updateHologram(b, "&7Finished"); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/ReactorHologram.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/ReactorHologram.java deleted file mode 100644 index fc2762c16..000000000 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/ReactorHologram.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.thebusybiscuit.slimefun4.utils.holograms; - -import java.util.Collection; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import org.bukkit.Location; -import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Entity; - -import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; - -public final class ReactorHologram { - - private ReactorHologram() {} - - @Nullable - public static ArmorStand getArmorStand(@Nonnull Location reactor, boolean createIfNoneExists) { - Location l = new Location(reactor.getWorld(), reactor.getX() + 0.5, reactor.getY() + 0.7, reactor.getZ() + 0.5); - Collection holograms = l.getWorld().getNearbyEntities(l, 0.2, 0.2, 0.2, ReactorHologram::isPossibleHologram); - - for (Entity n : holograms) { - if (n instanceof ArmorStand) { - return (ArmorStand) n; - } - } - - if (!createIfNoneExists) { - return null; - } - - ArmorStand hologram = SimpleHologram.create(l); - hologram.setCustomNameVisible(false); - hologram.setCustomName(null); - return hologram; - } - - private static boolean isPossibleHologram(@Nonnull Entity n) { - if (n instanceof ArmorStand) { - ArmorStand armorstand = (ArmorStand) n; - return armorstand.isValid() && armorstand.isSilent() && armorstand.isMarker() && !armorstand.hasGravity(); - } else { - return false; - } - - } - - public static void update(@Nonnull Location l, @Nonnull String name) { - SlimefunPlugin.runSync(() -> { - ArmorStand hologram = getArmorStand(l, true); - - hologram.setCustomNameVisible(true); - hologram.setCustomName(ChatColors.color(name)); - }); - } -} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/SimpleHologram.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/SimpleHologram.java index 84f0f01ce..4354660ea 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/SimpleHologram.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/SimpleHologram.java @@ -12,14 +12,18 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; +import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; /** * This utility class provides a few static methods for modifying a simple Text-based Hologram. * + * @deprecated Please use the interface {@link HologramOwner} instead + * * @author TheBusyBiscuit * */ +@Deprecated public final class SimpleHologram { private SimpleHologram() {}