diff --git a/src/main/java/de/nexuslobby/NexusLobby.java b/src/main/java/de/nexuslobby/NexusLobby.java index d4cead8..74e8157 100644 --- a/src/main/java/de/nexuslobby/NexusLobby.java +++ b/src/main/java/de/nexuslobby/NexusLobby.java @@ -16,12 +16,9 @@ import de.nexuslobby.modules.servers.ServerSwitcherListener; import de.nexuslobby.modules.armorstandtools.*; import de.nexuslobby.modules.gadgets.GadgetModule; import de.nexuslobby.modules.hologram.HologramModule; -import de.nexuslobby.utils.VoidProtection; -import de.nexuslobby.utils.DoubleJump; -import de.nexuslobby.utils.PlayerHider; -import de.nexuslobby.utils.MaintenanceListener; -import de.nexuslobby.utils.ConfigUpdater; -import de.nexuslobby.utils.UpdateChecker; +import de.nexuslobby.modules.mapart.MapArtModule; // Neu +import de.nexuslobby.modules.intro.IntroModule; // Neu +import de.nexuslobby.utils.*; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.ComponentBuilder; @@ -52,7 +49,9 @@ public class NexusLobby extends JavaPlugin implements Listener { private ItemsModule itemsModule; private GadgetModule gadgetModule; private HologramModule hologramModule; - private DynamicArmorStandModule dynamicArmorStandModule; // Neu hinzugefügt + private DynamicArmorStandModule dynamicArmorStandModule; + private MapArtModule mapArtModule; // Neu + private IntroModule introModule; // Neu private File visualsFile; private FileConfiguration visualsConfig; @@ -142,10 +141,17 @@ public class NexusLobby extends JavaPlugin implements Listener { this.hologramModule = new HologramModule(); moduleManager.registerModule(this.hologramModule); - // Dynamic ArmorStand Module registrieren + // Dynamic ArmorStand Module this.dynamicArmorStandModule = new DynamicArmorStandModule(); moduleManager.registerModule(this.dynamicArmorStandModule); + // MapArt & Intro Module + this.mapArtModule = new MapArtModule(); + moduleManager.registerModule(this.mapArtModule); + + this.introModule = new IntroModule(); + moduleManager.registerModule(this.introModule); + moduleManager.registerModule(new SecurityModule()); moduleManager.registerModule(new BossBarModule()); moduleManager.registerModule(new ActionBarModule()); @@ -290,6 +296,10 @@ public class NexusLobby extends JavaPlugin implements Listener { nexusCmd.setExecutor(new NexusLobbyCommand()); nexusCmd.setTabCompleter(tabCompleter); } + + // Neue Commands im TabCompleter registrieren + if (getCommand("mapart") != null) getCommand("mapart").setTabCompleter(tabCompleter); + if (getCommand("introtest") != null) getCommand("introtest").setTabCompleter(tabCompleter); } public class NexusLobbyExpansion extends PlaceholderExpansion { @@ -314,5 +324,5 @@ public class NexusLobby extends JavaPlugin implements Listener { public ItemsModule getItemsModule() { return itemsModule; } public GadgetModule getGadgetModule() { return gadgetModule; } public HologramModule getHologramModule() { return hologramModule; } - public DynamicArmorStandModule getDynamicArmorStandModule() { return dynamicArmorStandModule; } // Getter hinzugefügt + public DynamicArmorStandModule getDynamicArmorStandModule() { return dynamicArmorStandModule; } } \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/commands/LobbyTabCompleter.java b/src/main/java/de/nexuslobby/commands/LobbyTabCompleter.java index 34e3a8e..242cf1b 100644 --- a/src/main/java/de/nexuslobby/commands/LobbyTabCompleter.java +++ b/src/main/java/de/nexuslobby/commands/LobbyTabCompleter.java @@ -5,6 +5,7 @@ import de.nexuslobby.modules.hologram.HologramModule; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Arrays; @@ -22,7 +23,7 @@ public class LobbyTabCompleter implements TabCompleter { } @Override - public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { List suggestions = new ArrayList<>(); // --- NexusLobby Hauptbefehl --- @@ -38,7 +39,7 @@ public class LobbyTabCompleter implements TabCompleter { suggestions.add("spieler"); } } - } + } // --- Hologram Befehl --- else if (command.getName().equalsIgnoreCase("holo")) { @@ -69,15 +70,35 @@ public class LobbyTabCompleter implements TabCompleter { } } - // --- NexusTools (ehemals astools) --- - else if (command.getName().equalsIgnoreCase("nexustools") || command.getName().equalsIgnoreCase("astools") || command.getName().equalsIgnoreCase("nt")) { + // --- MapArt --- + else if (command.getName().equalsIgnoreCase("mapart")) { if (args.length == 1) { - suggestions.add("reload"); - suggestions.add("dynamic"); // Neu: Vorschlag für den Dynamic-Modus + suggestions.add("https://"); + } else if (args.length == 2) { + suggestions.add("1x1"); + suggestions.add("3x2"); + suggestions.add("6x4"); + } + } + + // --- Intro System --- + else if (command.getName().equalsIgnoreCase("intro")) { + if (args.length == 1) { + suggestions.add("add"); + suggestions.add("clear"); + suggestions.add("start"); } } - // --- NexusCmd (ehemals ascmd) --- + // --- NexusTools --- + else if (command.getName().equalsIgnoreCase("nexustools") || command.getName().equalsIgnoreCase("astools") || command.getName().equalsIgnoreCase("nt")) { + if (args.length == 1) { + suggestions.add("reload"); + suggestions.add("dynamic"); + } + } + + // --- NexusCmd --- else if (command.getName().equalsIgnoreCase("nexuscmd") || command.getName().equalsIgnoreCase("ascmd") || command.getName().equalsIgnoreCase("ncmd")) { if (args.length == 1) { suggestions.add("name"); @@ -87,22 +108,15 @@ public class LobbyTabCompleter implements TabCompleter { } else if (args.length == 2 && args[0].equalsIgnoreCase("name")) { suggestions.add("none"); - suggestions.add(""); } else if (args.length == 2 && args[0].equalsIgnoreCase("add")) { suggestions.add("0"); } - else if (args.length == 3 && args[0].equalsIgnoreCase("add")) { - suggestions.add("0"); - } else if (args.length == 4 && args[0].equalsIgnoreCase("add")) { suggestions.add("player"); suggestions.add("console"); suggestions.add("bungee"); } - else if (args.length == 5 && args[0].equalsIgnoreCase("add") && args[3].equalsIgnoreCase("bungee")) { - suggestions.add(""); - } } return suggestions.stream() diff --git a/src/main/java/de/nexuslobby/modules/intro/IntroModule.java b/src/main/java/de/nexuslobby/modules/intro/IntroModule.java new file mode 100644 index 0000000..93245a5 --- /dev/null +++ b/src/main/java/de/nexuslobby/modules/intro/IntroModule.java @@ -0,0 +1,219 @@ +package de.nexuslobby.modules.intro; + +import de.nexuslobby.NexusLobby; +import de.nexuslobby.api.Module; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.scheduler.BukkitRunnable; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +public class IntroModule implements Module, Listener, CommandExecutor { + + private final Set activeIntro = new HashSet<>(); + private final List points = new ArrayList<>(); + private File configFile; + private FileConfiguration config; + + // --- Einstellungen --- + private final int TICKS_FLUG = 70; // Dauer der Fahrt zwischen zwei Punkten (3.5 Sek) + private final int TICKS_PAUSE = 30; // Standzeit an jedem Punkt (1.5 Sek) + + @Override + public String getName() { return "Intro"; } + + @Override + public void onEnable() { + Bukkit.getPluginManager().registerEvents(this, NexusLobby.getInstance()); + if (NexusLobby.getInstance().getCommand("intro") != null) { + NexusLobby.getInstance().getCommand("intro").setExecutor(this); + } + loadPoints(); + } + + @Override + public void onDisable() { + activeIntro.clear(); + } + + private void loadPoints() { + points.clear(); + configFile = new File(NexusLobby.getInstance().getDataFolder(), "intro.yml"); + if (!configFile.exists()) { + try { configFile.createNewFile(); } catch (IOException ignored) {} + } + config = YamlConfiguration.loadConfiguration(configFile); + List list = config.getList("points"); + if (list != null) { + for (Object obj : list) { + if (obj instanceof Location loc) points.add(loc); + } + } + } + + private void savePoints() { + config.set("points", points); + try { config.save(configFile); } catch (IOException e) { e.printStackTrace(); } + } + + @EventHandler + public void onJoin(PlayerJoinEvent event) { + if (!event.getPlayer().hasPlayedBefore() && points.size() >= 2) { + startIntro(event.getPlayer()); + } + } + + @EventHandler + public void onSneak(PlayerToggleSneakEvent event) { + if (activeIntro.contains(event.getPlayer().getUniqueId()) && event.isSneaking()) { + stopIntro(event.getPlayer(), true); + } + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + if (!(sender instanceof Player p)) return true; + if (!p.hasPermission("nexuslobby.admin")) return true; + + if (args.length == 0) { + p.sendMessage("§8§m------------------------------------"); + p.sendMessage("§6§lNexus Intro System (Cinematic)"); + p.sendMessage("§e/intro add §7- Punkt hinzufügen"); + p.sendMessage("§e/intro clear §7- Alle Punkte löschen"); + p.sendMessage("§e/intro start §7- Teste die Fahrt"); + p.sendMessage("§8§m------------------------------------"); + return true; + } + + switch (args[0].toLowerCase()) { + case "add" -> { + points.add(p.getLocation()); + savePoints(); + p.sendMessage("§8[§6Nexus§8] §aPunkt #" + points.size() + " wurde gesetzt!"); + } + case "clear" -> { + points.clear(); + savePoints(); + p.sendMessage("§8[§6Nexus§8] §cAlle Intro-Punkte wurden gelöscht."); + } + case "start" -> { + if (points.size() < 2) { + p.sendMessage("§8[§6Nexus§8] §cDu brauchst mindestens 2 Punkte für eine Fahrt."); + } else { + startIntro(p); + } + } + } + return true; + } + + public void startIntro(Player player) { + activeIntro.add(player.getUniqueId()); + player.setGameMode(GameMode.SPECTATOR); + + new BukkitRunnable() { + int currentSegment = 0; + int tickInSegment = 0; + boolean isPausing = true; + + @Override + public void run() { + try { + if (!player.isOnline() || !activeIntro.contains(player.getUniqueId())) { + this.cancel(); + return; + } + + if (currentSegment >= points.size() - 1) { + stopIntro(player, false); + this.cancel(); + return; + } + + Location start = points.get(currentSegment); + Location end = points.get(currentSegment + 1); + + if (isPausing) { + // Kamera steht am aktuellen Punkt + player.teleport(start); + tickInSegment++; + if (tickInSegment >= TICKS_PAUSE) { + isPausing = false; + tickInSegment = 0; + } + } else { + // Kamera fliegt zum nächsten Punkt + double progress = (double) tickInSegment / (double) TICKS_FLUG; + + // "Smooth Step" für flüssigeres Beschleunigen/Bremsen + double smoothT = progress * progress * (3 - 2 * progress); + + Location nextLoc = interpolate(start, end, smoothT); + player.teleport(nextLoc); + + tickInSegment++; + if (tickInSegment >= TICKS_FLUG) { + isPausing = true; + tickInSegment = 0; + currentSegment++; + } + } + + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, + new TextComponent("§6§lINTRO-TOUR §8| §ePunkt " + (currentSegment + 1) + " §8| §7Sneak zum Abbrechen")); + + } catch (Exception e) { + this.cancel(); + stopIntro(player, true); + } + } + }.runTaskTimer(NexusLobby.getInstance(), 0L, 1L); + } + + private Location interpolate(Location start, Location end, double t) { + double x = start.getX() + (end.getX() - start.getX()) * t; + double y = start.getY() + (end.getY() - start.getY()) * t; + double z = start.getZ() + (end.getZ() - start.getZ()) * t; + + // Sanfte Drehung + float startYaw = start.getYaw(); + float endYaw = end.getYaw(); + // Verhindert ruckartige 360-Grad Dreher + float diff = (endYaw - startYaw) % 360; + if (diff > 180) diff -= 360; + if (diff < -180) diff += 360; + float yaw = startYaw + diff * (float)t; + + float pitch = (float) (start.getPitch() + (end.getPitch() - start.getPitch()) * t); + + return new Location(start.getWorld(), x, y, z, yaw, pitch); + } + + private void stopIntro(Player player, boolean canceled) { + activeIntro.remove(player.getUniqueId()); + player.setGameMode(GameMode.ADVENTURE); + player.teleport(player.getWorld().getSpawnLocation()); + + if (canceled) { + player.sendMessage("§8[§6Nexus§8] §cIntro abgebrochen."); + } else { + player.sendMessage("§8[§6Nexus§8] §aWillkommen auf dem Netzwerk!"); + } + } +} \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/modules/mapart/MapArtModule.java b/src/main/java/de/nexuslobby/modules/mapart/MapArtModule.java new file mode 100644 index 0000000..8e0a40e --- /dev/null +++ b/src/main/java/de/nexuslobby/modules/mapart/MapArtModule.java @@ -0,0 +1,298 @@ +package de.nexuslobby.modules.mapart; + +import de.nexuslobby.NexusLobby; +import de.nexuslobby.api.Module; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.ItemFrame; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.MapMeta; +import org.bukkit.map.MapCanvas; +import org.bukkit.map.MapRenderer; +import org.bukkit.map.MapView; +import org.bukkit.util.RayTraceResult; +import org.jetbrains.annotations.NotNull; + +import javax.imageio.ImageIO; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +public class MapArtModule implements Module, CommandExecutor { + + private File storageFile; + private FileConfiguration storageConfig; + + // RAM-Schutz: Cache für bereits geladene Bild-Kacheln + private final Map tileCache = new ConcurrentHashMap<>(); + // Hilfs-Set um parallele Downloads der gleichen URL zu verhindern + private final Map loadingShield = new ConcurrentHashMap<>(); + + @Override + public String getName() { return "MapArt"; } + + @Override + public void onEnable() { + if (NexusLobby.getInstance().getCommand("mapart") != null) { + NexusLobby.getInstance().getCommand("mapart").setExecutor(this); + } + initStorage(); + reloadMaps(); + } + + @Override + public void onDisable() { + saveStorage(); + tileCache.clear(); + } + + private void initStorage() { + storageFile = new File(NexusLobby.getInstance().getDataFolder(), "mapart.yml"); + if (!storageFile.exists()) { + try { + storageFile.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + storageConfig = YamlConfiguration.loadConfiguration(storageFile); + } + + private void saveStorage() { + try { + storageConfig.save(storageFile); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void reloadMaps() { + ConfigurationSection section = storageConfig.getConfigurationSection("active_maps"); + if (section == null) return; + + for (String idStr : section.getKeys(false)) { + try { + int mapId = Integer.parseInt(idStr); + String url = section.getString(idStr + ".url"); + int x = section.getInt(idStr + ".x"); + int y = section.getInt(idStr + ".y"); + int totalW = section.getInt(idStr + ".totalW"); + int totalH = section.getInt(idStr + ".totalH"); + + @SuppressWarnings("deprecation") + MapView view = Bukkit.getMap(mapId); + if (view != null) { + applyRenderer(view, url, x, y, totalW, totalH); + } + } catch (Exception ignored) {} + } + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + if (!(sender instanceof Player player)) return true; + if (!player.hasPermission("nexuslobby.mapart")) { + player.sendMessage("§8[§6Nexus§8] §cKeine Rechte."); + return true; + } + + if (args.length == 0) { + sendHelp(player); + return true; + } + + if (args[0].equalsIgnoreCase("delete")) { + int radius = 3; + if (args.length == 2) { + try { + radius = Integer.parseInt(args[1]); + } catch (NumberFormatException e) { + player.sendMessage("§8[§6Nexus§8] §cUngültiger Radius."); + return true; + } + } + deleteNearbyMaps(player, radius); + return true; + } + + if (args.length != 2) { + sendHelp(player); + return true; + } + + RayTraceResult rayTrace = player.rayTraceBlocks(5); + if (rayTrace == null || rayTrace.getHitBlock() == null || rayTrace.getHitBlockFace() == null) { + player.sendMessage("§8[§6Nexus§8] §cBitte schaue eine Wand direkt an."); + return true; + } + + Block targetBlock = rayTrace.getHitBlock(); + BlockFace hitFace = rayTrace.getHitBlockFace(); + + if (hitFace == BlockFace.UP || hitFace == BlockFace.DOWN) { + player.sendMessage("§8[§6Nexus§8] §cAktuell nur an vertikalen Wänden möglich."); + return true; + } + + String url = args[0]; + int width, height; + try { + String[] parts = args[1].toLowerCase().split("x"); + width = Integer.parseInt(parts[0]); + height = Integer.parseInt(parts[1]); + } catch (Exception e) { + player.sendMessage("§8[§6Nexus§8] §cUngültiges Format (z.B. 6x4)."); + return true; + } + + player.sendMessage("§8[§6Nexus§8] §7Bild wird verarbeitet..."); + createRaster(player, targetBlock, hitFace, url, width, height); + + return true; + } + + private void sendHelp(Player p) { + p.sendMessage("§8§m------------------------------------"); + p.sendMessage("§6§lNexus MapArt"); + p.sendMessage("§e/mapart §7- Bild erstellen"); + p.sendMessage("§e/mapart delete [Radius] §7- Bilder in der Nähe löschen"); + p.sendMessage("§8§m------------------------------------"); + } + + private void deleteNearbyMaps(Player player, int radius) { + AtomicInteger count = new AtomicInteger(0); + player.getNearbyEntities(radius, radius, radius).forEach(entity -> { + if (entity instanceof ItemFrame frame) { + ItemStack item = frame.getItem(); + if (item != null && item.getType() == Material.FILLED_MAP && item.getItemMeta() instanceof MapMeta meta) { + if (meta.hasMapView()) { + int id = meta.getMapView().getId(); + if (storageConfig.contains("active_maps." + id)) { + storageConfig.set("active_maps." + id, null); + frame.remove(); + count.incrementAndGet(); + } + } + } + } + }); + saveStorage(); + player.sendMessage("§8[§6Nexus§8] §aErfolgreich §e" + count.get() + " §aKartenelemente gelöscht."); + } + + private void createRaster(Player player, Block startBlock, BlockFace face, String url, int gridW, int gridH) { + BlockFace rightDirection; + switch (face) { + case NORTH: rightDirection = BlockFace.WEST; break; + case SOUTH: rightDirection = BlockFace.EAST; break; + case EAST: rightDirection = BlockFace.NORTH; break; + case WEST: rightDirection = BlockFace.SOUTH; break; + default: rightDirection = BlockFace.EAST; + } + + Block origin = startBlock.getRelative(face); + + for (int y = 0; y < gridH; y++) { + for (int x = 0; x < gridW; x++) { + Block currentPos = origin.getRelative(rightDirection, x).getRelative(BlockFace.DOWN, y); + spawnPersistentFrame(player, currentPos, face, url, x, y, gridW, gridH); + } + } + player.sendMessage("§8[§6Nexus§8] §aBild-Raster wurde permanent platziert!"); + } + + private void spawnPersistentFrame(Player player, Block pos, BlockFace face, String url, int x, int y, int totalW, int totalH) { + MapView view = Bukkit.createMap(player.getWorld()); + applyRenderer(view, url, x, y, totalW, totalH); + + String path = "active_maps." + view.getId(); + storageConfig.set(path + ".url", url); + storageConfig.set(path + ".x", x); + storageConfig.set(path + ".y", y); + storageConfig.set(path + ".totalW", totalW); + storageConfig.set(path + ".totalH", totalH); + saveStorage(); + + ItemStack mapStack = new ItemStack(Material.FILLED_MAP); + MapMeta meta = (MapMeta) mapStack.getItemMeta(); + if (meta != null) { + meta.setMapView(view); + mapStack.setItemMeta(meta); + } + + try { + ItemFrame frame = player.getWorld().spawn(pos.getLocation(), ItemFrame.class); + frame.setFacingDirection(face); + frame.setItem(mapStack); + frame.setVisible(false); + frame.setFixed(true); + } catch (Exception ignored) {} + } + + private void applyRenderer(MapView view, String url, int tileX, int tileY, int totalW, int totalH) { + view.getRenderers().forEach(view::removeRenderer); + view.addRenderer(new MapRenderer() { + private final String cacheKey = url + "_" + totalW + "x" + totalH + "_" + tileX + "_" + tileY; + private boolean errorLogged = false; + + @Override + public void render(@NotNull MapView map, @NotNull MapCanvas canvas, @NotNull Player p) { + // 1. Wenn Kachel im Cache, sofort zeichnen (extrem schnell) + if (tileCache.containsKey(cacheKey)) { + canvas.drawImage(0, 0, tileCache.get(cacheKey)); + return; + } + + // 2. Wenn bereits ein Thread für diese URL lädt, abbrechen (verhindert Spam) + if (loadingShield.containsKey(url)) return; + + // 3. Bild asynchron laden + loadingShield.put(url, true); + Bukkit.getScheduler().runTaskAsynchronously(NexusLobby.getInstance(), () -> { + try { + BufferedImage original = ImageIO.read(new URL(url)); + if (original != null) { + int targetW = totalW * 128; + int targetH = totalH * 128; + + BufferedImage fullScaled = new BufferedImage(targetW, targetH, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = fullScaled.createGraphics(); + g.drawImage(original.getScaledInstance(targetW, targetH, Image.SCALE_SMOOTH), 0, 0, null); + g.dispose(); + + // Alle benötigten Kacheln für dieses Bild in den Cache legen + for (int ty = 0; ty < totalH; ty++) { + for (int tx = 0; tx < totalW; tx++) { + String key = url + "_" + totalW + "x" + totalH + "_" + tx + "_" + ty; + tileCache.put(key, fullScaled.getSubimage(tx * 128, ty * 128, 128, 128)); + } + } + } + } catch (Exception e) { + if (!errorLogged) { + NexusLobby.getInstance().getLogger().warning("Fehler beim Laden von MapArt: " + url); + errorLogged = true; + } + } finally { + loadingShield.remove(url); + } + }); + } + }); + } +} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5dddf1e..83ee441 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: NexusLobby main: de.nexuslobby.NexusLobby -version: "1.0.3" +version: "1.0.4" api-version: "1.21" author: M_Viper description: Modular Lobby Plugin @@ -51,6 +51,14 @@ commands: description: Verwalte Lobby Hologramme (Text-Displays) usage: /holo [text] permission: nexuslobby.hologram + mapart: + description: Erstellt ein Bild-Raster auf unsichtbaren Rahmen + usage: /mapart + permission: nexuslobby.mapart + intro: + description: Verwalte und teste die Cinematic Intro Tour + usage: /intro + permission: nexuslobby.admin permissions: nexuslobby.portal: @@ -66,7 +74,7 @@ permissions: description: Zugriff auf den Server Switcher default: true nexuslobby.admin: - description: Voller Zugriff auf Lobby-Gamerules, Einstellungen und Reload + description: Voller Zugriff auf Lobby-Gamerules, Einstellungen, Intro und Reload default: op nexuslobby.build: description: Erlaubt das Umgehen des Lobby-Schutzes zum Bauen @@ -82,4 +90,7 @@ permissions: default: op nexuslobby.hologram: description: Erlaubt das Erstellen von Text-Display Hologrammen + default: op + nexuslobby.mapart: + description: Erlaubt das Erstellen von Map-Art Bildern default: op \ No newline at end of file