Upload folder via GUI - src
This commit is contained in:
@@ -120,15 +120,8 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── /ticket create (Konsole) ──────────────────────────────────────────
|
// ── /ticket create (Konsole) ──────────────────────────────────────────
|
||||||
//
|
|
||||||
// Syntax: /ticket create <Spielername> [Kategorie] [Priorität] <Beschreibung>
|
|
||||||
//
|
|
||||||
// Das Ticket wird im Namen des angegebenen Spielers erstellt.
|
|
||||||
// Als Erstell-Position wird die aktuelle Spieler-Location verwendet
|
|
||||||
// (oder eine Default-Location wenn der Spieler offline ist).
|
|
||||||
|
|
||||||
private void handleCreateConsole(CommandSender console, String[] args) {
|
private void handleCreateConsole(CommandSender console, String[] args) {
|
||||||
// args[0] = "create", args[1] = Spielername, args[2..] = [Kategorie] [Priorität] Text
|
|
||||||
if (args.length < 3) {
|
if (args.length < 3) {
|
||||||
console.sendMessage("[TicketSystem] Verwendung: /ticket create <Spielername> [Kategorie] [Priorität] <Beschreibung>");
|
console.sendMessage("[TicketSystem] Verwendung: /ticket create <Spielername> [Kategorie] [Priorität] <Beschreibung>");
|
||||||
console.sendMessage("[TicketSystem] Beispiel: /ticket create Notch bug high Spieler fällt durch den Boden");
|
console.sendMessage("[TicketSystem] Beispiel: /ticket create Notch bug high Spieler fällt durch den Boden");
|
||||||
@@ -137,7 +130,6 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
|
|
||||||
String targetName = args[1];
|
String targetName = args[1];
|
||||||
|
|
||||||
// Spieler suchen (online bevorzugt, sonst OfflinePlayer)
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
OfflinePlayer offlineTarget = Bukkit.getOfflinePlayer(targetName);
|
OfflinePlayer offlineTarget = Bukkit.getOfflinePlayer(targetName);
|
||||||
UUID targetUUID = offlineTarget.getUniqueId();
|
UUID targetUUID = offlineTarget.getUniqueId();
|
||||||
@@ -146,12 +138,11 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
CategoryManager cm = plugin.getCategoryManager();
|
CategoryManager cm = plugin.getCategoryManager();
|
||||||
ConfigCategory category = cm.getDefault();
|
ConfigCategory category = cm.getDefault();
|
||||||
TicketPriority priority = TicketPriority.NORMAL;
|
TicketPriority priority = TicketPriority.NORMAL;
|
||||||
int msgStart = 2; // Index ab dem die Beschreibung beginnt (relativ zu args[2..])
|
int msgStart = 2;
|
||||||
|
|
||||||
boolean categoriesOn = plugin.getConfig().getBoolean("categories-enabled", true);
|
boolean categoriesOn = plugin.getConfig().getBoolean("categories-enabled", true);
|
||||||
boolean prioritiesOn = plugin.getConfig().getBoolean("priorities-enabled", true);
|
boolean prioritiesOn = plugin.getConfig().getBoolean("priorities-enabled", true);
|
||||||
|
|
||||||
// args[2] = optional Kategorie, args[3] = optional Priorität, Rest = Text
|
|
||||||
if (args.length >= 4 && categoriesOn) {
|
if (args.length >= 4 && categoriesOn) {
|
||||||
ConfigCategory parsedCat = cm.resolve(args[2]);
|
ConfigCategory parsedCat = cm.resolve(args[2]);
|
||||||
if (parsedCat != null) {
|
if (parsedCat != null) {
|
||||||
@@ -170,15 +161,15 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
if (parsedPrio != null) { priority = parsedPrio; msgStart = 3; }
|
if (parsedPrio != null) { priority = parsedPrio; msgStart = 3; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Beschreibung zusammensetzen (args[msgStart+1] weil args[1]=Spielername)
|
// msgStart ist der absolute Index in args[] ab dem die Beschreibung beginnt.
|
||||||
int absoluteStart = msgStart + 1; // +1 für den Spielernamen in args[1]
|
// Kein +1 nötig – msgStart zeigt bereits auf das erste Beschreibungs-Wort.
|
||||||
if (absoluteStart >= args.length) {
|
if (msgStart >= args.length) {
|
||||||
console.sendMessage("[TicketSystem] Fehler: Keine Beschreibung angegeben.");
|
console.sendMessage("[TicketSystem] Fehler: Keine Beschreibung angegeben.");
|
||||||
console.sendMessage("[TicketSystem] Verwendung: /ticket create <Spielername> [Kategorie] [Priorität] <Beschreibung>");
|
console.sendMessage("[TicketSystem] Verwendung: /ticket create <Spielername> [Kategorie] [Priorität] <Beschreibung>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String message = String.join(" ", Arrays.copyOfRange(args, absoluteStart, args.length));
|
String message = String.join(" ", Arrays.copyOfRange(args, msgStart, args.length));
|
||||||
int maxLen = plugin.getConfig().getInt("max-description-length", 100);
|
int maxLen = plugin.getConfig().getInt("max-description-length", 100);
|
||||||
|
|
||||||
if (message.isEmpty()) {
|
if (message.isEmpty()) {
|
||||||
@@ -190,7 +181,6 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Location: online-Spieler → aktuelle Pos; offline → Spawn der Default-Welt
|
|
||||||
Location location;
|
Location location;
|
||||||
Player onlineTarget = Bukkit.getPlayer(targetUUID);
|
Player onlineTarget = Bukkit.getPlayer(targetUUID);
|
||||||
if (onlineTarget != null) {
|
if (onlineTarget != null) {
|
||||||
@@ -233,7 +223,6 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
+ "' erstellt." + catInfo + prioInfo);
|
+ "' erstellt." + catInfo + prioInfo);
|
||||||
console.sendMessage("[TicketSystem] Nachricht: " + fMessage);
|
console.sendMessage("[TicketSystem] Nachricht: " + fMessage);
|
||||||
|
|
||||||
// Team benachrichtigen (gleich wie bei normalem /ticket create)
|
|
||||||
plugin.getTicketManager().notifyTeam(ticket);
|
plugin.getTicketManager().notifyTeam(ticket);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -247,9 +236,10 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
plugin.reloadSettings();
|
plugin.reloadSettings();
|
||||||
plugin.getTicketGUI().reloadConfig();
|
plugin.getTicketGUI().reloadConfig();
|
||||||
plugin.getTicketGUI().reloadTitles();
|
plugin.getTicketGUI().reloadTitles();
|
||||||
plugin.getFaqGUI().reloadConfig();
|
// FaqGUI ist null wenn faq-enabled: false → Null-Check erforderlich
|
||||||
|
if (plugin.getFaqGUI() != null) plugin.getFaqGUI().reloadConfig();
|
||||||
plugin.getCategoryManager().reload();
|
plugin.getCategoryManager().reload();
|
||||||
plugin.getFaqManager().reload();
|
if (plugin.getFaqManager() != null) plugin.getFaqManager().reload();
|
||||||
plugin.getTicketCache().clear();
|
plugin.getTicketCache().clear();
|
||||||
console.sendMessage("[TicketSystem] Konfiguration erfolgreich neu geladen.");
|
console.sendMessage("[TicketSystem] Konfiguration erfolgreich neu geladen.");
|
||||||
}
|
}
|
||||||
@@ -729,9 +719,10 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
plugin.reloadSettings();
|
plugin.reloadSettings();
|
||||||
plugin.getTicketGUI().reloadConfig();
|
plugin.getTicketGUI().reloadConfig();
|
||||||
plugin.getTicketGUI().reloadTitles();
|
plugin.getTicketGUI().reloadTitles();
|
||||||
plugin.getFaqGUI().reloadConfig();
|
// FaqGUI ist null wenn faq-enabled: false → Null-Check erforderlich
|
||||||
|
if (plugin.getFaqGUI() != null) plugin.getFaqGUI().reloadConfig();
|
||||||
plugin.getCategoryManager().reload();
|
plugin.getCategoryManager().reload();
|
||||||
plugin.getFaqManager().reload();
|
if (plugin.getFaqManager() != null) plugin.getFaqManager().reload();
|
||||||
plugin.getTicketCache().clear();
|
plugin.getTicketCache().clear();
|
||||||
player.sendMessage(plugin.lang().get("reload.success"));
|
player.sendMessage(plugin.lang().get("reload.success"));
|
||||||
if (plugin.isBungeeCordEnabled())
|
if (plugin.isBungeeCordEnabled())
|
||||||
@@ -944,14 +935,13 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
// ── /ticket faq ───────────────────────────────────────────────────────
|
// ── /ticket faq ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
private void handleFaq(Player player, String[] args) {
|
private void handleFaq(Player player, String[] args) {
|
||||||
// FAQ-System global deaktiviert?
|
|
||||||
if (!plugin.getConfig().getBoolean("faq-enabled", true)) {
|
if (!plugin.getConfig().getBoolean("faq-enabled", true)) {
|
||||||
plugin.lang().send(player, "faq.disabled");
|
plugin.lang().send(player, "faq.disabled");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
plugin.getFaqGUI().openFaqGUI(player);
|
if (plugin.getFaqGUI() != null) plugin.getFaqGUI().openFaqGUI(player);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1122,7 +1112,6 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
if (!player.hasPermission("ticket.admin")) {
|
if (!player.hasPermission("ticket.admin")) {
|
||||||
plugin.lang().send(player, "general.no-permission"); return;
|
plugin.lang().send(player, "general.no-permission"); return;
|
||||||
}
|
}
|
||||||
// FAQ-System deaktiviert?
|
|
||||||
if (!plugin.getConfig().getBoolean("faq-enabled", true)) {
|
if (!plugin.getConfig().getBoolean("faq-enabled", true)) {
|
||||||
plugin.lang().send(player, "faq.disabled"); return;
|
plugin.lang().send(player, "faq.disabled"); return;
|
||||||
}
|
}
|
||||||
@@ -1218,6 +1207,7 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getFaqCategoryKeysForTab(String input) {
|
private List<String> getFaqCategoryKeysForTab(String input) {
|
||||||
|
if (plugin.getFaqManager() == null) return new ArrayList<>();
|
||||||
String lower = input == null ? "" : input.toLowerCase();
|
String lower = input == null ? "" : input.toLowerCase();
|
||||||
List<String> result = new ArrayList<>();
|
List<String> result = new ArrayList<>();
|
||||||
for (FaqCategory cat : plugin.getFaqManager().getAllCategories())
|
for (FaqCategory cat : plugin.getFaqManager().getAllCategories())
|
||||||
@@ -1257,11 +1247,9 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
for (String s : List.of("create", "reload", "archive", "stats"))
|
for (String s : List.of("create", "reload", "archive", "stats"))
|
||||||
if (s.startsWith(args[0].toLowerCase())) completions.add(s);
|
if (s.startsWith(args[0].toLowerCase())) completions.add(s);
|
||||||
} else if (args.length == 2 && normalize(args[0]).equals("create")) {
|
} else if (args.length == 2 && normalize(args[0]).equals("create")) {
|
||||||
// Spielernamen vorschlagen
|
|
||||||
for (Player p : Bukkit.getOnlinePlayers())
|
for (Player p : Bukkit.getOnlinePlayers())
|
||||||
if (p.getName().toLowerCase().startsWith(args[1].toLowerCase())) completions.add(p.getName());
|
if (p.getName().toLowerCase().startsWith(args[1].toLowerCase())) completions.add(p.getName());
|
||||||
} else if (args.length == 3 && normalize(args[0]).equals("create")) {
|
} else if (args.length == 3 && normalize(args[0]).equals("create")) {
|
||||||
// Kategorien vorschlagen
|
|
||||||
completions.addAll(plugin.getCategoryManager().getDisplayNamesForTabComplete(args[2]));
|
completions.addAll(plugin.getCategoryManager().getDisplayNamesForTabComplete(args[2]));
|
||||||
}
|
}
|
||||||
return completions;
|
return completions;
|
||||||
@@ -1321,8 +1309,9 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
|
|||||||
&& (args[1].equalsIgnoreCase("edit") || args[1].equalsIgnoreCase("delete")
|
&& (args[1].equalsIgnoreCase("edit") || args[1].equalsIgnoreCase("delete")
|
||||||
|| args[1].equalsIgnoreCase("bearbeiten") || args[1].equalsIgnoreCase("löschen"))
|
|| args[1].equalsIgnoreCase("bearbeiten") || args[1].equalsIgnoreCase("löschen"))
|
||||||
&& player.hasPermission("ticket.admin")) {
|
&& player.hasPermission("ticket.admin")) {
|
||||||
for (FaqEntry e : plugin.getFaqManager().getAll())
|
if (plugin.getFaqManager() != null)
|
||||||
completions.add(String.valueOf(e.getId()));
|
for (FaqEntry e : plugin.getFaqManager().getAll())
|
||||||
|
completions.add(String.valueOf(e.getId()));
|
||||||
|
|
||||||
} else if (args.length == 2 && (normalize(args[0]).equals("category")
|
} else if (args.length == 2 && (normalize(args[0]).equals("category")
|
||||||
|| args[0].equalsIgnoreCase("kategorie"))
|
|| args[0].equalsIgnoreCase("kategorie"))
|
||||||
|
|||||||
@@ -32,9 +32,12 @@ public class PlayerJoinListener implements Listener {
|
|||||||
int count = plugin.getDatabaseManager().countOpenTickets();
|
int count = plugin.getDatabaseManager().countOpenTickets();
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||||
player.sendMessage(plugin.lang().format("join.open-tickets",
|
// Anzahl als normaler Text – kein MiniMessage nötig
|
||||||
"{count}", String.valueOf(count)));
|
plugin.lang().send(player, "join.open-tickets",
|
||||||
player.sendMessage(plugin.lang().get("join.open-tickets-hint"));
|
"{count}", String.valueOf(count));
|
||||||
|
// Hint über send() routen → MiniMessage greift wenn
|
||||||
|
// <click:run_command:...> in der lang.yml steht
|
||||||
|
plugin.lang().send(player, "join.open-tickets-hint");
|
||||||
}, 40L);
|
}, 40L);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -54,14 +57,14 @@ public class PlayerJoinListener implements Listener {
|
|||||||
if (!player.isOnline()) return;
|
if (!player.isOnline()) return;
|
||||||
World world = Bukkit.getWorld(pt.world());
|
World world = Bukkit.getWorld(pt.world());
|
||||||
if (world == null) {
|
if (world == null) {
|
||||||
player.sendMessage(plugin.lang().format("join.teleport-world-missing",
|
plugin.lang().send(player, "join.teleport-world-missing",
|
||||||
"{world}", pt.world()));
|
"{world}", pt.world());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Location loc = new Location(world, pt.x(), pt.y(), pt.z(), pt.yaw(), pt.pitch());
|
Location loc = new Location(world, pt.x(), pt.y(), pt.z(), pt.yaw(), pt.pitch());
|
||||||
player.teleport(loc);
|
player.teleport(loc);
|
||||||
String coords = String.format("%.0f, %.0f, %.0f", pt.x(), pt.y(), pt.z());
|
String coords = String.format("%.0f, %.0f, %.0f", pt.x(), pt.y(), pt.z());
|
||||||
player.sendMessage(plugin.lang().format("join.teleport-success", "{coords}", coords));
|
plugin.lang().send(player, "join.teleport-success", "{coords}", coords);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, 40L);
|
}, 40L);
|
||||||
@@ -78,7 +81,9 @@ public class PlayerJoinListener implements Listener {
|
|||||||
player.sendMessage(plugin.lang().get("general.separator"));
|
player.sendMessage(plugin.lang().get("general.separator"));
|
||||||
player.sendMessage(plugin.lang().get("join.pending-header"));
|
player.sendMessage(plugin.lang().get("join.pending-header"));
|
||||||
for (String msg : pending) {
|
for (String msg : pending) {
|
||||||
player.sendMessage(plugin.lang().color(msg));
|
// Pending-Nachrichten können MiniMessage-Tags enthalten
|
||||||
|
// → sendRaw() statt color()
|
||||||
|
plugin.lang().sendRaw(player, msg);
|
||||||
}
|
}
|
||||||
player.sendMessage(plugin.lang().get("general.separator"));
|
player.sendMessage(plugin.lang().get("general.separator"));
|
||||||
});
|
});
|
||||||
@@ -94,7 +99,6 @@ public class PlayerJoinListener implements Listener {
|
|||||||
|
|
||||||
// ── Spieler: über geschlossene Tickets informieren ────────────────
|
// ── Spieler: über geschlossene Tickets informieren ────────────────
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
// Nur Tickets dieses Spielers laden (nicht ALLE closed Tickets)
|
|
||||||
List<Ticket> closed = plugin.getDatabaseManager()
|
List<Ticket> closed = plugin.getDatabaseManager()
|
||||||
.getUnnotifiedClosedTicketsByPlayer(player.getUniqueId());
|
.getUnnotifiedClosedTicketsByPlayer(player.getUniqueId());
|
||||||
|
|
||||||
@@ -111,7 +115,7 @@ public class PlayerJoinListener implements Listener {
|
|||||||
new de.ticketsystem.UpdateChecker(plugin, resourceId).getVersion(version -> {
|
new de.ticketsystem.UpdateChecker(plugin, resourceId).getVersion(version -> {
|
||||||
String current = plugin.getDescription().getVersion();
|
String current = plugin.getDescription().getVersion();
|
||||||
if (!current.equals(version)) {
|
if (!current.equals(version)) {
|
||||||
String bar = plugin.lang().get("update.available-bar");
|
String bar = plugin.lang().get("update.available-bar");
|
||||||
String line1 = plugin.lang().format("update.available-line1", "{version}", version);
|
String line1 = plugin.lang().format("update.available-line1", "{version}", version);
|
||||||
String line2 = plugin.lang().get("update.available-line2");
|
String line2 = plugin.lang().get("update.available-line2");
|
||||||
player.sendMessage(ChatColor.GOLD + bar);
|
player.sendMessage(ChatColor.GOLD + bar);
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ public class LanguageManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sendet eine Nachricht an einen CommandSender.
|
* Sendet eine Nachricht an einen CommandSender (aus einem lang-Key).
|
||||||
*
|
*
|
||||||
* Enthält der Rohtext MiniMessage-Tags mit interaktiven Elementen
|
* Enthält der Rohtext MiniMessage-Tags mit interaktiven Elementen
|
||||||
* (click, hover, insertion), wird die Nachricht als Adventure-Component
|
* (click, hover, insertion), wird die Nachricht als Adventure-Component
|
||||||
@@ -312,6 +312,38 @@ public class LanguageManager {
|
|||||||
for (int i = 0; i + 1 < replacements.length; i += 2)
|
for (int i = 0; i + 1 < replacements.length; i += 2)
|
||||||
raw = raw.replace(replacements[i], replacements[i + 1]);
|
raw = raw.replace(replacements[i], replacements[i + 1]);
|
||||||
|
|
||||||
|
sendProcessed(sender, raw, needsPrefix(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sendet einen bereits zusammengebauten Roh-String (KEIN lang-Key) durch
|
||||||
|
* die vollständige MiniMessage-Pipeline inkl. Legacy-Konvertierung.
|
||||||
|
*
|
||||||
|
* Verwende diese Methode wenn du Strings programmatisch zusammenbaust
|
||||||
|
* (z.B. Rating-Prompt aus mehreren Keys) und trotzdem klickbare
|
||||||
|
* run_command-Tags benötigst.
|
||||||
|
*
|
||||||
|
* Prefix wird NICHT automatisch vorangestellt.
|
||||||
|
*/
|
||||||
|
public void sendRaw(CommandSender sender, String rawText) {
|
||||||
|
if (rawText == null || rawText.isEmpty()) return;
|
||||||
|
sendProcessed(sender, rawText, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sendet einen bereits zusammengebauten Roh-String mit optionalem Prefix
|
||||||
|
* durch die vollständige MiniMessage-Pipeline.
|
||||||
|
*/
|
||||||
|
public void sendRaw(CommandSender sender, String rawText, boolean withPrefix) {
|
||||||
|
if (rawText == null || rawText.isEmpty()) return;
|
||||||
|
sendProcessed(sender, rawText, withPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interne Kernmethode: Verarbeitet einen vorbereiteten String und sendet ihn.
|
||||||
|
* Entscheidet automatisch zwischen MiniMessage-Component und Legacy-String.
|
||||||
|
*/
|
||||||
|
private void sendProcessed(CommandSender sender, String raw, boolean addPrefix) {
|
||||||
if (hasMiniMessageInteractiveTags(raw)) {
|
if (hasMiniMessageInteractiveTags(raw)) {
|
||||||
// MiniMessage-Pfad: interaktive Komponenten (click/hover)
|
// MiniMessage-Pfad: interaktive Komponenten (click/hover)
|
||||||
// Legacy-&-Farbcodes in MiniMessage-Äquivalente umwandeln damit
|
// Legacy-&-Farbcodes in MiniMessage-Äquivalente umwandeln damit
|
||||||
@@ -320,7 +352,7 @@ public class LanguageManager {
|
|||||||
Component component = MINI.deserialize(mm);
|
Component component = MINI.deserialize(mm);
|
||||||
|
|
||||||
// Prefix als Component voranstellen wenn nötig
|
// Prefix als Component voranstellen wenn nötig
|
||||||
if (needsPrefix(key)) {
|
if (addPrefix) {
|
||||||
Component prefixComp = MINI.deserialize(legacyToMiniMessage(
|
Component prefixComp = MINI.deserialize(legacyToMiniMessage(
|
||||||
color("&8[&6Ticket&8] &r")));
|
color("&8[&6Ticket&8] &r")));
|
||||||
component = prefixComp.append(component);
|
component = prefixComp.append(component);
|
||||||
@@ -332,7 +364,7 @@ public class LanguageManager {
|
|||||||
} else {
|
} else {
|
||||||
// Legacy-Pfad: §-Codes, kein Adventure nötig
|
// Legacy-Pfad: §-Codes, kein Adventure nötig
|
||||||
String text = color(raw);
|
String text = color(raw);
|
||||||
sender.sendMessage(needsPrefix(key) ? prefix + text : text);
|
sender.sendMessage(addPrefix ? prefix + text : text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,37 +486,6 @@ public class LanguageManager {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sendet eine Adventure-Component an einen CommandSender.
|
|
||||||
*
|
|
||||||
* Der Cast auf net.kyori.adventure.audience.Audience umgeht das compile-time
|
|
||||||
* Problem, dass Spigots CommandSender-Interface sendMessage(Component) nicht
|
|
||||||
* direkt exponiert – zur Laufzeit implementiert jeder CommandSender auf
|
|
||||||
* Paper/Spigot 1.18+ das Audience-Interface.
|
|
||||||
*/
|
|
||||||
private void sendComponent(CommandSender sender, Component component) {
|
|
||||||
if (sender instanceof net.kyori.adventure.audience.Audience audience) {
|
|
||||||
try {
|
|
||||||
audience.sendMessage(component);
|
|
||||||
} catch (NoSuchMethodError | AbstractMethodError e) {
|
|
||||||
// Fallback für reines Spigot ohne Adventure-Patch:
|
|
||||||
// Component in Legacy-String serialisieren (click/hover gehen verloren,
|
|
||||||
// aber der Text bleibt lesbar)
|
|
||||||
String legacy = LegacyComponentSerializer.legacySection().serialize(component);
|
|
||||||
sender.sendMessage(legacy);
|
|
||||||
if (plugin.isDebug()) {
|
|
||||||
plugin.getLogger().info("[LanguageManager] Adventure-API nicht verfügbar – "
|
|
||||||
+ "interaktive Tags werden als Plain-Text gesendet. "
|
|
||||||
+ "Wechsel auf Paper für volle MiniMessage-Unterstützung.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Kein Audience (z. B. alte Konsole) → Legacy-Fallback
|
|
||||||
String legacy = LegacyComponentSerializer.legacySection().serialize(component);
|
|
||||||
sender.sendMessage(legacy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Intern ───────────────────────────────────────────────────────────────
|
// ── Intern ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private boolean needsPrefix(String key) {
|
private boolean needsPrefix(String key) {
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ public class TicketManager {
|
|||||||
/**
|
/**
|
||||||
* Benachrichtigt alle Supporter/Admins über ein neues Ticket.
|
* Benachrichtigt alle Supporter/Admins über ein neues Ticket.
|
||||||
* Bei BungeeCord wird die Nachricht an alle Server weitergeleitet.
|
* Bei BungeeCord wird die Nachricht an alle Server weitergeleitet.
|
||||||
|
*
|
||||||
|
* Die gui-hint-Nachricht wird über lang().send() geroutet, damit
|
||||||
|
* ein <click:run_command:...>-Tag in der lang.yml funktioniert.
|
||||||
*/
|
*/
|
||||||
public void notifyTeam(Ticket ticket) {
|
public void notifyTeam(Ticket ticket) {
|
||||||
String creatorName = ticket.getCreatorName() != null ? ticket.getCreatorName() : "Unbekannt";
|
String creatorName = ticket.getCreatorName() != null ? ticket.getCreatorName() : "Unbekannt";
|
||||||
@@ -66,21 +69,24 @@ public class TicketManager {
|
|||||||
serverInfo = plugin.lang().format("notify.team-server", "{server}", ticket.getServerName());
|
serverInfo = plugin.lang().format("notify.team-server", "{server}", ticket.getServerName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Haupt-Benachrichtigung (plain Legacy-String, kein MiniMessage nötig)
|
||||||
String msg = plugin.lang().format("ticket.new-notify",
|
String msg = plugin.lang().format("ticket.new-notify",
|
||||||
"{player}", creatorName,
|
"{player}", creatorName,
|
||||||
"{message}", message,
|
"{message}", message,
|
||||||
"{id}", String.valueOf(ticket.getId()))
|
"{id}", String.valueOf(ticket.getId()))
|
||||||
+ categoryInfo + priorityInfo + serverInfo;
|
+ categoryInfo + priorityInfo + serverInfo;
|
||||||
|
|
||||||
String guiHint = plugin.lang().get("notify.gui-hint");
|
|
||||||
|
|
||||||
if (plugin.isBungeeCordEnabled()) {
|
if (plugin.isBungeeCordEnabled()) {
|
||||||
plugin.getBungeeMessenger().broadcastTeamNotification(msg + "\n" + guiHint);
|
// BungeeCord: Roh-String broadcasten (gui-hint separat per sendRaw)
|
||||||
|
plugin.getBungeeMessenger().broadcastTeamNotification(msg);
|
||||||
|
plugin.getBungeeMessenger().broadcastTeamNotification(
|
||||||
|
plugin.lang().get("notify.gui-hint"));
|
||||||
} else {
|
} else {
|
||||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||||
if (p.hasPermission("ticket.support") || p.hasPermission("ticket.admin")) {
|
if (p.hasPermission("ticket.support") || p.hasPermission("ticket.admin")) {
|
||||||
p.sendMessage(msg);
|
p.sendMessage(msg);
|
||||||
p.sendMessage(guiHint);
|
// gui-hint über send() routen → MiniMessage greift wenn Tags vorhanden
|
||||||
|
plugin.lang().send(p, "notify.gui-hint");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,14 +126,13 @@ public class TicketManager {
|
|||||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||||
if (!player.isOnline()) return;
|
if (!player.isOnline()) return;
|
||||||
if (t.getStatus() == TicketStatus.CLAIMED) {
|
if (t.getStatus() == TicketStatus.CLAIMED) {
|
||||||
player.sendMessage(plugin.lang().format("ticket.claimed-notify",
|
plugin.lang().send(player, "ticket.claimed-notify",
|
||||||
"{id}", String.valueOf(t.getId()), "{claimer}", name));
|
"{id}", String.valueOf(t.getId()), "{claimer}", name);
|
||||||
} else {
|
} else {
|
||||||
String forwardedTo = t.getForwardedToName() != null ? t.getForwardedToName() : "einen Supporter";
|
String forwardedTo = t.getForwardedToName() != null ? t.getForwardedToName() : "einen Supporter";
|
||||||
player.sendMessage(plugin.lang().format("ticket.forwarded-creator",
|
plugin.lang().send(player, "ticket.forwarded-creator",
|
||||||
"{id}", String.valueOf(t.getId()), "{supporter}", forwardedTo));
|
"{id}", String.valueOf(t.getId()), "{supporter}", forwardedTo);
|
||||||
}
|
}
|
||||||
// Flag NACH der Nachricht setzen – sicher im Hauptthread
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(plugin,
|
Bukkit.getScheduler().runTaskAsynchronously(plugin,
|
||||||
() -> plugin.getDatabaseManager().markClaimerNotified(t.getId()));
|
() -> plugin.getDatabaseManager().markClaimerNotified(t.getId()));
|
||||||
});
|
});
|
||||||
@@ -163,6 +168,14 @@ public class TicketManager {
|
|||||||
notifyCreatorClosed(ticket, null);
|
notifyCreatorClosed(ticket, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Benachrichtigt den Ersteller über die Schließung seines Tickets.
|
||||||
|
*
|
||||||
|
* Der Rating-Prompt wird über lang().sendRaw() gesendet, damit
|
||||||
|
* <click:run_command:...>-Tags in der lang.yml tatsächlich funktionieren.
|
||||||
|
* Dazu werden die einzelnen Keys zusammengebaut und als ein String
|
||||||
|
* durch die MiniMessage-Pipeline geschickt.
|
||||||
|
*/
|
||||||
public void notifyCreatorClosed(Ticket ticket, String closerName) {
|
public void notifyCreatorClosed(Ticket ticket, String closerName) {
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () ->
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () ->
|
||||||
plugin.getDatabaseManager().markCloseNotified(ticket.getId()));
|
plugin.getDatabaseManager().markCloseNotified(ticket.getId()));
|
||||||
@@ -170,36 +183,50 @@ public class TicketManager {
|
|||||||
String comment = (ticket.getCloseComment() != null && !ticket.getCloseComment().isEmpty())
|
String comment = (ticket.getCloseComment() != null && !ticket.getCloseComment().isEmpty())
|
||||||
? ticket.getCloseComment() : "";
|
? ticket.getCloseComment() : "";
|
||||||
|
|
||||||
String msg = plugin.lang().format("ticket.closed-notify", "{id}", String.valueOf(ticket.getId()));
|
// Schließ-Nachricht (normaler send()-Pfad reicht)
|
||||||
|
String closedKey = "ticket.closed-notify";
|
||||||
|
|
||||||
// Bewertungsaufforderung aufbauen
|
// Rating-Prompt: Keys einzeln holen und zu einem String zusammenbauen,
|
||||||
String ratingMsg = null;
|
// damit Platzhalter korrekt ersetzt werden, BEVOR sendRaw() aufgerufen wird.
|
||||||
|
String ratingRaw = null;
|
||||||
if (plugin.getConfig().getBoolean("rating-enabled", true)) {
|
if (plugin.getConfig().getBoolean("rating-enabled", true)) {
|
||||||
String id = String.valueOf(ticket.getId());
|
String id = String.valueOf(ticket.getId());
|
||||||
ratingMsg = plugin.lang().get("rating.prompt-header") + "\n"
|
ratingRaw = plugin.lang().getRaw("rating.prompt-header") + "\n"
|
||||||
+ plugin.lang().get("rating.prompt-title") + "\n"
|
+ plugin.lang().getRaw("rating.prompt-title") + "\n"
|
||||||
+ plugin.lang().format("rating.prompt-good", "{id}", id) + "\n"
|
+ plugin.lang().getRaw("rating.prompt-good").replace("{id}", id) + "\n"
|
||||||
+ plugin.lang().format("rating.prompt-bad", "{id}", id) + "\n"
|
+ plugin.lang().getRaw("rating.prompt-bad").replace("{id}", id) + "\n"
|
||||||
+ plugin.lang().get("rating.prompt-footer");
|
+ plugin.lang().getRaw("rating.prompt-footer");
|
||||||
|
// {cmd_rate}-Platzhalter ebenfalls ersetzen
|
||||||
|
ratingRaw = ratingRaw.replace("{cmd_rate}", plugin.lang().getCmdName("rate"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String finalRatingRaw = ratingRaw;
|
||||||
|
|
||||||
Player creator = Bukkit.getPlayer(ticket.getCreatorUUID());
|
Player creator = Bukkit.getPlayer(ticket.getCreatorUUID());
|
||||||
if (creator != null && creator.isOnline()) {
|
if (creator != null && creator.isOnline()) {
|
||||||
creator.sendMessage(msg);
|
// Schließ-Nachricht
|
||||||
|
plugin.lang().send(creator, closedKey, "{id}", String.valueOf(ticket.getId()));
|
||||||
|
// Kommentar des Supports
|
||||||
if (!comment.isEmpty())
|
if (!comment.isEmpty())
|
||||||
creator.sendMessage(plugin.lang().format("ticket.close-comment-label", "{comment}", comment));
|
creator.sendMessage(plugin.lang().format("ticket.close-comment-label", "{comment}", comment));
|
||||||
if (ratingMsg != null)
|
// Rating-Prompt: über sendRaw() damit MiniMessage-Tags greifen
|
||||||
creator.sendMessage(ratingMsg);
|
if (finalRatingRaw != null)
|
||||||
|
plugin.lang().sendRaw(creator, finalRatingRaw);
|
||||||
|
|
||||||
} else if (plugin.isBungeeCordEnabled()) {
|
} else if (plugin.isBungeeCordEnabled()) {
|
||||||
plugin.getBungeeMessenger().sendMessageToPlayer(ticket.getCreatorUUID(), ticket.getCreatorName(), msg);
|
String closedMsg = plugin.lang().format(closedKey, "{id}", String.valueOf(ticket.getId()));
|
||||||
|
plugin.getBungeeMessenger().sendMessageToPlayer(ticket.getCreatorUUID(), ticket.getCreatorName(), closedMsg);
|
||||||
if (!comment.isEmpty())
|
if (!comment.isEmpty())
|
||||||
plugin.getBungeeMessenger().sendMessageToPlayer(
|
plugin.getBungeeMessenger().sendMessageToPlayer(
|
||||||
ticket.getCreatorUUID(), ticket.getCreatorName(),
|
ticket.getCreatorUUID(), ticket.getCreatorName(),
|
||||||
plugin.lang().format("ticket.close-comment-label", "{comment}", comment));
|
plugin.lang().format("ticket.close-comment-label", "{comment}", comment));
|
||||||
if (ratingMsg != null)
|
// Im BungeeCord-Modus: Rating-Prompt als plain Text (click-Events
|
||||||
|
// funktionieren nur lokal über Adventure – BungeeCord-Messaging
|
||||||
|
// überträgt keine Component-Events, nur Text)
|
||||||
|
if (finalRatingRaw != null)
|
||||||
plugin.getBungeeMessenger().sendMessageToPlayer(
|
plugin.getBungeeMessenger().sendMessageToPlayer(
|
||||||
ticket.getCreatorUUID(), ticket.getCreatorName(), ratingMsg);
|
ticket.getCreatorUUID(), ticket.getCreatorName(),
|
||||||
|
plugin.lang().color(finalRatingRaw));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
savePendingClosedNotification(ticket, comment);
|
savePendingClosedNotification(ticket, comment);
|
||||||
@@ -230,42 +257,34 @@ public class TicketManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sendet die Hilfe-Nachricht an den Spieler.
|
* Sendet die Hilfe-Nachricht an den Spieler.
|
||||||
*
|
* Jede Zeile wird über lang().send() geroutet damit
|
||||||
* Die Befehlsnamen in den lang.yml-Schlüsseln (z.B. help.create) enthalten
|
* eventuelle MiniMessage-Tags funktionieren.
|
||||||
* {cmd_X}-Platzhalter. Der LanguageManager ersetzt diese automatisch
|
|
||||||
* anhand von language in config.yml:
|
|
||||||
*
|
|
||||||
* language: de → /ticket erstellen
|
|
||||||
* language: en → /ticket create
|
|
||||||
* language: both → /ticket create (erstellen)
|
|
||||||
*
|
|
||||||
* Hier muss kein manueller Sprachcode gelesen werden.
|
|
||||||
*/
|
*/
|
||||||
public void sendHelpMessage(Player player) {
|
public void sendHelpMessage(Player player) {
|
||||||
player.sendMessage(plugin.lang().get("general.separator"));
|
plugin.lang().send(player, "general.separator");
|
||||||
player.sendMessage(plugin.lang().get("help.header"));
|
plugin.lang().send(player, "help.header");
|
||||||
player.sendMessage(plugin.lang().get("general.separator"));
|
plugin.lang().send(player, "general.separator");
|
||||||
player.sendMessage(plugin.lang().get("help.create"));
|
plugin.lang().send(player, "help.create");
|
||||||
player.sendMessage(plugin.lang().get("help.list"));
|
plugin.lang().send(player, "help.list");
|
||||||
player.sendMessage(plugin.lang().get("help.comment"));
|
plugin.lang().send(player, "help.comment");
|
||||||
|
|
||||||
if (plugin.getConfig().getBoolean("rating-enabled", true))
|
if (plugin.getConfig().getBoolean("rating-enabled", true))
|
||||||
player.sendMessage(plugin.lang().get("help.rate"));
|
plugin.lang().send(player, "help.rate");
|
||||||
|
|
||||||
if (player.hasPermission("ticket.support") || player.hasPermission("ticket.admin")) {
|
if (player.hasPermission("ticket.support") || player.hasPermission("ticket.admin")) {
|
||||||
player.sendMessage(plugin.lang().get("help.claim"));
|
plugin.lang().send(player, "help.claim");
|
||||||
player.sendMessage(plugin.lang().get("help.close"));
|
plugin.lang().send(player, "help.close");
|
||||||
}
|
}
|
||||||
if (player.hasPermission("ticket.admin")) {
|
if (player.hasPermission("ticket.admin")) {
|
||||||
player.sendMessage(plugin.lang().get("help.forward"));
|
plugin.lang().send(player, "help.forward");
|
||||||
player.sendMessage(plugin.lang().get("help.blacklist"));
|
plugin.lang().send(player, "help.blacklist");
|
||||||
player.sendMessage(plugin.lang().get("help.reload"));
|
plugin.lang().send(player, "help.reload");
|
||||||
player.sendMessage(plugin.lang().get("help.stats"));
|
plugin.lang().send(player, "help.stats");
|
||||||
}
|
}
|
||||||
player.sendMessage(plugin.lang().get("general.separator"));
|
plugin.lang().send(player, "general.separator");
|
||||||
|
|
||||||
if (player.hasPermission("ticket.admin") && plugin.isBungeeCordEnabled())
|
if (player.hasPermission("ticket.admin") && plugin.isBungeeCordEnabled())
|
||||||
player.sendMessage(plugin.lang().format("help.bungee-status", "{server}", plugin.getServerName()));
|
plugin.lang().send(player, "help.bungee-status", "{server}", plugin.getServerName());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Interne Hilfsmethoden ─────────────────────────────────────────────
|
// ── Interne Hilfsmethoden ─────────────────────────────────────────────
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ ticket:
|
|||||||
# BENACHRICHTIGUNGEN (Team / GUI-Hinweis)
|
# BENACHRICHTIGUNGEN (Team / GUI-Hinweis)
|
||||||
# ============================================================
|
# ============================================================
|
||||||
notify:
|
notify:
|
||||||
gui-hint: "&7» Klicke &e{cmd_list} &7um die Übersicht zu öffnen."
|
gui-hint: "&7» <click:run_command:/ticket liste><yellow>Klicke hier</yellow></click> &7um die Übersicht zu öffnen."
|
||||||
team-category: " §7[§r{category}§7]"
|
team-category: " §7[§r{category}§7]"
|
||||||
team-priority: " §7Priorität: §r{priority}"
|
team-priority: " §7Priorität: §r{priority}"
|
||||||
team-server: " §7Server: §b{server}"
|
team-server: " §7Server: §b{server}"
|
||||||
@@ -139,8 +139,8 @@ rating:
|
|||||||
invalid: "&cUngültige Bewertung! Benutze &egood &coder &ebad&c."
|
invalid: "&cUngültige Bewertung! Benutze &egood &coder &ebad&c."
|
||||||
prompt-header: "򇨣&m "
|
prompt-header: "򇨣&m "
|
||||||
prompt-title: "&6Wie zufrieden bist du mit dem Support?"
|
prompt-title: "&6Wie zufrieden bist du mit dem Support?"
|
||||||
prompt-good: "&a{cmd_rate} {id} good &7– 👍 Gut"
|
prompt-good: "<green><click:run_command:/ticket bewerten {id} good>&a👍 Gut bewerten</click></green>"
|
||||||
prompt-bad: "&c{cmd_rate} {id} bad &7– 👎 Schlecht"
|
prompt-bad: "<red><click:run_command:/ticket bewerten {id} bad>&c👎 Schlecht bewerten</click></red>"
|
||||||
prompt-footer: "򇨣&m "
|
prompt-footer: "򇨣&m "
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -538,7 +538,7 @@ gui:
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
join:
|
join:
|
||||||
open-tickets: "&eEs gibt noch &6{count} &eoffene Ticket(s)!"
|
open-tickets: "&eEs gibt noch &6{count} &eoffene Ticket(s)!"
|
||||||
open-tickets-hint: "&7» Tippe &e{cmd_list} &7für die Übersicht."
|
open-tickets-hint: "&7» <click:run_command:/ticket liste><yellow>Klicke hier</yellow></click> &7für die Ticket-Übersicht."
|
||||||
teleport-world-missing: "&cTeleport-Zielwelt &e{world} &cnicht gefunden!"
|
teleport-world-missing: "&cTeleport-Zielwelt &e{world} &cnicht gefunden!"
|
||||||
teleport-success: "&7Du wurdest zur Ticket-Position teleportiert. &8({coords})"
|
teleport-success: "&7Du wurdest zur Ticket-Position teleportiert. &8({coords})"
|
||||||
pending-header: "&6Ticket-Benachrichtigungen &7(während du offline warst):"
|
pending-header: "&6Ticket-Benachrichtigungen &7(während du offline warst):"
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ ticket:
|
|||||||
# NOTIFICATIONS (Team / GUI hint)
|
# NOTIFICATIONS (Team / GUI hint)
|
||||||
# ============================================================
|
# ============================================================
|
||||||
notify:
|
notify:
|
||||||
gui-hint: "&7» Click &e{cmd_list} &7to open the overview."
|
gui-hint: "&7» <click:run_command:/ticket list><yellow>Click here</yellow></click> &7to open the overview."
|
||||||
team-category: " §7[§r{category}§7]"
|
team-category: " §7[§r{category}§7]"
|
||||||
team-priority: " §7Priority: §r{priority}"
|
team-priority: " §7Priority: §r{priority}"
|
||||||
team-server: " §7Server: §b{server}"
|
team-server: " §7Server: §b{server}"
|
||||||
@@ -139,8 +139,8 @@ rating:
|
|||||||
invalid: "&cInvalid rating! Use &egood &cor &ebad&c."
|
invalid: "&cInvalid rating! Use &egood &cor &ebad&c."
|
||||||
prompt-header: "򽸱&m "
|
prompt-header: "򽸱&m "
|
||||||
prompt-title: "&6How satisfied are you with the support?"
|
prompt-title: "&6How satisfied are you with the support?"
|
||||||
prompt-good: "&a{cmd_rate} {id} good &7– 👍 Good"
|
prompt-good: "<green><click:run_command:/ticket rate {id} good>&a👍 Rate Good</click></green>"
|
||||||
prompt-bad: "&c{cmd_rate} {id} bad &7– 👎 Bad"
|
prompt-bad: "<red><click:run_command:/ticket rate {id} bad>&c👎 Rate Bad</click></red>"
|
||||||
prompt-footer: "򽸱&m "
|
prompt-footer: "򽸱&m "
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -538,7 +538,7 @@ gui:
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
join:
|
join:
|
||||||
open-tickets: "&eThere are still &6{count} &eopen ticket(s)!"
|
open-tickets: "&eThere are still &6{count} &eopen ticket(s)!"
|
||||||
open-tickets-hint: "&7» Type &e{cmd_list} &7for the overview."
|
open-tickets-hint: "&7» <click:run_command:/ticket list><yellow>Click here</yellow></click> &7for the ticket overview."
|
||||||
teleport-world-missing: "&cTeleport target world &e{world} &cnot found!"
|
teleport-world-missing: "&cTeleport target world &e{world} &cnot found!"
|
||||||
teleport-success: "&7You have been teleported to the ticket location. &8({coords})"
|
teleport-success: "&7You have been teleported to the ticket location. &8({coords})"
|
||||||
pending-header: "&6Ticket notifications &7(while you were offline):"
|
pending-header: "&6Ticket notifications &7(while you were offline):"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: TicketSystem
|
name: TicketSystem
|
||||||
version: 1.1.5
|
version: 1.1.6
|
||||||
main: de.ticketsystem.TicketPlugin
|
main: de.ticketsystem.TicketPlugin
|
||||||
api-version: 1.20
|
api-version: 1.20
|
||||||
author: M_Viper
|
author: M_Viper
|
||||||
|
|||||||
Reference in New Issue
Block a user