4 Commits
1.0.4 ... 1.0.5

Author SHA1 Message Date
cd3567d157 Update from Git Manager GUI 2026-03-27 15:34:13 +01:00
98d08b627d Upload via Git Manager GUI - pom.xml 2026-03-27 14:34:13 +00:00
114b0e83d7 Upload pom.xml via GUI 2026-03-24 15:32:53 +00:00
df4ee6c2e9 Update from Git Manager GUI 2026-03-24 16:32:52 +01:00
13 changed files with 489 additions and 11 deletions

View File

@@ -5,7 +5,7 @@
<groupId>me.viper</groupId>
<artifactId>Team</artifactId>
<version>1.0.2</version>
<version>1.0.5</version>
<name>TeamPlugin</name>
<description>Erweitertes konfigurierbares Team-Plugin (Spigot 1.21.x)</description>

View File

@@ -4,6 +4,7 @@ import me.viper.teamplugin.commands.TeamCommand;
import me.viper.teamplugin.listener.InventoryListener;
import me.viper.teamplugin.manager.DataManager;
import me.viper.teamplugin.manager.LangManager;
import me.viper.teamplugin.util.ConfigUpdater;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin;
@@ -16,8 +17,9 @@ public class Main extends JavaPlugin {
instance = this;
saveDefaultConfig(); // config.yml
saveResource("lang_de.yml", false); // German lang file (only if absent)
saveResource("lang_en.yml", false); // English lang file (only if absent)
ConfigUpdater.update(); // fehlende Keys automatisch ergänzen
if (!new java.io.File(getDataFolder(), "lang_de.yml").exists()) saveResource("lang_de.yml", false);
if (!new java.io.File(getDataFolder(), "lang_en.yml").exists()) saveResource("lang_en.yml", false);
LangManager.setup();
DataManager.setup();

View File

@@ -7,6 +7,7 @@ import me.viper.teamplugin.gui.MailboxGUI;
import me.viper.teamplugin.gui.SettingsGUI;
import me.viper.teamplugin.gui.TeamGUI;
import me.viper.teamplugin.manager.*;
import me.viper.teamplugin.util.ConfigUpdater;
import me.viper.teamplugin.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
@@ -54,6 +55,7 @@ public class TeamCommand implements CommandExecutor, TabCompleter {
private static final String C_APPLY = "apply";
private static final String C_LOG = "log";
private static final String C_MAILBOX = "mailbox";
private static final String C_STATUS = "status";
// apply sub-sub-commands
private static final String C_LIST = "list";
@@ -74,7 +76,9 @@ public class TeamCommand implements CommandExecutor, TabCompleter {
Map.entry("suchen", C_SEARCH),
Map.entry("bewerben", C_APPLY),
Map.entry("protokoll", C_LOG),
Map.entry("postfach", C_MAILBOX)
Map.entry("postfach", C_MAILBOX),
Map.entry("status", C_STATUS),
Map.entry("offline", C_STATUS)
);
// apply sub-sub DE aliases
@@ -120,7 +124,8 @@ public class TeamCommand implements CommandExecutor, TabCompleter {
LangManager.getCmd("cmd_search"),
LangManager.getCmd("cmd_apply"),
LangManager.getCmd("cmd_log"),
LangManager.getCmd("cmd_mailbox")
LangManager.getCmd("cmd_mailbox"),
LangManager.getCmd("cmd_status")
);
}
@@ -239,6 +244,7 @@ public class TeamCommand implements CommandExecutor, TabCompleter {
case C_RELOAD -> {
if (!sender.hasPermission("teamplugin.admin")) { sender.sendMessage(LangManager.get("no_permission")); return true; }
Main.getInstance().reloadConfig();
ConfigUpdater.update();
LangManager.setup();
DataManager.reloadData();
MailboxManager.reload();
@@ -255,7 +261,7 @@ public class TeamCommand implements CommandExecutor, TabCompleter {
String rankDisplay = Main.getInstance().getConfig().getString("rank-settings." + infoRank + ".display", infoRank);
String iso = DataManager.getJoinDate(infoName);
String joinDate = (iso != null && !iso.isEmpty()) ? Utils.prettifyIso(iso) : "\u00a77\u2014";
boolean isOnline = Bukkit.getOfflinePlayer(infoName).isOnline();
boolean isOnline = PresenceManager.isShownAsOnline(infoName);
String statusOn = Main.getInstance().getConfig().getString("status.online", "&a\uD83D\uDFE2 Online");
String statusOff = Main.getInstance().getConfig().getString("status.offline", "&c\uD83D\uDD34 Offline");
sender.sendMessage(Utils.color(Utils.replace(LangManager.get("info_header"), "%player%", infoName)));
@@ -264,6 +270,32 @@ public class TeamCommand implements CommandExecutor, TabCompleter {
sender.sendMessage(Utils.color(Utils.replace(LangManager.get("info_status"), "%status%", isOnline ? statusOn : statusOff)));
}
// ── status ────────────────────────────────────────────────
case C_STATUS -> {
if (!(sender instanceof Player p)) { sender.sendMessage(LangManager.get("only_player")); return true; }
if (findRank(p.getName()) == null) {
p.sendMessage(Utils.color(LangManager.get("status_only_team")));
return true;
}
String mode = (args.length >= 2) ? args[1].toLowerCase() : "toggle";
if (mode.equals("status")) {
boolean forced = PresenceManager.isForcedOffline(p.getName());
p.sendMessage(Utils.color(forced
? LangManager.get("status_state_forced")
: LangManager.get("status_state_normal")));
return true;
}
boolean newForced = !PresenceManager.isForcedOffline(p.getName());
PresenceManager.setForcedOffline(p.getName(), newForced);
p.sendMessage(Utils.color(newForced
? LangManager.get("status_enabled")
: LangManager.get("status_disabled")));
}
// ── search ────────────────────────────────────────────────
case C_SEARCH -> {
if (args.length < 2) { sender.sendMessage(Utils.color(LangManager.get("prefix")) + "\u00a7cUsage: /team " + LangManager.getCmd("cmd_search") + " <n>"); return true; }
@@ -427,6 +459,7 @@ public class TeamCommand implements CommandExecutor, TabCompleter {
case C_SEARCH -> filter(allTeamMembers(), args[1]);
case C_LOG -> List.of("10", "25", "50");
case C_APPLY -> filter(activeApplySubs(sender.hasPermission("teamplugin.admin")), args[1]);
case C_STATUS -> filter(List.of("toggle", "status"), args[1]);
default -> new ArrayList<>();
};

View File

@@ -4,6 +4,8 @@ import me.viper.teamplugin.Main;
import me.viper.teamplugin.manager.BackupManager;
import me.viper.teamplugin.manager.DataManager;
import me.viper.teamplugin.manager.LangManager;
import me.viper.teamplugin.manager.PresenceManager;
import me.viper.teamplugin.util.ConfigUpdater;
import me.viper.teamplugin.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@@ -59,6 +61,11 @@ public class SettingsGUI {
}
}
// Fallback: show status toggle even if not configured in admin-buttons.
if (!hasButtonKey(buttons, "status_toggle")) {
inv.setItem(24, createStatusToggleItem(player));
}
player.openInventory(inv);
}
@@ -89,6 +96,7 @@ public class SettingsGUI {
}
case "reload" -> {
Main.getInstance().reloadConfig();
ConfigUpdater.update();
LangManager.setup();
DataManager.reloadData();
LangManager.save();
@@ -113,13 +121,32 @@ public class SettingsGUI {
else p.sendMessage(Utils.color(LangManager.get("prefix")) + "§cBackup fehlgeschlagen.");
p.closeInventory();
}
case "status_toggle" -> {
boolean next = !PresenceManager.isForcedOffline(p.getName());
PresenceManager.setForcedOffline(p.getName(), next);
p.sendMessage(Utils.color(next
? LangManager.get("status_enabled")
: LangManager.get("status_disabled")));
openSettings(p);
}
default -> {
p.sendMessage(Utils.color(LangManager.get("prefix")) + "§cUnbekannter Button: " + key);
}
}
return;
}
}
}
// Fallback click handler for the built-in status toggle item.
if (isStatusToggleTitle(title)) {
boolean next = !PresenceManager.isForcedOffline(p.getName());
PresenceManager.setForcedOffline(p.getName(), next);
p.sendMessage(Utils.color(next
? LangManager.get("status_enabled")
: LangManager.get("status_disabled")));
openSettings(p);
}
}
/**
@@ -128,4 +155,37 @@ public class SettingsGUI {
public static String getGuiTitle() {
return LangManager.get("settings_gui_title");
}
private static boolean hasButtonKey(List<?> buttons, String key) {
if (buttons == null || key == null) return false;
for (Object o : buttons) {
if (!(o instanceof Map<?, ?> map)) continue;
Object raw = map.get("key");
if (raw instanceof String s && s.equalsIgnoreCase(key)) return true;
}
return false;
}
private static ItemStack createStatusToggleItem(Player player) {
boolean forced = PresenceManager.isForcedOffline(player.getName());
Material mat = forced ? Material.REDSTONE_TORCH : Material.LIME_DYE;
ItemStack item = new ItemStack(mat);
ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(Utils.color(LangManager.get("settings_status_toggle_title")));
meta.setLore(List.of(
Utils.color(Utils.replace(LangManager.get("settings_status_toggle_lore_state"), "%state%",
forced ? LangManager.get("settings_status_state_offline") : LangManager.get("settings_status_state_online"))),
Utils.color(LangManager.get("settings_status_toggle_lore_vanish")),
Utils.color(LangManager.get("settings_status_toggle_lore_click"))
));
item.setItemMeta(meta);
}
return item;
}
private static boolean isStatusToggleTitle(String title) {
return title != null && title.equals(Utils.color(LangManager.get("settings_status_toggle_title")));
}
}

View File

@@ -4,6 +4,7 @@ import me.viper.teamplugin.Main;
import me.viper.teamplugin.manager.DataManager;
import me.viper.teamplugin.manager.LangManager;
import me.viper.teamplugin.manager.MessageManager;
import me.viper.teamplugin.manager.PresenceManager;
import me.viper.teamplugin.util.SkinResolver;
import me.viper.teamplugin.util.Utils;
import org.bukkit.Bukkit;
@@ -82,6 +83,28 @@ public class TeamGUI {
if (slot < 0 || slot >= GUI_SIZE) continue;
inv.setItem(slot, createRankOverviewBlock(rank));
}
// Info-Item
if (cfg.getBoolean("gui.info-item.enabled", false)) {
int infoSlot = cfg.getInt("gui.info-item.slot", 49);
if (infoSlot >= 0 && infoSlot < GUI_SIZE) {
String skullTex = cfg.getString("gui.info-item.skull_texture", "");
ItemStack infoItem = (skullTex != null && !skullTex.isEmpty())
? buildCustomSkull(skullTex)
: new ItemStack(parseMaterial(cfg.getString("gui.info-item.material", "BOOK"), Material.BOOK));
String infoDisplay = cfg.getString("gui.info-item.display", "&eInfo");
List<String> infoLore = cfg.getStringList("gui.info-item.lore")
.stream().map(Utils::color).collect(Collectors.toList());
ItemMeta infoMeta = infoItem.getItemMeta();
if (infoMeta != null) {
infoMeta.setDisplayName(Utils.color(infoDisplay));
infoMeta.setLore(infoLore);
infoItem.setItemMeta(infoMeta);
}
inv.setItem(infoSlot, infoItem);
}
}
player.openInventory(inv);
}
@@ -267,6 +290,20 @@ public class TeamGUI {
return;
}
}
// Info-Item click
if (cfg.getBoolean("gui.info-item.enabled", false)
&& slot == cfg.getInt("gui.info-item.slot", 49)) {
String action = cfg.getString("gui.info-item.on-click", "");
if (action != null && !action.isEmpty()) {
player.closeInventory();
if (action.startsWith("cmd:")) {
player.performCommand(action.substring(4));
} else {
player.sendMessage(Utils.color(action));
}
}
}
}
public static void handleRankPageClick(Player player, int slot, String currentRank) {
@@ -389,8 +426,7 @@ public class TeamGUI {
String statusOnline = cfg.getString("status.online", "&a\uD83D\uDFE2 Online");
String statusOffline = cfg.getString("status.offline", "&c\uD83D\uDD34 Offline");
@SuppressWarnings("deprecation")
boolean online = Bukkit.getOfflinePlayer(name).isOnline();
boolean online = PresenceManager.isShownAsOnline(name);
lore.add(Utils.color("&7Status&8: " + (online ? statusOnline : statusOffline)));
String iso = DataManager.getData().getString("JoinDates." + name, "");

View File

@@ -13,6 +13,8 @@ import java.util.*;
import java.util.stream.Collectors;
public class DataManager {
private static final String FORCE_OFFLINE_PATH = "Status.force-offline";
private static File file;
private static FileConfiguration data;
@@ -94,6 +96,7 @@ public class DataManager {
}
if (removed) {
data.set("JoinDates." + name, null);
data.set(FORCE_OFFLINE_PATH + "." + normalizeName(name), null);
save();
}
}
@@ -177,4 +180,17 @@ public class DataManager {
public static String getJoinDate(String name) {
return data.getString("JoinDates." + name, "");
}
public static boolean isForcedOffline(String name) {
return data.getBoolean(FORCE_OFFLINE_PATH + "." + normalizeName(name), false);
}
public static void setForcedOffline(String name, boolean forcedOffline) {
data.set(FORCE_OFFLINE_PATH + "." + normalizeName(name), forcedOffline ? true : null);
save();
}
private static String normalizeName(String name) {
return name == null ? "" : name.toLowerCase(Locale.ROOT);
}
}

View File

@@ -6,6 +6,10 @@ import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
public class LangManager {
@@ -17,6 +21,8 @@ public class LangManager {
// ── Setup ─────────────────────────────────────────────────────────
public static void setup() {
syncLanguageFiles();
String lang = Main.getInstance().getConfig().getString("language", "de").toLowerCase();
String fileName = "lang_" + lang + ".yml";
@@ -31,6 +37,58 @@ public class LangManager {
"[LangManager] Loaded language: " + lang + " (" + fileName + ")");
}
private static void syncLanguageFiles() {
syncLanguageFile("lang_de.yml");
syncLanguageFile("lang_en.yml");
}
private static void syncLanguageFile(String fileName) {
Main plugin = Main.getInstance();
File target = new File(plugin.getDataFolder(), fileName);
if (!target.exists()) {
plugin.saveResource(fileName, false);
plugin.getLogger().info("[LangManager] Created missing file: " + fileName);
return;
}
YamlConfiguration onDisk = YamlConfiguration.loadConfiguration(target);
YamlConfiguration defaults = loadLangDefaults(plugin, fileName);
if (defaults == null) return;
List<String> added = new ArrayList<>();
for (String path : defaults.getKeys(true)) {
if (defaults.isConfigurationSection(path)) continue;
if (!onDisk.isSet(path)) {
onDisk.set(path, defaults.get(path));
added.add(path);
}
}
if (added.isEmpty()) return;
try {
onDisk.save(target);
plugin.getLogger().info("[LangManager] " + fileName + ": " + added.size()
+ " missing key(s) added.");
} catch (IOException e) {
plugin.getLogger().warning("[LangManager] Failed to save " + fileName + ": " + e.getMessage());
}
}
private static YamlConfiguration loadLangDefaults(Main plugin, String fileName) {
try (InputStream in = plugin.getResource(fileName)) {
if (in == null) {
plugin.getLogger().warning("[LangManager] Missing bundled language file: " + fileName);
return null;
}
return YamlConfiguration.loadConfiguration(new InputStreamReader(in, StandardCharsets.UTF_8));
} catch (IOException e) {
plugin.getLogger().warning("[LangManager] Failed to load bundled " + fileName + ": " + e.getMessage());
return null;
}
}
// ── Getters ───────────────────────────────────────────────────────
public static String get(String path) {

View File

@@ -0,0 +1,64 @@
package me.viper.teamplugin.manager;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.metadata.MetadataValue;
import java.util.List;
/**
* Zentraler Präsenz-Status für Team-Anzeige.
* Spieler gelten als offline, wenn sie wirklich offline sind,
* manuell auf offline gesetzt wurden oder im Vanish sind.
*/
public final class PresenceManager {
private PresenceManager() {}
public static boolean isShownAsOnline(String playerName) {
if (playerName == null || playerName.isEmpty()) return false;
@SuppressWarnings("deprecation")
OfflinePlayer off = Bukkit.getOfflinePlayer(playerName);
if (!off.isOnline()) return false;
Player player = off.getPlayer();
if (player == null) return false;
if (DataManager.isForcedOffline(playerName)) return false;
return !isVanished(player);
}
public static boolean isForcedOffline(String playerName) {
return DataManager.isForcedOffline(playerName);
}
public static void setForcedOffline(String playerName, boolean forcedOffline) {
DataManager.setForcedOffline(playerName, forcedOffline);
}
private static boolean isVanished(Player player) {
if (player == null) return false;
// Common metadata keys used by vanish plugins.
// Important: check metadata BOOLEAN value, not just key existence.
if (hasTrueMetadata(player, "vanished")
|| hasTrueMetadata(player, "vanish")
|| hasTrueMetadata(player, "essentials.vanish")
|| hasTrueMetadata(player, "supervanish")) {
return true;
}
// Fallback for plugins that toggle entity invisibility directly.
return player.isInvisible();
}
private static boolean hasTrueMetadata(Player player, String key) {
List<MetadataValue> values = player.getMetadata(key);
for (MetadataValue value : values) {
if (value != null && value.asBoolean()) return true;
}
return false;
}
}

View File

@@ -0,0 +1,135 @@
package me.viper.teamplugin.util;
import me.viper.teamplugin.Main;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Versionierte config.yml-Migration:
* Es werden niemals pauschal alle fehlenden Keys ergänzt.
* Ergänzt werden nur explizit definierte, neue Migrations-Keys pro Version.
* User-verwaltete Rangbereiche werden nie automatisch zurückgeschrieben.
*/
public class ConfigUpdater {
private static final String CONFIG_VERSION_PATH = "config-version";
private static final Set<String> MIGRATION_EXCLUDED_ROOTS = Set.of(
"ranks",
"rank-settings"
);
/**
* Nur hier eingetragene Pfade werden bei einem Upgrade auf die jeweilige Version ergänzt.
* Format: targetVersion -> List<configPath>
*
* Wichtig: Nur wirklich neue Keys eintragen, niemals bestehende User-Bereiche.
*/
private static final Map<Integer, List<String>> MIGRATION_ADDITIONS = Map.of(
1, List.of()
);
public static void update() {
Main plugin = Main.getInstance();
File configFile = new File(plugin.getDataFolder(), "config.yml");
YamlConfiguration defaults = loadDefaults(plugin);
if (defaults == null) return;
YamlConfiguration onDisk = YamlConfiguration.loadConfiguration(configFile);
int defaultVersion = Math.max(1, defaults.getInt(CONFIG_VERSION_PATH, 1));
int diskVersion = onDisk.getInt(CONFIG_VERSION_PATH, 0);
if (diskVersion > defaultVersion) {
plugin.getLogger().warning("[Config] config.yml hat eine neuere Version (" + diskVersion
+ ") als dieses Plugin (" + defaultVersion + ").");
return;
}
if (diskVersion >= defaultVersion) {
// Bereits aktuell: keine Migration ausführen.
return;
}
List<String> added = new ArrayList<>();
// Migrationen inkrementell je Versionsschritt anwenden.
for (int targetVersion = diskVersion + 1; targetVersion <= defaultVersion; targetVersion++) {
List<String> additions = MIGRATION_ADDITIONS.getOrDefault(targetVersion, List.of());
for (String path : additions) {
addPathIfMissing(plugin, onDisk, defaults, path, added);
}
}
// Nach erfolgreicher Migration Version anheben.
onDisk.set(CONFIG_VERSION_PATH, defaultVersion);
try {
onDisk.save(configFile);
plugin.getLogger().info("[Config] Migration " + diskVersion + " -> " + defaultVersion
+ " abgeschlossen; " + added.size() + " fehlende Einstellung(en) ergänzt.");
} catch (IOException e) {
plugin.getLogger().warning("[Config] Fehler beim Speichern der config.yml: " + e.getMessage());
return;
}
// Neu gespeicherte Migration sofort in die Runtime laden.
plugin.reloadConfig();
}
private static YamlConfiguration loadDefaults(Main plugin) {
try (InputStream ds = plugin.getResource("config.yml")) {
if (ds == null) return null;
return YamlConfiguration.loadConfiguration(new InputStreamReader(ds));
} catch (IOException e) {
plugin.getLogger().warning("[Config] Fehler beim Laden der Default-config.yml: " + e.getMessage());
return null;
}
}
private static void addPathIfMissing(Main plugin,
YamlConfiguration onDisk,
YamlConfiguration defaults,
String path,
List<String> added) {
if (path == null || path.trim().isEmpty()) return;
if (shouldSkipAutoMerge(path)) return;
if (!defaults.isSet(path)) {
plugin.getLogger().warning("[Config] Migration-Key nicht in default config vorhanden: " + path);
return;
}
if (defaults.isConfigurationSection(path)) {
for (String relPath : defaults.getConfigurationSection(path).getKeys(true)) {
String fullPath = path + "." + relPath;
if (defaults.isConfigurationSection(fullPath)) continue;
if (shouldSkipAutoMerge(fullPath)) continue;
if (!onDisk.isSet(fullPath)) {
onDisk.set(fullPath, defaults.get(fullPath));
added.add(fullPath);
}
}
return;
}
if (!onDisk.isSet(path)) {
onDisk.set(path, defaults.get(path));
added.add(path);
}
}
/**
* User-managed rank sections must not be recreated automatically.
* Otherwise intentionally removed ranks reappear after /team reload.
*/
private static boolean shouldSkipAutoMerge(String path) {
int dot = path.indexOf('.');
String root = dot < 0 ? path : path.substring(0, dot);
return MIGRATION_EXCLUDED_ROOTS.contains(root);
}
}

View File

@@ -3,6 +3,11 @@
# GUI-Größe ist IMMER 54 und NICHT konfigurierbar.
# ══════════════════════════════════════════════════════
# Konfigurationsversion für automatische Migrationen
# Hinweis: Nur explizit in ConfigUpdater definierte neue Keys werden ergänzt.
# Es gibt kein pauschales Wiederherstellen fehlender Einträge.
config-version: 1
# ── Sprache / Language ───────────────────────────────────────────────
# de → Deutsche Befehle & Nachrichten (/team hinzufügen, entfernen …)
# en → English commands & messages (/team add, del …)
@@ -29,6 +34,38 @@ gui:
rank_page_title: "&8» &bTeam &7| "
background: "GRAY_STAINED_GLASS_PANE"
# ── Info-Item im Übersichts-GUI ─────────────────────────────────
# Zeigt dem Spieler, wie er sich bewerben kann.
# slot → Slot-Nummer im Übersichts-GUI (0-53)
# material → Beliebiges Vanilla-Material (z. B. BOOK, PAPER, MAP)
# display → Anzeigename (& Farbcodes erlaubt)
# lore → Zeilenliste (& Farbcodes erlaubt)
#
# on-click → Aktion beim Klicken (optional):
# Leer lassen / weglassen → kein Klick-Effekt
# Präfix „cmd:" → Befehl ausführen (als Spieler, ohne /)
# Beispiel: cmd:team bewerben
# Kein Präfix → Chat-Nachricht senden
# Beispiel: "&eBenutze /team bewerben um dich zu bewerben!"
#
# skull_texture → Skull statt material verwenden (optional)
# Gleiche Formate wie bei rank-settings (URL / 64-Hex / Base64 eyJ...)
# Wenn gesetzt, wird material ignoriert.
info-item:
enabled: true
slot: 49
material: BOOK
skull_texture: "http://textures.minecraft.net/texture/d01afe973c5482fdc71e6aa10698833c79c437f21308ea9a1a095746ec274a0f"
display: "&e&lBewirb dich!"
lore:
- "&7Möchtest du Teil unseres Teams werden?"
- ""
- "&eBefehl&8: &f/team bewerben"
- ""
- "&7Fülle die Bewerbung aus und schicke sie ab."
- "&7Wir melden uns so schnell wie möglich!"
on-click: "cmd:team bewerben"
# ── Rang-Einstellungen ──────────────────────────────────────────────
#
# Jeder Rang kann folgende Felder haben:
@@ -190,3 +227,12 @@ admin-buttons:
lore:
- "&7Bearbeite ranks & rank-settings"
- "&7in der config.yml"
- key: status_toggle
slot: 24
material: LIME_DYE
title: "&bStatus umschalten"
lore:
- "&7Schaltet deinen Team-Status"
- "&7zwischen online/offline um"
- "&8(Vanish wird automatisch als offline erkannt)"

View File

@@ -18,6 +18,7 @@ cmd_apply_accept: "annehmen"
cmd_apply_deny: "ablehnen"
cmd_log: "protokoll"
cmd_mailbox: "postfach"
cmd_status: "status"
# ── Allgemein ────────────────────────────────────────────────────────
no_permission: "%prefix%§cDazu hast du keine Berechtigung!"
@@ -46,6 +47,13 @@ info_joined: "%prefix%§7Beigetreten§8: §e%joindate%"
info_status: "%prefix%§7Status§8: %status%"
info_not_team: "%prefix%§c%player% ist kein Teammitglied."
# ── /team status ────────────────────────────────────────────────────
status_only_team: "%prefix%§cNur Teammitglieder können diesen Status setzen."
status_state_forced: "%prefix%§7Du wirst aktuell als §coffline §7angezeigt."
status_state_normal: "%prefix%§7Du wirst aktuell als §aonline §7angezeigt (sofern nicht vanished)."
status_enabled: "%prefix%§aOffline-Modus aktiviert. Du wirst in Team-Infos als offline angezeigt."
status_disabled: "%prefix%§aOffline-Modus deaktiviert. Du wirst wieder normal angezeigt."
# ── /team bewerben ───────────────────────────────────────────────────
apply_sent: "%prefix%§aDeine Bewerbung für §e%rank% §awurde eingereicht!"
apply_already: "%prefix%§cDu hast bereits eine offene Bewerbung."
@@ -71,6 +79,12 @@ settings_reload_lore:
settings_backup: "§eBackups verwalten"
settings_backup_lore:
- "§7Öffnet die Backup-Übersicht"
settings_status_toggle_title: "&bStatus umschalten"
settings_status_toggle_lore_state: "&7Aktuell: %state%"
settings_status_toggle_lore_vanish: "&8(Bei Vanish immer offline)"
settings_status_toggle_lore_click: "&eKlicken zum Umschalten"
settings_status_state_online: "&aOnline"
settings_status_state_offline: "&cOffline"
# ── Rang-Seite: Navigation ────────────────────────────────────────────
nav_prev_label: "§7« %rank%"

View File

@@ -17,6 +17,7 @@ cmd_apply_accept: "accept"
cmd_apply_deny: "deny"
cmd_log: "log"
cmd_mailbox: "mailbox"
cmd_status: "status"
# ── General ──────────────────────────────────────────────────────────
no_permission: "%prefix%§cYou don't have permission to do that!"
@@ -45,6 +46,13 @@ info_joined: "%prefix%§7Joined§8: §e%joindate%"
info_status: "%prefix%§7Status§8: %status%"
info_not_team: "%prefix%§c%player% is not a team member."
# ── /team status ────────────────────────────────────────────────────
status_only_team: "%prefix%§cOnly team members can change this status."
status_state_forced: "%prefix%§7You are currently shown as §coffline§7."
status_state_normal: "%prefix%§7You are currently shown as §aonline§7 (unless vanished)."
status_enabled: "%prefix%§aOffline mode enabled. You will be shown as offline in team info."
status_disabled: "%prefix%§aOffline mode disabled. You will be shown normally again."
# ── /team apply ───────────────────────────────────────────────────────
apply_sent: "%prefix%§aYour application for §e%rank% §ahas been submitted!"
apply_already: "%prefix%§cYou already have a pending application."
@@ -70,6 +78,12 @@ settings_reload_lore:
settings_backup: "§eManage backups"
settings_backup_lore:
- "§7Opens the backup overview"
settings_status_toggle_title: "&bToggle status"
settings_status_toggle_lore_state: "&7Current: %state%"
settings_status_toggle_lore_vanish: "&8(Always offline while vanished)"
settings_status_toggle_lore_click: "&eClick to toggle"
settings_status_state_online: "&aOnline"
settings_status_state_offline: "&cOffline"
# ── Rank page navigation ──────────────────────────────────────────────
nav_prev_label: "§7« %rank%"

View File

@@ -1,8 +1,8 @@
name: Team
version: 1.0.2
version: 1.0.5
main: me.viper.teamplugin.Main
api-version: 1.21
author: Viper
author: M_Viper
description: Erweiterbares Team-Plugin mit GUI, Backup/Restore und vielen Config-Optionen
commands: