diff --git a/src/main/java/net/voltexstudios/applicationLobby/ApplicationLobby.java b/src/main/java/net/voltexstudios/applicationLobby/ApplicationLobby.java new file mode 100644 index 0000000..27feeb5 --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/ApplicationLobby.java @@ -0,0 +1,87 @@ +package net.voltexstudios.applicationLobby; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.voltexstudios.applicationLobby.commands.HologramCommand; +import net.voltexstudios.applicationLobby.commands.SetSpawnCommand; +import net.voltexstudios.applicationLobby.commands.SpawnCommand; +import net.voltexstudios.applicationLobby.holograms.HologramData; +import net.voltexstudios.applicationLobby.holograms.HologramDataUtil; +import net.voltexstudios.applicationLobby.holograms.HologramService; +import net.voltexstudios.applicationLobby.listener.PlayerListener; +import net.voltexstudios.applicationLobby.util.EyeTrace; +import net.voltexstudios.applicationLobby.util.SimpleLocation; +import net.voltexstudios.applicationLobby.util.SpawnUtil; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +public final class ApplicationLobby extends JavaPlugin { + + public static final TextComponent PREFIX = Component.text("§8[§6ApplicationLobby§8] §7"); + + private static ApplicationLobby instance; + private final Map eyeTraces = new HashMap<>(); + private Location spawnLocation; + private HologramData hologramData; + + @Override + public void onEnable() { + // Plugin startup logic + instance = this; + + registerListeners(); + registerCommands(); + + SimpleLocation simpleLocation = SpawnUtil.getSpawnLocation(); + if(simpleLocation != null) { + spawnLocation = simpleLocation.toLocation(); + } else { + spawnLocation = Bukkit.getWorlds().getFirst().getSpawnLocation(); + } + + hologramData = HologramDataUtil.loadHologramData(); + if(hologramData == null) { + hologramData = new HologramData(new HashSet<>()); + HologramDataUtil.saveHologramData(); + } + new HologramService(hologramData.getHolograms()); + + } + + @Override + public void onDisable() { + // Plugin shutdown logic + } + + private void registerListeners() { + Bukkit.getPluginManager().registerEvents(new PlayerListener(), this); + } + + private void registerCommands() { + + HologramCommand hologramCommand = new HologramCommand(); + getCommand("hologram").setExecutor(hologramCommand); + getCommand("hologram").setTabCompleter(hologramCommand); + + getCommand("setSpawn").setExecutor(new SetSpawnCommand()); + getCommand("spawn").setExecutor(new SpawnCommand()); + } + + public static ApplicationLobby getInstance() { + return instance; + } + + public Location getSpawnLocation() { + return spawnLocation; + } + + public Map getEyeTraces() { + return eyeTraces; + } +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/commands/HologramCommand.java b/src/main/java/net/voltexstudios/applicationLobby/commands/HologramCommand.java new file mode 100644 index 0000000..ed6a588 --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/commands/HologramCommand.java @@ -0,0 +1,112 @@ +package net.voltexstudios.applicationLobby.commands; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; + +import net.voltexstudios.applicationLobby.ApplicationLobby; +import net.voltexstudios.applicationLobby.holograms.Hologram; +import net.voltexstudios.applicationLobby.holograms.HologramDataUtil; +import net.voltexstudios.applicationLobby.holograms.HologramService; +import net.voltexstudios.applicationLobby.holograms.HologramType; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Interaction; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; +import java.util.StringJoiner; + +public class HologramCommand implements CommandExecutor, TabCompleter { + + private static final int INTERACTION_ENTITY_RANGE = 5; + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, @NotNull String[] args) { + + if (!sender.hasPermission("applicationlobby.hologram")) { + sender.sendMessage( + ApplicationLobby.PREFIX + .append(Component.text("You do not have permission to use this command!").color(NamedTextColor.RED)) + ); + return false; + } + + if (args.length > 3) { + if (args[0].equalsIgnoreCase("create")) { + + if (!(sender instanceof Player player)) { + sender.sendMessage( + ApplicationLobby.PREFIX + .append(Component.text("Only players can use this command!").color(NamedTextColor.RED)) + ); + return false; + } + + Entity entity = player.getTargetEntity(INTERACTION_ENTITY_RANGE); + if (entity == null || !entity.getType().equals(EntityType.INTERACTION)) { + player.sendMessage( + ApplicationLobby.PREFIX + .append(Component.text("You must be looking at an interaction entity to use this command!").color(NamedTextColor.RED)) + ); + return false; + } + + Interaction interaction = (Interaction) entity; + + HologramType type = HologramType.valueOf(args[1]); + String name = args[2]; + StringJoiner dataJoiner = new StringJoiner(" "); + for (int i = 3; i < args.length; i++) { + dataJoiner.add(args[i]); + } + Hologram hologram = HologramService.getInstance().createHologram(type, name, interaction.getUniqueId(), dataJoiner.toString()); + if (hologram == null) { + sender.sendMessage(ApplicationLobby.PREFIX.append(Component.text("Hologram creation failed!").color(NamedTextColor.RED))); + return false; + } + + HologramDataUtil.saveHologramData(); + + sender.sendMessage(ApplicationLobby.PREFIX.append(Component.text("Hologram created!").color(NamedTextColor.GREEN))); + return true; + } + } + + if (args.length == 1) { + if (args[0].equalsIgnoreCase("list")) { + sender.sendMessage(ApplicationLobby.PREFIX.append(Component.text("Holograms:").color(NamedTextColor.GRAY))); + HologramService.getInstance().getHolograms().forEach(hologram -> { + sender.sendMessage(ApplicationLobby.PREFIX.append(Component.text("Name: " + hologram.getName() + " Type: " + hologram.getType().name()).color(NamedTextColor.GRAY))); + }); + return true; + } + } + + return false; + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { + if (strings.length == 1) { + return List.of("create", "delete", "list"); + } + if (strings.length == 2) { + if (strings[0].equalsIgnoreCase("create")) { + return Arrays.stream(HologramType.values()).toList().stream().map(Enum::name).toList(); + } + else if (strings[0].equalsIgnoreCase("delete")) { + List hologramNames = HologramService.getInstance().getHolograms().stream().map(Hologram::getName).toList(); + hologramNames.add("all"); + return hologramNames; + } + } + return null; + } +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/commands/SetSpawnCommand.java b/src/main/java/net/voltexstudios/applicationLobby/commands/SetSpawnCommand.java new file mode 100644 index 0000000..625f7ff --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/commands/SetSpawnCommand.java @@ -0,0 +1,37 @@ +package net.voltexstudios.applicationLobby.commands; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.voltexstudios.applicationLobby.ApplicationLobby; +import net.voltexstudios.applicationLobby.util.SpawnUtil; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class SetSpawnCommand implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, @NotNull String[] args) { + + if (!sender.hasPermission("applicationlobby.setspawn")) { + sender.sendMessage( + ApplicationLobby.PREFIX + .append(Component.text("You do not have permission to use this command!").color(NamedTextColor.RED)) + ); + return false; + } + + if (!(sender instanceof Player player)) { + sender.sendMessage( + ApplicationLobby.PREFIX + .append(Component.text("Only players can use this command!").color(NamedTextColor.RED)) + ); + return false; + } + + SpawnUtil.setSpawnLocation(player.getLocation()); + player.sendMessage(ApplicationLobby.PREFIX.append(Component.text("Spawn location set!"))); + return true; + } +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/commands/SpawnCommand.java b/src/main/java/net/voltexstudios/applicationLobby/commands/SpawnCommand.java new file mode 100644 index 0000000..c84c255 --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/commands/SpawnCommand.java @@ -0,0 +1,27 @@ +package net.voltexstudios.applicationLobby.commands; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.voltexstudios.applicationLobby.ApplicationLobby; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class SpawnCommand implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, @NotNull String[] args) { + + if (!(sender instanceof Player player)) { + sender.sendMessage( + ApplicationLobby.PREFIX + .append(Component.text("Only players can use this command!").color(NamedTextColor.RED)) + ); + return false; + } + + player.teleport(ApplicationLobby.getInstance().getSpawnLocation()); + return false; + } +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/holograms/Hologram.java b/src/main/java/net/voltexstudios/applicationLobby/holograms/Hologram.java new file mode 100644 index 0000000..04c7a7f --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/holograms/Hologram.java @@ -0,0 +1,62 @@ +package net.voltexstudios.applicationLobby.holograms; + +import net.voltexstudios.applicationLobby.holograms.actions.Clickable; +import net.voltexstudios.applicationLobby.holograms.actions.Hoverable; +import org.bukkit.Bukkit; +import org.bukkit.entity.Display; +import org.bukkit.entity.Interaction; +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public abstract class Hologram implements Hoverable, Clickable { + + protected final Map displayMap = new HashMap<>(); + private final String name; + private final UUID interactionUUID; + private final HologramType type; + + public Hologram(String name, HologramType type, UUID interactionUUID) { + this.name = name; + this.type = type; + this.interactionUUID = interactionUUID; + } + + public abstract void addDisplay(UUID PlayerUUID); + + protected Player getPlayer(UUID playerUUID) { + return Bukkit.getServer().getPlayer(playerUUID); + } + + protected Interaction getInteraction(Player player) { + return (Interaction) player.getWorld().getEntity(interactionUUID); + } + + protected Display getDisplay(Player player) { + return (Display) player.getWorld().getEntity(displayMap.get(player.getUniqueId())); + } + + public void removeDisplay(UUID playerUUID) { + Display display = (Display) Bukkit.getServer().getEntity(displayMap.get(playerUUID)); + if (display == null) { + return; + } + + display.remove(); + displayMap.remove(playerUUID); + } + + public UUID getInteractionUUID() { + return interactionUUID; + } + + public String getName() { + return name; + } + + public HologramType getType() { + return type; + } +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/holograms/HologramData.java b/src/main/java/net/voltexstudios/applicationLobby/holograms/HologramData.java new file mode 100644 index 0000000..1b842e5 --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/holograms/HologramData.java @@ -0,0 +1,16 @@ +package net.voltexstudios.applicationLobby.holograms; + +import java.util.Set; + +public class HologramData { + + public final Set holograms; + + public HologramData(Set holograms) { + this.holograms = holograms; + } + + public Set getHolograms() { + return holograms; + } +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/holograms/HologramDataUtil.java b/src/main/java/net/voltexstudios/applicationLobby/holograms/HologramDataUtil.java new file mode 100644 index 0000000..e797059 --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/holograms/HologramDataUtil.java @@ -0,0 +1,37 @@ +package net.voltexstudios.applicationLobby.holograms; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; + +public class HologramDataUtil { + + private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + private static final String npcDataPath = "plugins/ApplicationLobby/npcData.json"; + + public static void saveHologramData() { + File folder = new File("plugins/ApplicationLobby"); + + if(!folder.exists()) { + folder.mkdirs(); + } + + try(FileWriter fileWriter = new FileWriter(npcDataPath)) { + gson.toJson(HologramService.getInstance().getHologramData(), fileWriter); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static HologramData loadHologramData() { + try(FileReader fileReader = new FileReader(npcDataPath)) { + return gson.fromJson(fileReader, HologramData.class); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/holograms/HologramService.java b/src/main/java/net/voltexstudios/applicationLobby/holograms/HologramService.java new file mode 100644 index 0000000..e54f97e --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/holograms/HologramService.java @@ -0,0 +1,146 @@ +package net.voltexstudios.applicationLobby.holograms; + +import net.voltexstudios.applicationLobby.holograms.types.TextHologram; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Interaction; +import org.bukkit.entity.Player; + +import java.util.*; + +public final class HologramService { + + private static HologramService instance; + + private final Set holograms; + private final Map hovering; + + public HologramService(Set holograms) { + instance = this; + this.holograms = holograms; + this.hovering = new HashMap<>(); + } + + public Hologram createHologram(HologramType type, String name, UUID interactionUUID, String data) { + if (interactionExists(interactionUUID)) { + return null; + } + + Hologram hologram = null; + switch (type) { + case TEXT: + hologram = createTextHologram(name, interactionUUID, data); + break; + } + + if (hologram != null) { + addHologram(hologram); + } + return hologram; + } + + private void addHologram(Hologram hologram) { + holograms.add(hologram); + + for (Player player : Bukkit.getServer().getOnlinePlayers()) { + hologram.addDisplay(player.getUniqueId()); + } + } + + private TextHologram createTextHologram(String name, UUID interactionUUID, String text) { + return new TextHologram(name, interactionUUID, text); + } + + public void handleHologramHover(Player player, Entity entity) { + if (entity == null) { + if (isHovering(player)) { + getHovering(player).onUnhover(player); + hovering.remove(player.getUniqueId()); + } + return; + } + + if (!(entity instanceof Interaction)) { + return; + } + + Hologram hologram = getHologram(entity.getUniqueId()); + + if (isHovering(player)) { + Hologram lastHovering = getHovering(player); + if (lastHovering.getInteractionUUID().equals(hologram.getInteractionUUID())) { + return; + } + } + + hovering.put(player.getUniqueId(), hologram); + hologram.onHover(player); + } + + public void handleHologramClick(Player player, Hologram hologram) { + if (hologram == null) { + return; + } + + hologram.onClick(player); + } + + public Location getClosestHologramLocation(Player player) { + return holograms.stream() + .map(Hologram::getInteractionUUID) + .map(interactionUUID -> (Interaction) player.getWorld().getEntity(interactionUUID)) + .filter(Objects::nonNull) + .min(Comparator.comparingDouble(interaction -> interaction.getLocation().distance(player.getLocation()))) + .map(Entity::getLocation) + .orElse(null); + } + + public void addPlayerDisplays(Player player) { + holograms.forEach(hologram -> hologram.addDisplay(player.getUniqueId())); + } + + public void removePlayerDisplays(Player player) { + holograms.forEach(hologram -> hologram.removeDisplay(player.getUniqueId())); + } + + public Hologram getHologram(UUID interactionUUID) { + return holograms.stream().filter(hologram -> hologram.getInteractionUUID().equals(interactionUUID)).findFirst().orElse(null); + } + + public boolean isHologram(UUID interactionUUID) { + return holograms.stream().anyMatch(hologram -> hologram.getInteractionUUID().equals(interactionUUID)); + } + + public boolean isHovering(Player player) { + return hovering.containsKey(player.getUniqueId()); + } + + public Hologram getHovering(Player player) { + return hovering.get(player.getUniqueId()); + } + + public void removeHovering(Player player) { + hovering.remove(player.getUniqueId()); + } + + private boolean interactionExists(UUID interactionUUID) { + return holograms.stream().anyMatch(hologram -> hologram.getInteractionUUID().equals(interactionUUID)); + } + + public Set getHolograms() { + return holograms; + } + + public HologramData getHologramData() { + return new HologramData(holograms); + } + + public static HologramService getInstance() { + if(instance == null) { + instance = new HologramService(new HashSet<>()); + } + return instance; + } + +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/holograms/HologramType.java b/src/main/java/net/voltexstudios/applicationLobby/holograms/HologramType.java new file mode 100644 index 0000000..706a877 --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/holograms/HologramType.java @@ -0,0 +1,6 @@ +package net.voltexstudios.applicationLobby.holograms; + +public enum HologramType { + TEXT, + ITEM +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/holograms/actions/Clickable.java b/src/main/java/net/voltexstudios/applicationLobby/holograms/actions/Clickable.java new file mode 100644 index 0000000..0c4c674 --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/holograms/actions/Clickable.java @@ -0,0 +1,7 @@ +package net.voltexstudios.applicationLobby.holograms.actions; + +import org.bukkit.entity.Player; + +public interface Clickable { + void onClick(Player player); +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/holograms/actions/Hoverable.java b/src/main/java/net/voltexstudios/applicationLobby/holograms/actions/Hoverable.java new file mode 100644 index 0000000..1d4dbbe --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/holograms/actions/Hoverable.java @@ -0,0 +1,9 @@ +package net.voltexstudios.applicationLobby.holograms.actions; + +import org.bukkit.entity.Player; + +public interface Hoverable { + + void onHover(Player player); + void onUnhover(Player player); +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/holograms/types/TextHologram.java b/src/main/java/net/voltexstudios/applicationLobby/holograms/types/TextHologram.java new file mode 100644 index 0000000..56505e4 --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/holograms/types/TextHologram.java @@ -0,0 +1,103 @@ +package net.voltexstudios.applicationLobby.holograms.types; + +import net.kyori.adventure.text.Component; +import net.voltexstudios.applicationLobby.ApplicationLobby; +import net.voltexstudios.applicationLobby.holograms.Hologram; +import net.voltexstudios.applicationLobby.holograms.HologramType; +import org.bukkit.Color; +import org.bukkit.entity.*; +import org.bukkit.util.Transformation; +import org.bukkit.util.Vector; + +import java.util.UUID; + +public class TextHologram extends Hologram { + + private static final float HOVER_SCALING = 1.3f; + + private final String text; + + public TextHologram(String name, UUID interactionUUID, String text) { + super(name, HologramType.TEXT, interactionUUID); + this.text = text; + } + + @Override + public void addDisplay(UUID playerUUID) { + Player player = getPlayer(playerUUID); + if (player == null) { + return; + } + + Interaction interaction = getInteraction(player); + if (interaction == null) { + return; + } + + TextDisplay display = createDisplay(player, new Vector(-0.05, -1, 0)); + player.showEntity(ApplicationLobby.getInstance(), display); + + displayMap.put(playerUUID, display.getUniqueId()); + } + + private TextDisplay createDisplay(Player player, Vector offset) { + TextDisplay display = (TextDisplay) player.getWorld().spawnEntity(getInteraction(player).getLocation().clone() + .setDirection(new Vector(1, 0, 0)) + .add(offset), + EntityType.TEXT_DISPLAY); + display.setAlignment(TextDisplay.TextAlignment.CENTER); + display.setBillboard(TextDisplay.Billboard.FIXED); + display.setDefaultBackground(false); + display.setBackgroundColor(Color.fromARGB(0, 0, 0, 0)); + display.text(Component.text(text)); + display.setVisibleByDefault(false); + + Transformation transformation = display.getTransformation(); + transformation.getScale().mul(8.313f, 8.313f, 8.313f); + display.setTransformation(transformation); + + return display; + } + + @Override + public void onClick(Player player) { + //Do nothing for now + player.sendMessage("Klicked " + getName()); + } + + @Override + public void onHover(Player player) { + player.playSound(player, "custom:hover_sound", 0.5f, 1); + + Display display = getDisplay(player); + if (display == null) { + player.sendMessage( + "§cAn error occurred while trying to hover over the NPC. Please try again later." + ); + return; + } + + Transformation transformation = display.getTransformation(); + transformation.getScale().mul(HOVER_SCALING, HOVER_SCALING, HOVER_SCALING); + display.setInterpolationDelay(0); + display.setInterpolationDuration(3); // smooth the scaling + display.setTransformation(transformation); + } + + @Override + public void onUnhover(Player player) { + Display display = getDisplay(player); + if (display == null) { + player.sendMessage( + "§cAn error occurred while trying to hover over the NPC. Please try again later." + ); + return; + } + + Transformation transformation = display.getTransformation(); + transformation.getScale().div(HOVER_SCALING, HOVER_SCALING, HOVER_SCALING); + display.setInterpolationDelay(0); + display.setInterpolationDuration(3); // smooth the scaling + display.setTransformation(transformation); + } +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/listener/PlayerListener.java b/src/main/java/net/voltexstudios/applicationLobby/listener/PlayerListener.java new file mode 100644 index 0000000..347e9da --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/listener/PlayerListener.java @@ -0,0 +1,100 @@ +package net.voltexstudios.applicationLobby.listener; + +import net.voltexstudios.applicationLobby.holograms.Hologram; +import net.voltexstudios.applicationLobby.holograms.HologramService; +import net.voltexstudios.applicationLobby.util.PlayerUtil; +import org.bukkit.entity.Display; +import org.bukkit.entity.Interaction; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntitySpawnEvent; +import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.player.*; +import org.bukkit.util.RayTraceResult; + +public class PlayerListener implements Listener { + + @EventHandler + public void onFoodLevelChange(FoodLevelChangeEvent event) { + event.setCancelled(true); + } + + @EventHandler + public void onDamage(EntityDamageEvent event) { + event.setCancelled(true); + } + + @EventHandler + public void onEntitySpawn(EntitySpawnEvent event) { + if (!(event.getEntity() instanceof Display)) { + event.setCancelled(true); + } + } + + @EventHandler + public void onJoin(PlayerJoinEvent event) { + PlayerUtil.handlePlayerJoin(event.getPlayer()); + } + + @EventHandler + public void onLeave(PlayerQuitEvent event) { + PlayerUtil.handlePlayerQuit(event.getPlayer()); + } + + @EventHandler + public void onTexturepackLoad(PlayerResourcePackStatusEvent event) { + if (event.getStatus().equals(PlayerResourcePackStatusEvent.Status.SUCCESSFULLY_LOADED)) { + HologramService.getInstance().addPlayerDisplays(event.getPlayer()); + } + } + + @EventHandler + public void onEntityInteract(PlayerInteractEntityEvent event) { + if (event.getRightClicked() instanceof Interaction interaction) { + event.setCancelled(true); + + Hologram hologram = HologramService.getInstance().getHologram(interaction.getUniqueId()); + if (hologram == null) { + return; + } + + HologramService.getInstance().handleHologramClick(event.getPlayer(), hologram); + } + } + + @EventHandler + public void onInteraction(PlayerInteractEvent event) { + Player player = event.getPlayer(); + if (event.getAction() != Action.RIGHT_CLICK_AIR) { + return; + } + + RayTraceResult result = player.getWorld().rayTraceEntities( + player.getEyeLocation(), + player.getEyeLocation().getDirection(), + 15, + entity -> entity instanceof Interaction + ); + + if (result == null) { + return; + } + + Interaction interaction = (Interaction) result.getHitEntity(); + if (interaction == null) { + return; + } + + Hologram hologram = HologramService.getInstance().getHologram(interaction.getUniqueId()); + if (hologram == null) { + return; + } + + HologramService.getInstance().handleHologramClick(player, hologram); + } + + +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/util/EyeTrace.java b/src/main/java/net/voltexstudios/applicationLobby/util/EyeTrace.java new file mode 100644 index 0000000..8ff1d86 --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/util/EyeTrace.java @@ -0,0 +1,66 @@ +package net.voltexstudios.applicationLobby.util; + +import net.voltexstudios.applicationLobby.holograms.HologramService; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.RayTraceResult; +import org.bukkit.util.Vector; + +public class EyeTrace extends BukkitRunnable { + + private static final double MAX_DISTANCE = 15.0; + + private final Player player; + + public EyeTrace(Player player) { + this.player = player; + } + + @Override + public void run() { + if (player == null || !player.isOnline()) { + cancel(); + return; + } + + Location eyeLocation = player.getEyeLocation(); + Location closestHologramLocation = HologramService.getInstance().getClosestHologramLocation(player); + if (closestHologramLocation == null || eyeLocation.getWorld() != closestHologramLocation.getWorld()) { + return; + } + + if (eyeLocation.distance(closestHologramLocation) > MAX_DISTANCE) { + //unhover if player is too far away + HologramService.getInstance().handleHologramHover(player, null); + return; + } + + checkPlayerLookingAtEntity(player); + } + + private void checkPlayerLookingAtEntity(Player player) { + + Location eyeLocation = player.getEyeLocation(); + Vector direction = eyeLocation.getDirection(); + + // RayTrace durchführen + RayTraceResult rayTraceResult = player.getWorld().rayTraceEntities( + eyeLocation, + direction, + MAX_DISTANCE, + entity -> entity != player && HologramService.getInstance().isHologram(entity.getUniqueId()) + ); + + if (rayTraceResult != null) { + Entity targetEntity = rayTraceResult.getHitEntity(); + if (targetEntity != null) { + // Spieler betrachtet ein Interaktions-Entity + HologramService.getInstance().handleHologramHover(player, targetEntity); + return; + } + } + HologramService.getInstance().handleHologramHover(player, null); + } +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/util/PlayerUtil.java b/src/main/java/net/voltexstudios/applicationLobby/util/PlayerUtil.java new file mode 100644 index 0000000..e78a0fa --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/util/PlayerUtil.java @@ -0,0 +1,58 @@ +package net.voltexstudios.applicationLobby.util; + +import net.voltexstudios.applicationLobby.ApplicationLobby; +import net.voltexstudios.applicationLobby.holograms.HologramService; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public final class PlayerUtil { + + private PlayerUtil() { + } + + public static void handlePlayerJoin(Player player) { + + Location spawnLocation = ApplicationLobby.getInstance().getSpawnLocation(); + if (spawnLocation == null) { + return; + } + player.teleport(spawnLocation); + player.setGameMode(GameMode.ADVENTURE); + + giveLobbyItems(player); + + EyeTrace eyeTrace = new EyeTrace(player); + eyeTrace.runTaskTimer(ApplicationLobby.getInstance(), 0, 1); + ApplicationLobby.getInstance().getEyeTraces().put(player, eyeTrace); + } + + public static void handlePlayerQuit(Player player) { + HologramService.getInstance().removeHovering(player); + + EyeTrace eyeTrace = ApplicationLobby.getInstance().getEyeTraces().get(player); + if (eyeTrace != null) { + eyeTrace.cancel(); + } + ApplicationLobby.getInstance().getEyeTraces().remove(player); + + HologramService.getInstance().removePlayerDisplays(player); + } + + private static void giveLobbyItems(Player player) { + + //give invisible offhand item + ItemStack offHand = new ItemStack(Material.DIAMOND); + ItemMeta meta = offHand.getItemMeta(); + meta.setCustomModelData(1); + offHand.setItemMeta(meta); + player.getInventory().setItem(EquipmentSlot.OFF_HAND, offHand); + + player.updateInventory(); + } + +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/util/SimpleLocation.java b/src/main/java/net/voltexstudios/applicationLobby/util/SimpleLocation.java new file mode 100644 index 0000000..6c28356 --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/util/SimpleLocation.java @@ -0,0 +1,34 @@ +package net.voltexstudios.applicationLobby.util; + +import org.bukkit.Bukkit; +import org.bukkit.Location; + +public class SimpleLocation { + + private String world; + private double x,y,z; + private float yaw,pitch; + + public SimpleLocation(String world, double x, double y, double z, float yaw, float pitch) { + this.world = world; + this.x = x; + this.y = y; + this.z = z; + this.yaw = yaw; + this.pitch = pitch; + } + + public SimpleLocation(Location location) { + this.world = location.getWorld().getName(); + this.x = location.getX(); + this.y = location.getY(); + this.z = location.getZ(); + this.yaw = location.getYaw(); + this.pitch = location.getPitch(); + } + + public Location toLocation() { + return new Location(Bukkit.getWorld(world), x, y, z, yaw, pitch); + } + +} diff --git a/src/main/java/net/voltexstudios/applicationLobby/util/SpawnUtil.java b/src/main/java/net/voltexstudios/applicationLobby/util/SpawnUtil.java new file mode 100644 index 0000000..88c70e7 --- /dev/null +++ b/src/main/java/net/voltexstudios/applicationLobby/util/SpawnUtil.java @@ -0,0 +1,42 @@ +package net.voltexstudios.applicationLobby.util; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.bukkit.Location; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; + +public class SpawnUtil { + + private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + public static void setSpawnLocation(Location location) { + + File folder = new File("plugins/ApplicationLobby"); + + if(!folder.exists()) { + folder.mkdirs(); + } + + SimpleLocation simpleLocation = new SimpleLocation(location); + + try(FileWriter fileWriter = new FileWriter("plugins/ApplicationLobby/spawn.json")) { + gson.toJson(simpleLocation, fileWriter); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static SimpleLocation getSpawnLocation() { + try(FileReader fileReader = new FileReader("plugins/ApplicationLobby/spawn.json")) { + return gson.fromJson(fileReader, SimpleLocation.class); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + +}