Update from Git Manager GUI

This commit is contained in:
2026-01-27 00:02:21 +01:00
parent b4eeb2dee7
commit ce9c40137a
13 changed files with 1040 additions and 72 deletions

View File

@@ -0,0 +1,69 @@
package de.mviper.adventskalender;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.time.LocalDate;
import java.time.Month;
public class AdventCalendarExpansion extends PlaceholderExpansion {
@Override
public @NotNull String getIdentifier() {
return "ak";
}
@Override
public @NotNull String getAuthor() {
return "M_Viper";
}
@Override
public @NotNull String getVersion() {
return "2.0.0";
}
@Override
public boolean persist() {
return true; // Expansion bleibt nach PAPI-Reload registriert
}
@Override
public String onPlaceholderRequest(Player player, String identifier) {
if (player == null) return "";
// Aktuellen Tag ermitteln (Berücksichtigt den test_day aus der Config)
int testDay = Adventskalender.getInstance().getConfig().getInt("general.test_day", 0);
LocalDate date = LocalDate.now();
int currentDay = (testDay > 0) ? testDay : (date.getMonth() == Month.DECEMBER ? date.getDayOfMonth() : 0);
switch (identifier.toLowerCase()) {
// %ak_claimed% - Anzahl der bereits geöffneten Türchen
case "claimed":
return String.valueOf(DataHandler.getClaimedDays(player).size());
// %ak_day% - Der aktuelle Tag des Adventskalenders (1-24)
case "day":
return String.valueOf(currentDay);
// %ak_has_claimed_today% - Gibt "Ja" oder "Nein" zurück, ob heute schon geöffnet wurde
case "has_claimed_today":
if (currentDay == 0) return "Keine Adventszeit";
return DataHandler.hasClaimed(player, currentDay) ? "Ja" : "Nein";
// %ak_remaining% - Wie viele Türchen sind noch offen (für diesen Spieler)?
case "remaining":
int claimedCount = DataHandler.getClaimedDays(player).size();
return String.valueOf(24 - claimedCount);
// %ak_is_global% - Zeigt an, ob der globale Modus aktiv ist
case "is_global":
boolean isGlobal = Adventskalender.getInstance().getConfig().getBoolean("calendar.use_global_calendar", false);
return isGlobal ? "Global" : "Spieler-basiert";
}
return null; // Placeholder unbekannt
}
}

View File

@@ -0,0 +1,160 @@
package de.mviper.adventskalender;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import java.util.*;
import java.util.stream.Collectors;
public class AdventCommand implements CommandExecutor, TabCompleter {
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (args.length > 0 && args[0].equalsIgnoreCase("admin")) {
if (!sender.hasPermission("adventskalender.admin")) {
sender.sendMessage(LanguageManager.getMessage("messages.no_permission"));
return true;
}
// /ak admin reload
if (args.length == 2 && args[1].equalsIgnoreCase("reload")) {
Adventskalender.getInstance().reloadConfig();
LanguageManager.setup();
DataHandler.setup();
sender.sendMessage(LanguageManager.getMessage("messages.admin.reload_success"));
return true;
}
// /ak admin test <Tag/reset>
if (args.length == 3 && args[1].equalsIgnoreCase("test")) {
if (args[2].equalsIgnoreCase("reset")) {
Adventskalender.getInstance().getConfig().set("general.test_day", 0);
Adventskalender.getInstance().saveConfig();
sender.sendMessage("§e[Admin] §7Test-Modus §cbeendet§7. Das echte Datum wird nun verwendet.");
return true;
}
try {
int day = Integer.parseInt(args[2]);
if (day < 1 || day > 24) {
sender.sendMessage("§cBitte gib einen Tag zwischen 1 und 24 an (oder 'reset').");
return true;
}
Adventskalender.getInstance().getConfig().set("general.test_day", day);
Adventskalender.getInstance().saveConfig();
sender.sendMessage("§e[Admin] §7Test-Tag auf §6" + day + " §7gesetzt.");
} catch (NumberFormatException e) {
sender.sendMessage("§cBitte gib eine gültige Zahl (1-24) oder 'reset' an.");
}
return true;
}
// /ak admin resetday <global/Spieler> <Tag>
if (args.length == 4 && args[1].equalsIgnoreCase("resetday")) {
String target = args[2];
try {
int day = Integer.parseInt(args[3]);
if (day < 1 || day > 24) throw new NumberFormatException();
if (target.equalsIgnoreCase("global")) {
DataHandler.GlobalDataManager.resetGlobalDay(day);
sender.sendMessage("§a[Admin] §7Tag §6" + day + " §7global zurückgesetzt.");
} else {
DataHandler.resetPlayerDay(target, day);
sender.sendMessage("§a[Admin] §7Tag §6" + day + " §7für §e" + target + " §7zurückgesetzt.");
}
} catch (NumberFormatException e) {
sender.sendMessage("§cTag muss zwischen 1 und 24 liegen.");
}
return true;
}
// /ak admin reset <global/Spieler>
if (args.length >= 3 && args[1].equalsIgnoreCase("reset")) {
String baseTitle = LanguageManager.getString("gui.title");
if (args[2].equalsIgnoreCase("global")) {
DataHandler.resetAll();
for (Player online : Bukkit.getOnlinePlayers()) {
if (online.getOpenInventory().getTitle().contains(baseTitle)) online.closeInventory();
}
sender.sendMessage("§a[Admin] §7Kompletter Reset durchgeführt.");
} else {
String targetName = args[2];
Player target = Bukkit.getPlayer(targetName);
if (target != null) {
DataHandler.resetPlayer(target);
if (target.getOpenInventory().getTitle().contains(baseTitle)) target.closeInventory();
sender.sendMessage("§a[Admin] §7Daten für §e" + target.getName() + " §7gelöscht.");
} else {
DataHandler.resetOfflinePlayer(targetName);
sender.sendMessage("§a[Admin] §7Offline-Daten für §e" + targetName + " §7gelöscht.");
}
}
return true;
}
sender.sendMessage("§8§m---§r §6Advent Admin §8§m---");
sender.sendMessage("§e/ak admin reload §7- Config neu laden");
sender.sendMessage("§e/ak admin test <1-24/reset> §7- Datum simulieren");
sender.sendMessage("§e/ak admin resetday <global/Spieler> <Tag> §7- Tag löschen");
sender.sendMessage("§e/ak admin reset <global/Spieler> §7- Alles löschen");
return true;
}
if (!(sender instanceof Player player)) return true;
if (!player.hasPermission("adventskalender.use")) {
player.sendMessage(LanguageManager.getMessage("messages.no_permission"));
return true;
}
AdventInventory.open(player);
return true;
}
@Override
public List<String> onTabComplete(CommandSender s, Command c, String a, String[] args) {
if (args.length == 1) return Collections.singletonList("admin");
if (args.length == 2 && args[0].equalsIgnoreCase("admin"))
return Arrays.asList("reload", "test", "reset", "resetday");
// Tab-Completion für das Ziel (global oder Spielername)
if (args.length == 3 && (args[1].equalsIgnoreCase("reset") || args[1].equalsIgnoreCase("resetday"))) {
List<String> options = new ArrayList<>();
options.add("global");
Bukkit.getOnlinePlayers().forEach(p -> options.add(p.getName()));
return options.stream()
.filter(opt -> opt.toLowerCase().startsWith(args[2].toLowerCase()))
.collect(Collectors.toList());
}
// Tab-Completion für die TAGE (Numerisch sortiert)
if ((args.length == 3 && args[1].equalsIgnoreCase("test")) || (args.length == 4 && args[1].equalsIgnoreCase("resetday"))) {
List<String> options = new ArrayList<>();
// "reset" Option nur für den test command hinzufügen
if (args[1].equalsIgnoreCase("test")) {
options.add("reset");
}
for (int i = 1; i <= 24; i++) {
options.add(String.valueOf(i));
}
String currentInput = (args.length == 3) ? args[2] : args[3];
return options.stream()
.filter(opt -> opt.toLowerCase().startsWith(currentInput.toLowerCase()))
.sorted((s1, s2) -> {
// "reset" immer nach oben sortieren
if (s1.equalsIgnoreCase("reset")) return -1;
if (s2.equalsIgnoreCase("reset")) return 1;
// Restliche Zahlen numerisch vergleichen
return Integer.compare(Integer.parseInt(s1), Integer.parseInt(s2));
})
.collect(Collectors.toList());
}
return Collections.emptyList();
}
}

View File

@@ -0,0 +1,154 @@
package de.mviper.adventskalender;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.profile.PlayerProfile;
import org.bukkit.profile.PlayerTextures;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.LocalDate;
import java.time.Month;
import java.util.*;
public class AdventInventory {
// Textur für das geöffnete Geschenk (Wreath)
private static final String OPEN_WREATH_URL = "http://textures.minecraft.net/texture/5e39248b341c87ce3e4294ac214c6f74468889cb1273ae7412906fd28db097e8";
// Texturen für die geschlossenen Tage (1-24)
private static final Map<Integer, String> CLOSED_TEXTURES = new HashMap<>();
private static final Map<String, ItemStack> HEAD_CACHE = new HashMap<>();
static {
// Hier sind die URLs für die "Christmas Calendar #01-24 (red)" Reihe
CLOSED_TEXTURES.put(1, "http://textures.minecraft.net/texture/105b356be68ac56cfe0611b95027adf1ee67050e4cd66a0a99678fc2e25b6b0f");
CLOSED_TEXTURES.put(2, "http://textures.minecraft.net/texture/40ec45e8ffb9cb714d1412bb9ee54fd1e7a3140c02e35ae0d3f308f1666ba126");
CLOSED_TEXTURES.put(3, "http://textures.minecraft.net/texture/2466629a31aae22dba15a7b710a4517308656c19ba39a89ac2de2915a46e2823");
CLOSED_TEXTURES.put(4, "http://textures.minecraft.net/texture/97a1956ed6f32e18b139f2d709355ac6945d0ab8fecd04d4c159d08006bfbe58");
CLOSED_TEXTURES.put(5, "http://textures.minecraft.net/texture/855fad012c8844fc313510436b4919e002d93d6a0761f7bdaf78069683eee5e6");
CLOSED_TEXTURES.put(6, "http://textures.minecraft.net/texture/c0400111ae026101077b59d8482c84a832c74f4f2105fc13b7c94f5b8000ea3");
CLOSED_TEXTURES.put(7, "http://textures.minecraft.net/texture/a34505ed2567ea2efbab49977f7da8f1178db9ae53a0e99737286dc56e63636a");
CLOSED_TEXTURES.put(8, "http://textures.minecraft.net/texture/a17ddf12485fb54cab9c9ffb55feea62a2d90b825772c6ea38561ce750cb6f83");
CLOSED_TEXTURES.put(9, "http://textures.minecraft.net/texture/f75022feb11b736e50bc7d19d26d4ee00cecd6734a2138d2579f799b119b6734");
CLOSED_TEXTURES.put(10, "http://textures.minecraft.net/texture/6b84208e4be2233fcd96e7f02d9613d5437f1d006236277c57d40652c5be2f23");
CLOSED_TEXTURES.put(11, "http://textures.minecraft.net/texture/19aa8a65ba29b4b7cbb9c66cf59fb537ba2c3013a958620b976b9f06248e8dda");
CLOSED_TEXTURES.put(12, "http://textures.minecraft.net/texture/7dc1330b302e800c31c8dfefbd1b996016c34649f3a396749d3e048637364aad");
CLOSED_TEXTURES.put(13, "http://textures.minecraft.net/texture/7e98a3884e0eac967c73a2bcbff7df62ab2fb327b4ceb9e636c74254866b5c7c");
CLOSED_TEXTURES.put(14, "http://textures.minecraft.net/texture/3866643decb2d148999f9768dae89fbdb196b30d55f8846b1fbbe736bb7e5042");
CLOSED_TEXTURES.put(15, "http://textures.minecraft.net/texture/744a95611950cc7f154c9f56ad472c1941376ec171efb8ba476e6cec4f866526");
CLOSED_TEXTURES.put(16, "http://textures.minecraft.net/texture/1546959556eff4b8827ca50d8df686e8f20d5c843da689dddc48bff0a217efbe");
CLOSED_TEXTURES.put(17, "http://textures.minecraft.net/texture/1f4fb00e824c97d9cfba4c44def27a79513978979515048f2e69eb5b7123c159");
CLOSED_TEXTURES.put(18, "http://textures.minecraft.net/texture/9216b42018004a86081b5c1ee87dc8f12770f1859266e2cd359b75b44b5e7680");
CLOSED_TEXTURES.put(19, "http://textures.minecraft.net/texture/93c7097291042c394267892c56feee9ba3936826ea5b2232f46cb5474f9cd937");
CLOSED_TEXTURES.put(20, "http://textures.minecraft.net/texture/4f85a13977d01865a9d95d3279528285872551c36fd5231c7e3ab9897a7560fd");
CLOSED_TEXTURES.put(21, "http://textures.minecraft.net/texture/cdb512403f3610966d10bd3ca9fc61fdc5021268382f69719ac5679f3efd4c14");
CLOSED_TEXTURES.put(22, "http://textures.minecraft.net/texture/cadaef824771250374fc3e82efe020ab765e665340cc2393f3b4ae8d6d18529c");
CLOSED_TEXTURES.put(23, "http://textures.minecraft.net/texture/266f896c37a9d7fb857ff8c9f6f5e3540d17e1b893419f523eb199b71e71dde3");
CLOSED_TEXTURES.put(24, "http://textures.minecraft.net/texture/f081f9274e4ef802453ac95381c00426e462440d3bb085fb3afefa6ded6a8d01");
// Hinweis: In der Praxis füllst du hier alle 1-24 mit den URLs von Minecraft-Heads.
}
public static void initCache() {
// Cache den Wreath-Kopf
HEAD_CACHE.put("OPENED", createBaseSkull(OPEN_WREATH_URL));
// Cache alle nummerierten geschlossenen Köpfe
for (int i = 1; i <= 24; i++) {
if (CLOSED_TEXTURES.containsKey(i)) {
HEAD_CACHE.put("CLOSED_" + i, createBaseSkull(CLOSED_TEXTURES.get(i)));
}
}
}
public static void open(Player player) {
String title = " " + LanguageManager.getString("gui.title");
Inventory inv = Bukkit.createInventory(null, 54, title);
int testDay = Adventskalender.getInstance().getConfig().getInt("general.test_day", 0);
LocalDate date = LocalDate.now();
int currentDay = (testDay > 0) ? testDay : (date.getMonth() == Month.DECEMBER ? date.getDayOfMonth() : 0);
for (int i = 0; i < 54; i++) {
if (i < 9 || i >= 45 || i % 9 == 0 || (i + 1) % 9 == 0) {
Material m = (i % 2 == 0) ? Material.RED_STAINED_GLASS_PANE : Material.GREEN_STAINED_GLASS_PANE;
inv.setItem(i, createFiller(m));
} else {
inv.setItem(i, createFiller(Material.WHITE_STAINED_GLASS_PANE));
}
}
int[] slots = {10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 39, 40, 41};
for (int day = 1; day <= 24; day++) {
boolean claimed = DataHandler.hasClaimed(player, day);
boolean isAvailable = currentDay >= day;
inv.setItem(slots[day - 1], createGiftItem(day, claimed, isAvailable));
}
player.openInventory(inv);
}
private static ItemStack createGiftItem(int day, boolean claimed, boolean isAvailable) {
ItemStack item;
if (claimed) {
item = HEAD_CACHE.getOrDefault("OPENED", new ItemStack(Material.PLAYER_HEAD)).clone();
} else {
item = HEAD_CACHE.getOrDefault("CLOSED_" + day, new ItemStack(Material.PLAYER_HEAD)).clone();
}
ItemMeta meta = item.getItemMeta();
List<String> lore = new ArrayList<>();
lore.add(" ");
if (claimed) {
meta.setDisplayName(LanguageManager.getString("rewards.day_" + day + ".name"));
meta.addEnchant(Enchantment.LUCK, 1, true);
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
lore.add("§8» §6Bereits abgeholt");
lore.add("§aDu hast dieses Geschenk bereits geöffnet! ✔");
} else {
if (!isAvailable) {
meta.setDisplayName("§c§lTag #" + day);
lore.add("§8» §7Noch verschlossen");
lore.add("§7Komme am " + day + ". Dezember wieder!");
} else {
meta.setDisplayName(LanguageManager.getString("rewards.day_" + day + ".name"));
lore.add("§8» §eKlicke zum Öffnen!");
lore.addAll(LanguageManager.getStringList("rewards.day_" + day + ".lore"));
}
}
meta.setLore(lore);
item.setItemMeta(meta);
return item;
}
private static ItemStack createBaseSkull(String url) {
ItemStack item = new ItemStack(Material.PLAYER_HEAD);
SkullMeta meta = (SkullMeta) item.getItemMeta();
try {
UUID uuid = UUID.nameUUIDFromBytes(url.getBytes());
PlayerProfile profile = Bukkit.createPlayerProfile(uuid, "AdventHead");
profile.getTextures().setSkin(new URL(url));
meta.setOwnerProfile(profile);
item.setItemMeta(meta);
} catch (MalformedURLException e) { e.printStackTrace(); }
return item;
}
private static ItemStack createFiller(Material material) {
ItemStack item = new ItemStack(material);
ItemMeta meta = item.getItemMeta();
if (meta != null) { meta.setDisplayName(" "); item.setItemMeta(meta); }
return item;
}
}

View File

@@ -0,0 +1,135 @@
package de.mviper.adventskalender;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.hover.content.Text;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.time.LocalDate;
import java.time.Month;
import java.util.List;
import java.util.Map;
public class AdventListener implements Listener {
@EventHandler
public void onJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
// Nachricht an Admins senden, wenn ein Update da ist
if (player.hasPermission("adventskalender.admin")) {
// Delay von 2 Sekunden (40 Ticks), damit die Nachricht nicht im Join-Spam untergeht
Bukkit.getScheduler().runTaskLater(Adventskalender.getInstance(), () -> {
if (Adventskalender.getInstance().isUpdateAvailable()) {
String latest = Adventskalender.getInstance().getLatestVersion();
String current = Adventskalender.getInstance().getDescription().getVersion();
player.sendMessage("§7 ");
player.sendMessage("§8§m+-------------------------------------------+");
player.sendMessage("§6§l ADVENTSKALENDER UPDATE");
player.sendMessage("§7 ");
player.sendMessage("§7 Eine neue Version ist verfügbar: §a§l" + latest);
player.sendMessage("§7 Installierte Version: §c" + current);
player.sendMessage("§7 ");
// Erstellung der klickbaren Nachricht
TextComponent message = new TextComponent("§e §nKLICKE HIER ZUM DOWNLOAD");
message.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://www.spigotmc.org/resources/130974/"));
message.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("§7Öffnet die Spigot-Seite")));
player.spigot().sendMessage(message);
player.sendMessage("§7 ");
player.sendMessage("§8§m+-------------------------------------------+");
player.sendMessage("§7 ");
}
}, 40L);
}
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
String baseTitle = LanguageManager.getString("gui.title");
if (!event.getView().getTitle().contains(baseTitle)) return;
event.setCancelled(true);
if (!(event.getWhoClicked() instanceof Player player)) return;
ItemStack clicked = event.getCurrentItem();
if (clicked == null || clicked.getType() != Material.PLAYER_HEAD) return;
if (!clicked.hasItemMeta() || !clicked.getItemMeta().hasDisplayName()) return;
String displayName = ChatColor.stripColor(clicked.getItemMeta().getDisplayName());
int day;
try {
day = Integer.parseInt(displayName.replaceAll("[^0-9]", ""));
} catch (NumberFormatException e) {
return;
}
int testDay = Adventskalender.getInstance().getConfig().getInt("general.test_day", 0);
LocalDate date = LocalDate.now();
int currentDay = (testDay > 0) ? testDay : (date.getMonth() == Month.DECEMBER ? date.getDayOfMonth() : 0);
if (currentDay >= day) {
if (DataHandler.hasClaimed(player, day)) {
player.sendMessage(LanguageManager.getMessage("messages.day_already_claimed"));
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f);
return;
}
giveReward(player, day);
DataHandler.setClaimed(player, day);
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1f, 1.5f);
AdventInventory.open(player);
} else {
player.sendMessage(LanguageManager.getMessage("messages.day_not_available"));
player.playSound(player.getLocation(), Sound.BLOCK_CHEST_LOCKED, 1f, 1f);
}
}
private void giveReward(Player player, int day) {
String path = "rewards." + day;
String matName = Adventskalender.getInstance().getConfig().getString(path + ".material", "COOKIE");
int amount = Adventskalender.getInstance().getConfig().getInt(path + ".amount", 1);
ItemStack reward = new ItemStack(Material.valueOf(matName.toUpperCase()), amount);
ItemMeta meta = reward.getItemMeta();
if (meta != null) {
List<Map<?, ?>> enchants = Adventskalender.getInstance().getConfig().getMapList(path + ".enchantments");
for (Map<?, ?> entry : enchants) {
String type = (String) entry.get("type");
Object levelObj = entry.get("level");
int level = (levelObj instanceof Integer) ? (int) levelObj : 1;
Enchantment enc = Enchantment.getByName(type.toUpperCase());
if (enc != null) {
meta.addEnchant(enc, level, true);
}
}
reward.setItemMeta(meta);
}
if (player.getInventory().firstEmpty() == -1) {
player.getWorld().dropItemNaturally(player.getLocation(), reward);
player.sendMessage(LanguageManager.getMessage("messages.inventory_full"));
} else {
player.getInventory().addItem(reward);
}
player.sendMessage(LanguageManager.getMessage("messages.reward_received").replace("%day%", String.valueOf(day)));
}
}

View File

@@ -0,0 +1,62 @@
package de.mviper.adventskalender;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.plugin.java.JavaPlugin;
public final class Adventskalender extends JavaPlugin {
private static Adventskalender instance;
private NamespacedKey dataKey;
// Update-Status Variablen
private boolean updateAvailable = false;
private String latestVersion = "";
@Override
public void onEnable() {
instance = this;
this.dataKey = new NamespacedKey(this, "claimed_days_v2");
saveDefaultConfig();
LanguageManager.setup();
// Initialisierung der Daten (MySQL wird hier bevorzugt behandelt)
DataHandler.setup();
// Textur-Puffer füllen, um Steve-Köpfe zu vermeiden
AdventInventory.initCache();
getCommand("adventskalender").setExecutor(new AdventCommand());
getServer().getPluginManager().registerEvents(new AdventListener(), this);
// Update Checker Integration (ID: 130974)
new UpdateChecker(this, 130974).getVersion(version -> {
if (!this.getDescription().getVersion().equals(version)) {
this.updateAvailable = true;
this.latestVersion = version;
getLogger().warning("Eine neue Version (" + version + ") ist verfügbar!");
getLogger().warning("Download: https://www.spigotmc.org/resources/130974/");
} else {
getLogger().info("Das Plugin ist auf dem neuesten Stand.");
}
});
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
new AdventCalendarExpansion().register();
}
getLogger().info("Adventskalender erfolgreich gestartet!");
}
@Override
public void onDisable() {
MySQLManager.close();
}
public static Adventskalender getInstance() { return instance; }
public NamespacedKey getDataKey() { return dataKey; }
// Getter für den Update-Status
public boolean isUpdateAvailable() { return updateAvailable; }
public String getLatestVersion() { return latestVersion; }
}

View File

@@ -0,0 +1,241 @@
package de.mviper.adventskalender;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import java.io.File;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
public class DataHandler {
private static File file;
private static FileConfiguration dataConfig;
private static boolean mysqlActive = false;
public static void setup() {
if (Adventskalender.getInstance().getConfig().getBoolean("mysql.enable")) {
MySQLManager.connect();
if (MySQLManager.isConnected()) {
mysqlActive = true;
Adventskalender.getInstance().getLogger().info("MySQL-Verbindung steht. data.yml wird deaktiviert.");
return;
} else {
Adventskalender.getInstance().getLogger().warning("MySQL aktiviert, aber Verbindung fehlgeschlagen! Nutze data.yml als Backup.");
}
}
if (!Adventskalender.getInstance().getDataFolder().exists()) {
Adventskalender.getInstance().getDataFolder().mkdirs();
}
file = new File(Adventskalender.getInstance().getDataFolder(), "data.yml");
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
dataConfig = YamlConfiguration.loadConfiguration(file);
}
public static boolean hasClaimed(Player player, int day) {
if (isGlobal()) {
return GlobalDataManager.isDayClaimedGlobally(day);
}
if (mysqlActive && MySQLManager.isConnected()) {
try (PreparedStatement ps = MySQLManager.getConnection().prepareStatement("SELECT 1 FROM advent_players WHERE uuid = ? AND day = ?")) {
ps.setString(1, player.getUniqueId().toString());
ps.setInt(2, day);
return ps.executeQuery().next();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (dataConfig != null) {
List<Integer> claimed = dataConfig.getIntegerList("players." + player.getUniqueId() + ".claimed");
return claimed.contains(day);
}
return false;
}
public static void setClaimed(Player player, int day) {
if (isGlobal()) {
GlobalDataManager.setDayClaimedGlobally(day, player.getName());
return;
}
if (mysqlActive && MySQLManager.isConnected()) {
try (PreparedStatement ps = MySQLManager.getConnection().prepareStatement("INSERT IGNORE INTO advent_players (uuid, day) VALUES (?, ?)")) {
ps.setString(1, player.getUniqueId().toString());
ps.setInt(2, day);
ps.executeUpdate();
return;
} catch (SQLException e) {
e.printStackTrace();
}
}
if (dataConfig != null) {
List<Integer> claimed = dataConfig.getIntegerList("players." + player.getUniqueId() + ".claimed");
if (!claimed.contains(day)) {
claimed.add(day);
dataConfig.set("players." + player.getUniqueId() + ".claimed", claimed);
dataConfig.set("players." + player.getUniqueId() + ".name", player.getName());
save();
}
}
}
public static void resetPlayerDay(String playerName, int day) {
if (mysqlActive && MySQLManager.isConnected()) {
@SuppressWarnings("deprecation")
OfflinePlayer target = Bukkit.getOfflinePlayer(playerName);
try (PreparedStatement ps = MySQLManager.getConnection().prepareStatement("DELETE FROM advent_players WHERE uuid = ? AND day = ?")) {
ps.setString(1, target.getUniqueId().toString());
ps.setInt(2, day);
ps.executeUpdate();
} catch (SQLException e) { e.printStackTrace(); }
}
if (dataConfig != null && dataConfig.getConfigurationSection("players") != null) {
for (String uuid : dataConfig.getConfigurationSection("players").getKeys(false)) {
if (playerName.equalsIgnoreCase(dataConfig.getString("players." + uuid + ".name"))) {
List<Integer> claimed = dataConfig.getIntegerList("players." + uuid + ".claimed");
claimed.remove(Integer.valueOf(day));
dataConfig.set("players." + uuid + ".claimed", claimed);
save();
break;
}
}
}
}
public static Set<Integer> getClaimedDays(Player player) {
if (mysqlActive && MySQLManager.isConnected()) {
Set<Integer> days = new HashSet<>();
try (PreparedStatement ps = MySQLManager.getConnection().prepareStatement("SELECT day FROM advent_players WHERE uuid = ?")) {
ps.setString(1, player.getUniqueId().toString());
ResultSet rs = ps.executeQuery();
while (rs.next()) days.add(rs.getInt("day"));
return days;
} catch (SQLException e) {
e.printStackTrace();
}
}
if (dataConfig != null) {
return new HashSet<>(dataConfig.getIntegerList("players." + player.getUniqueId() + ".claimed"));
}
return new HashSet<>();
}
public static void resetPlayer(Player player) {
if (mysqlActive && MySQLManager.isConnected()) {
try (PreparedStatement ps = MySQLManager.getConnection().prepareStatement("DELETE FROM advent_players WHERE uuid = ?")) {
ps.setString(1, player.getUniqueId().toString());
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (dataConfig != null) {
dataConfig.set("players." + player.getUniqueId(), null);
save();
}
}
public static void resetOfflinePlayer(String name) {
if (dataConfig == null || dataConfig.getConfigurationSection("players") == null) return;
for (String uuid : dataConfig.getConfigurationSection("players").getKeys(false)) {
String savedName = dataConfig.getString("players." + uuid + ".name");
if (name.equalsIgnoreCase(savedName)) {
dataConfig.set("players." + uuid, null);
save();
break;
}
}
}
public static void resetAll() {
if (mysqlActive && MySQLManager.isConnected()) {
try (PreparedStatement ps1 = MySQLManager.getConnection().prepareStatement("DELETE FROM advent_players");
PreparedStatement ps2 = MySQLManager.getConnection().prepareStatement("DELETE FROM advent_global")) {
ps1.executeUpdate();
ps2.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (dataConfig != null) {
dataConfig.set("players", null);
dataConfig.set("global", null);
save();
}
}
private static boolean isGlobal() {
return Adventskalender.getInstance().getConfig().getBoolean("calendar.use_global_calendar", false);
}
private static void save() {
if (dataConfig == null || file == null) return;
try {
dataConfig.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
public static class GlobalDataManager {
public static boolean isDayClaimedGlobally(int day) {
if (mysqlActive && MySQLManager.isConnected()) {
try (PreparedStatement ps = MySQLManager.getConnection().prepareStatement("SELECT 1 FROM advent_global WHERE day = ?")) {
ps.setInt(1, day);
return ps.executeQuery().next();
} catch (SQLException e) {
e.printStackTrace();
}
}
return dataConfig != null && dataConfig.contains("global.day_" + day);
}
public static void setDayClaimedGlobally(int day, String playerName) {
if (mysqlActive && MySQLManager.isConnected()) {
try (PreparedStatement ps = MySQLManager.getConnection().prepareStatement("REPLACE INTO advent_global (day, player_name) VALUES (?, ?)")) {
ps.setInt(1, day);
ps.setString(2, playerName);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
} else if (dataConfig != null) {
dataConfig.set("global.day_" + day, playerName);
save();
}
}
public static void resetGlobalDay(int day) {
if (mysqlActive && MySQLManager.isConnected()) {
try (PreparedStatement ps = MySQLManager.getConnection().prepareStatement("DELETE FROM advent_global WHERE day = ?")) {
ps.setInt(1, day);
ps.executeUpdate();
} catch (SQLException e) { e.printStackTrace(); }
} else if (dataConfig != null) {
dataConfig.set("global.day_" + day, null);
DataHandler.save();
}
}
}
}

View File

@@ -0,0 +1,35 @@
package de.mviper.adventskalender;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.util.List;
import java.util.stream.Collectors;
public class LanguageManager {
private static YamlConfiguration cfg;
private static String prefix;
public static void setup() {
String lang = Adventskalender.getInstance().getConfig().getString("general.language", "de");
File f = new File(Adventskalender.getInstance().getDataFolder(), "messages_" + lang + ".yml");
if (!f.exists()) Adventskalender.getInstance().saveResource("messages_" + lang + ".yml", false);
cfg = YamlConfiguration.loadConfiguration(f);
prefix = ChatColor.translateAlternateColorCodes('&', cfg.getString("prefix", "&6[Advent] "));
}
public static String getString(String path) {
String s = cfg.getString(path);
return s == null ? "§cKey error: " + path : ChatColor.translateAlternateColorCodes('&', s);
}
public static String getMessage(String path) {
return prefix + getString(path);
}
public static List<String> getStringList(String path) {
return cfg.getStringList(path).stream()
.map(s -> ChatColor.translateAlternateColorCodes('&', s))
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,66 @@
package de.mviper.adventskalender;
import org.bukkit.configuration.file.FileConfiguration;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MySQLManager {
private static Connection connection;
public static void connect() {
FileConfiguration config = Adventskalender.getInstance().getConfig();
String host = config.getString("mysql.host");
int port = config.getInt("mysql.port");
String database = config.getString("mysql.database");
String user = config.getString("mysql.user");
String password = config.getString("mysql.password");
try {
if (connection != null && !connection.isClosed()) return;
synchronized (MySQLManager.class) {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://" + host + ":" + port + "/" + database + "?autoReconnect=true&useSSL=false", user, password);
}
createTables();
Adventskalender.getInstance().getLogger().info("MySQL-Verbindung erfolgreich hergestellt!");
} catch (Exception e) {
Adventskalender.getInstance().getLogger().severe("MySQL-Verbindung fehlgeschlagen: " + e.getMessage());
}
}
private static void createTables() {
try (Statement s = connection.createStatement()) {
// Tabelle für Einzelspieler-Daten
s.executeUpdate("CREATE TABLE IF NOT EXISTS advent_players (uuid VARCHAR(36), day INT, PRIMARY KEY(uuid, day))");
// Tabelle für globalen Modus
s.executeUpdate("CREATE TABLE IF NOT EXISTS advent_global (day INT PRIMARY KEY, player_name VARCHAR(16))");
} catch (SQLException e) {
e.printStackTrace();
}
}
public static boolean isConnected() {
try {
return connection != null && !connection.isClosed();
} catch (SQLException e) {
return false;
}
}
public static void close() {
try {
if (isConnected()) connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
return connection;
}
}

View File

@@ -0,0 +1,33 @@
package de.mviper.adventskalender;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Scanner;
import java.util.function.Consumer;
public class UpdateChecker {
private final JavaPlugin plugin;
private final int resourceId;
public UpdateChecker(JavaPlugin plugin, int resourceId) {
this.plugin = plugin;
this.resourceId = resourceId;
}
public void getVersion(final Consumer<String> consumer) {
Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> {
try (InputStream is = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + this.resourceId).openStream();
Scanner scann = new Scanner(is)) {
if (scann.hasNext()) {
consumer.accept(scann.next());
}
} catch (IOException e) {
plugin.getLogger().info("Update-Check fehlgeschlagen: " + e.getMessage());
}
});
}
}

View File

@@ -8,6 +8,9 @@ general:
# Verfügbare Optionen: 'de', 'en' # Verfügbare Optionen: 'de', 'en'
language: "de" language: "de"
# Nur für Testzwecke: Simuliert einen Tag (0 = echtes Datum verwenden)
test_day: 0
# --- Kalender-Einstellungen --- # --- Kalender-Einstellungen ---
calendar: calendar:
# Soll jeder Spieler seinen eigenen, individuellen Kalender haben? # Soll jeder Spieler seinen eigenen, individuellen Kalender haben?
@@ -19,6 +22,15 @@ calendar:
# Dieser Text ist ein Schlüssel, der in der messages.yml übersetzt wird. # Dieser Text ist ein Schlüssel, der in der messages.yml übersetzt wird.
gui_title_key: "adventskalender.gui_title" gui_title_key: "adventskalender.gui_title"
# Datenbank für Bungeecord Nutzung
mysql:
enable: false
host: "localhost"
port: 3306
database: "adventskalender"
user: "root"
password: ""
# --- Belohnungen für die Tage 1 bis 24 --- # --- Belohnungen für die Tage 1 bis 24 ---
# Hier definierst du die Items für jeden Tag. # Hier definierst du die Items für jeden Tag.
# 'material': Der Materialname des Items (z.B. DIAMOND, ELYTRA). # 'material': Der Materialname des Items (z.B. DIAMOND, ELYTRA).

View File

@@ -1,15 +1,14 @@
# ============================================================================= # =============================================================================
# Adventskalender Plugin - Deutsche Sprachdatei # Adventskalender Plugin - Deutsche Sprachdatei (v2.0 - 2026)
# ============================================================================= # =============================================================================
# --- Prefix --- # --- Prefix ---
# Dieser Prefix wird vor fast jeder Nachricht im Chat angezeigt.
prefix: "&6[Adventskalender] &r" prefix: "&6[Adventskalender] &r"
# --- GUI-Texte --- # --- GUI-Texte ---
gui: gui:
# Der Titel des Adventskalender-Inventars. # Der Titel des Adventskalender-Inventars.
title: "&6✦ Adventskalender 2024 ✦" title: "&6✦ Adventskalender 2026 ✦"
# --- Nachrichten an Spieler --- # --- Nachrichten an Spieler ---
# Verfügbare Platzhalter: # Verfügbare Platzhalter:
@@ -18,90 +17,92 @@ gui:
messages: messages:
no_permission: "&cDafür hast du keine Berechtigung." no_permission: "&cDafür hast du keine Berechtigung."
only_player: "&cDieser Befehl kann nur von einem Spieler ausgeführt werden." only_player: "&cDieser Befehl kann nur von einem Spieler ausgeführt werden."
inventory_full: "&cDein Inventar war voll! Das Item wurde auf den Boden geworfen." inventory_full: "&cDein Inventar ist voll! Dein Geschenk wurde vor deine Füße geworfen."
reward_received: "&aDu hast dein Geschenk für Tag %day% erhalten!" reward_received: "&aGlückwunsch! Du hast dein Geschenk für Tag &e%day% &aerhalten!"
day_not_available: "&cDieses Geschenk kannst du (noch) nicht öffnen." day_not_available: "&cDieses Türchen ist noch fest verschlossen. Gedulde dich noch etwas!"
day_already_claimed: "&7Du hast dein Geschenk für diesen Tag bereits geholt." day_already_claimed: "&7Du hast dieses Geschenk bereits abgeholt."
global_already_claimed: "&cDieses Geschenk wurde heute bereits von jemand anderem abgeholt!"
# --- Admin-Nachrichten --- # --- Admin-Nachrichten ---
admin: admin:
reload_success: "&aKonfiguration und Sprachdateien wurden neu geladen." reload_success: "&aKonfiguration und Sprachdateien wurden erfolgreich neu geladen."
test_mode_on: "&e[Admin] &7Der Test-Modus wurde auf Tag &6%day% &7gesetzt."
test_mode_off: "&e[Admin] &7Test-Modus deaktiviert. Es wird wieder das reale Datum genutzt."
player_not_found: "&cDer Spieler '%player%' wurde nicht gefunden." player_not_found: "&cDer Spieler '%player%' wurde nicht gefunden."
invalid_day: "&cUngültiger Tag. Bitte wähle eine Zahl zwischen 1 und 24." invalid_day: "&cUngültiger Tag. Bitte wähle eine Zahl zwischen 1 und 24."
open_success: "&aDu hast für %player% das Türchen für Tag %day% geöffnet."
# --- Namen und Beschreibungen für die Belohnungs-Items --- # --- Belohnungs-Texte im GUI ---
# Die Schlüssel hier (z.B. 'day_1') müssen mit den 'keys' in der config.yml übereinstimmen. # Diese Schlüssel werden vom AdventInventory genutzt, um die Items im Menü zu benennen.
rewards: rewards:
day_1: day_1:
name: "&bErste Diamanten!" name: "&bTag 1: Erste Diamanten!"
lore: ["&7Ein kleiner Vorgeschmack auf den Reichtum...", "&7Viel Spaß damit!"] lore: ["&7Ein kleiner Vorgeschmack auf den Reichtum...", "&7Viel Spaß damit!"]
day_2: day_2:
name: "&6Goldene Äpfel" name: "&6Tag 2: Goldene Äpfel"
lore: ["&7Für den Fall, dass es mal eng wird..."] lore: ["&7Für den Fall, dass es mal eng wird..."]
day_3: day_3:
name: "&cSchwert des Helden" name: "&cTag 3: Schwert des Helden"
lore: ["&7Ein mächtiges Schwert, um Monster zu jagen."] lore: ["&7Ein mächtiges Schwert, um Monster zu jagen."]
day_4: day_4:
name: "&aFlügel der Freiheit" name: "&aTag 4: Flügel der Freiheit"
lore: ["&7Sei frei wie ein Adler!"] lore: ["&7Sei frei wie ein Adler!"]
day_5: day_5:
name: "&8Ein Hauch von Netherit" name: "&8Tag 5: Ein Hauch von Netherit"
lore: ["&7Sehr wertvoll und selten."] lore: ["&7Sehr wertvoll und selten."]
day_6: day_6:
name: "&6Göttlicher Apfel" name: "&6Tag 6: Göttlicher Apfel"
lore: ["&7Ein Geschenk der Götter... oder des Admins."] lore: ["&7Ein Geschenk der Götter... oder des Admins."]
day_7: day_7:
name: "&eBergbau-Meister" name: "&eTag 7: Bergbau-Meister"
lore: ["&7Für die größten Schätze der Welt."] lore: ["&7Für die größten Schätze der Welt."]
day_8: day_8:
name: "&dTotem des Unvergänglichen" name: "&dTag 8: Totem des Unvergänglichen"
lore: ["&7Ein kleines Extra-Leben."] lore: ["&7Ein kleines Extra-Leben."]
day_9: day_9:
name: "&5Stern des Nethers" name: "&5Tag 9: Stern des Nethers"
lore: ["&7Der Kern eines mächtigen Wesens."] lore: ["&7Der Kern eines mächtigen Wesens."]
day_10: day_10:
name: "&9Magische Truhe" name: "&9Tag 10: Magische Truhen"
lore: ["&7Hält all deine Schätze sicher."] lore: ["&7Hält all deine Schätze sicher."]
day_11: day_11:
name: "&3Stachel des Ozeans" name: "&3Tag 11: Stachel des Ozeans"
lore: ["&7Die Waffe der Wächter."] lore: ["&7Die Waffe der Wächter."]
day_12: day_12:
name: "&7Helm der Weisheit" name: "&7Tag 12: Helm der Weisheit"
lore: ["&7Schützt deinen Kopf."] lore: ["&7Schützt deinen Kopf."]
day_13: day_13:
name: "&fSattel für ein treues Tier" name: "&fTag 13: Sattel"
lore: ["&7Für dein nächstes Abenteuer zu Pferd."] lore: ["&7Für dein nächstes Abenteuer zu Pferd."]
day_14: day_14:
name: "&eNamensschilder" name: "&eTag 14: Namensschilder"
lore: ["&7Gib deinem Lieblings-Wolf einen Namen!"] lore: ["&7Gib deinem Lieblings-Wolf einen Namen!"]
day_15: day_15:
name: "&aSchallplatte - cat" name: "&aTag 15: Schallplatte - cat"
lore: ["&7Relaxende Musik für eine gemütliche Zeit."] lore: ["&7Relaxende Musik für eine gemütliche Zeit."]
day_16: day_16:
name: "&5Endkristall" name: "&5Tag 16: Endkristalle"
lore: ["&7Mächtig und gefährlich. Mit Vorsicht genießen!"] lore: ["&7Mächtig und gefährlich. Mit Vorsicht genießen!"]
day_17: day_17:
name: "&7Brustpanzer der Unzerstörbarkeit" name: "&7Tag 17: Brustpanzer der Unzerstörbarkeit"
lore: ["&7Bietet maximalen Schutz."] lore: ["&7Bietet maximalen Schutz."]
day_18: day_18:
name: "&bHerz des Ozeans" name: "&bTag 18: Herz des Ozeans"
lore: ["&7Das Zentrum einer Conduit-Struktur."] lore: ["&7Das Zentrum einer Conduit-Struktur."]
day_19: day_19:
name: "&fNautilusmuschel" name: "&fTag 19: Nautilusmuscheln"
lore: ["&7Ein seltenes Gut aus den Tiefen."] lore: ["&7Ein seltenes Gut aus den Tiefen."]
day_20: day_20:
name: "&8Kopf des Enderdrachen" name: "&8Tag 20: Kopf des Enderdrachen"
lore: ["&7Eine beeindruckende Trophäe."] lore: ["&7Eine beeindruckende Trophäe."]
day_21: day_21:
name: "&8Stiefel der Tiefe" name: "&8Tag 21: Stiefel der Tiefe"
lore: ["&7Lass dich nicht im Feuer verbrennen."] lore: ["&7Lass dich nicht im Feuer verbrennen."]
day_22: day_22:
name: "&dVerzauberungstisch" name: "&dTag 22: Verzauberungstisch"
lore: ["&7Kreiere deine eigenen magischen Items."] lore: ["&7Kreiere deine eigenen magischen Items."]
day_23: day_23:
name: "&bDie ultimative Hacke" name: "&bTag 23: Die ultimative Hacke"
lore: ["&7Nicht nur für den Ackerbau..."] lore: ["&7Nicht nur für den Ackerbau..."]
day_24: day_24:
name: "&cDas große Finale! - Feuerwerk" name: "&cTag 24: Das große Finale!"
lore: ["&7Frohe Weihnachten!", "&7Feiere mit einem riesigen Feuerwerk!"] lore: ["&7Frohe Weihnachten!", "&7Feiere mit einem riesigen Feuerwerk!"]

View File

@@ -1,15 +1,14 @@
# ============================================================================= # =============================================================================
# Adventskalender Plugin - English Language File # Adventskalender Plugin - English Language File (v2.0 - 2026)
# ============================================================================= # =============================================================================
# --- Prefix --- # --- Prefix ---
# This prefix will be shown before most chat messages. prefix: "&6[Advent] &r"
prefix: "&6[Adventskalender] &r"
# --- GUI Texts --- # --- GUI Texts ---
gui: gui:
# The title of the Advent Calendar inventory. # The title of the Advent Calendar inventory.
title: "&6✦ Advent Calendar 2024 ✦" title: "&6✦ Advent Calendar 2026 ✦"
# --- Messages to Players --- # --- Messages to Players ---
# Available placeholders: # Available placeholders:
@@ -18,90 +17,91 @@ gui:
messages: messages:
no_permission: "&cYou don't have permission for that." no_permission: "&cYou don't have permission for that."
only_player: "&cThis command can only be executed by a player." only_player: "&cThis command can only be executed by a player."
inventory_full: "&cYour inventory was full! The item was dropped on the ground." inventory_full: "&cYour inventory is full! Your gift was dropped at your feet."
reward_received: "&aYou have received your gift for day %day%!" reward_received: "&aCongratulations! You have received your gift for day &e%day%&a!"
day_not_available: "&cYou cannot open this gift (yet)." day_not_available: "&cThis door is still locked. You'll have to wait a bit longer!"
day_already_claimed: "&7You have already claimed your gift for this day." day_already_claimed: "&7You have already claimed this gift."
global_already_claimed: "&cThis gift has already been claimed by someone else today!"
# --- Admin Messages --- # --- Admin Messages ---
admin: admin:
reload_success: "&aConfiguration and language files have been reloaded." reload_success: "&aConfiguration and language files have been reloaded."
test_mode_on: "&e[Admin] &7Test mode set to day &6%day%&7."
test_mode_off: "&e[Admin] &7Test mode disabled. Using real-time date again."
player_not_found: "&cThe player '%player%' was not found." player_not_found: "&cThe player '%player%' was not found."
invalid_day: "&cInvalid day. Please choose a number between 1 and 24." invalid_day: "&cInvalid day. Please choose a number between 1 and 24."
open_success: "&aYou have opened day %day% for %player%."
# --- Names and Descriptions for Reward Items --- # --- Reward Texts in GUI ---
# The keys here (e.g., 'day_1') must match the 'keys' in the config.yml.
rewards: rewards:
day_1: day_1:
name: "&bFirst Diamonds!" name: "&bDay 1: First Diamonds!"
lore: ["&7A little taste of wealth...", "&7Have fun with it!"] lore: ["&7A little taste of wealth...", "&7Have fun with it!"]
day_2: day_2:
name: "&6Golden Apples" name: "&6Day 2: Golden Apples"
lore: ["&7In case things get tight..."] lore: ["&7In case things get tight..."]
day_3: day_3:
name: "&cSword of the Hero" name: "&cDay 3: Sword of the Hero"
lore: ["&7A mighty sword to hunt monsters."] lore: ["&7A mighty sword to hunt monsters."]
day_4: day_4:
name: "&aWings of Freedom" name: "&aDay 4: Wings of Freedom"
lore: ["&7Be free as an eagle!"] lore: ["&7Be free as an eagle!"]
day_5: day_5:
name: "&8A Touch of Netherite" name: "&8Day 5: A Touch of Netherite"
lore: ["&7Very valuable and rare."] lore: ["&7Very valuable and rare."]
day_6: day_6:
name: "&6Godly Apple" name: "&6Day 6: Godly Apple"
lore: ["&7A gift from the gods... or the admin."] lore: ["&7A gift from the gods... or the admin."]
day_7: day_7:
name: "&eMaster Pickaxe" name: "&eDay 7: Master Pickaxe"
lore: ["&7For the greatest treasures in the world."] lore: ["&7For the greatest treasures in the world."]
day_8: day_8:
name: "&dTotem of Undying" name: "&dDay 8: Totem of Undying"
lore: ["&7An extra life."] lore: ["&7An extra life."]
day_9: day_9:
name: "&5Nether Star" name: "&5Day 9: Nether Star"
lore: ["&7The core of a powerful being."] lore: ["&7The core of a powerful being."]
day_10: day_10:
name: "&9Magic Box" name: "&9Day 10: Magic Chests"
lore: ["&7Keeps all your treasures safe."] lore: ["&7Keeps all your treasures safe."]
day_11: day_11:
name: "&3Spear of the Ocean" name: "&3Day 11: Spear of the Ocean"
lore: ["&7The weapon of the guardians."] lore: ["&7The weapon of the guardians."]
day_12: day_12:
name: "&7Helmet of Wisdom" name: "&7Day 12: Helmet of Wisdom"
lore: ["&7Protects your head."] lore: ["&7Protects your head."]
day_13: day_13:
name: "&fSaddle for a Loyal Steed" name: "&fDay 13: Saddle"
lore: ["&7For your next equestrian adventure."] lore: ["&7For your next equestrian adventure."]
day_14: day_14:
name: "&eName Tags" name: "&eDay 14: Name Tags"
lore: ["&7Give your favorite wolf a name!"] lore: ["&7Give your favorite wolf a name!"]
day_15: day_15:
name: "&aMusic Disc - cat" name: "&aDay 15: Music Disc - cat"
lore: ["&7Relaxing music for a cozy time."] lore: ["&7Relaxing music for a cozy time."]
day_16: day_16:
name: "&5End Crystal" name: "&5Day 16: End Crystals"
lore: ["&7Powerful and dangerous. Handle with care!"] lore: ["&7Powerful and dangerous. Handle with care!"]
day_17: day_17:
name: "&7Chestplate of Durability" name: "&7Day 17: Chestplate of Durability"
lore: ["&7Offers maximum protection."] lore: ["&7Offers maximum protection."]
day_18: day_18:
name: "&bHeart of the Sea" name: "&bDay 18: Heart of the Sea"
lore: ["&7The center of a Conduit structure."] lore: ["&7The center of a Conduit structure."]
day_19: day_19:
name: "&fNautilus Shell" name: "&fDay 19: Nautilus Shells"
lore: ["&7A rare goodie from the depths."] lore: ["&7A rare goodie from the depths."]
day_20: day_20:
name: "&8Head of the Ender Dragon" name: "&8Day 20: Head of the Ender Dragon"
lore: ["&7An impressive trophy."] lore: ["&7An impressive trophy."]
day_21: day_21:
name: "&8Boots of the Deep" name: "&8Day 21: Boots of the Deep"
lore: ["&7Don't let yourself get burned in fire."] lore: ["&7Don't let yourself get burned in fire."]
day_22: day_22:
name: "&dEnchanting Table" name: "&dDay 22: Enchanting Table"
lore: ["&7Create your own magical items."] lore: ["&7Create your own magical items."]
day_23: day_23:
name: "&bThe Ultimate Hoe" name: "&bDay 23: The Ultimate Hoe"
lore: ["&7Not just for farming..."] lore: ["&7Not just for farming..."]
day_24: day_24:
name: "&cThe Grand Finale! - Fireworks" name: "&cDay 24: The Grand Finale!"
lore: ["&7Merry Christmas!", "&7Celebrate with a huge firework!"] lore: ["&7Merry Christmas!", "&7Celebrate with a huge firework!"]

View File

@@ -1,9 +1,9 @@
name: Adventskalender name: Adventskalender
version: '1.0.0' version: '1.0.1'
main: de.mviper.adventskalender.Adventskalender main: de.mviper.adventskalender.Adventskalender
api-version: 1.20 api-version: 1.20
author: M_Viper author: M_Viper
description: Ein konfigurierbarer Adventskalender für Minecraft. description: Ein moderner, performanter Adventskalender (2026 Edition).
commands: commands:
adventskalender: adventskalender: