Upload folder via GUI - src

This commit is contained in:
Git Manager GUI
2026-04-06 22:42:47 +02:00
parent 51b94955f4
commit 4e18de17fc
41 changed files with 5671 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
package dev.viper.eventengine;
import dev.viper.eventengine.command.EventCommand;
import dev.viper.eventengine.command.RegionSetupManager;
import dev.viper.eventengine.config.ConfigManager;
import dev.viper.eventengine.gui.EventGUI;
import dev.viper.eventengine.listener.EventCreateListener;
import dev.viper.eventengine.listener.EventProtectionListener;
import dev.viper.eventengine.manager.EventManager;
import dev.viper.eventengine.manager.EventRegistry;
import dev.viper.eventengine.scheduler.EventScheduler;
import org.bukkit.plugin.java.JavaPlugin;
public class EventEngine extends JavaPlugin {
private static EventEngine instance;
private ConfigManager configManager;
private EventRegistry eventRegistry;
private EventManager eventManager;
private EventScheduler eventScheduler;
private EventGUI eventGUI;
private EventCreateListener eventCreateListener;
private RegionSetupManager regionSetupManager;
@Override
public void onEnable() {
instance = this;
// Config
configManager = new ConfigManager(this);
configManager.load();
// Registry (builtin + custom)
eventRegistry = new EventRegistry(this);
eventRegistry.init();
// Event-Manager (Lifecycle)
eventManager = new EventManager(this);
// Scheduler
eventScheduler = new EventScheduler(this);
eventScheduler.start();
// GUI
eventGUI = new EventGUI(this);
getServer().getPluginManager().registerEvents(eventGUI, this);
// Create-Listener (Custom Event Builder)
eventCreateListener = new EventCreateListener(this);
getServer().getPluginManager().registerEvents(eventCreateListener, this);
// Region-Schutz Listener
getServer().getPluginManager().registerEvents(new EventProtectionListener(this), this);
// Region-Setup Manager
regionSetupManager = new RegionSetupManager(this);
// Command
EventCommand cmd = new EventCommand(this);
getCommand("event").setExecutor(cmd);
getCommand("event").setTabCompleter(cmd);
getLogger().info("EventEngine gestartet — " + eventRegistry.count() + " Events geladen.");
}
@Override
public void onDisable() {
if (eventScheduler != null) eventScheduler.stop();
if (eventManager != null && eventManager.isRunning()) {
eventManager.endEvent("Server-Shutdown");
}
getLogger().info("EventEngine deaktiviert.");
}
// ─── Getter ────────────────────────────────────────────────────────────
public static EventEngine getInstance() { return instance; }
public ConfigManager getConfigManager() { return configManager; }
public EventRegistry getEventRegistry() { return eventRegistry; }
public EventManager getEventManager() { return eventManager; }
public EventScheduler getEventScheduler() { return eventScheduler; }
public EventGUI getEventGUI() { return eventGUI; }
public EventCreateListener getEventCreateListener() { return eventCreateListener; }
public RegionSetupManager getRegionSetupManager() { return regionSetupManager; }
public String prefix() { return configManager.getPrefix(); }
}

View File

@@ -0,0 +1,318 @@
package dev.viper.eventengine.command;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.command.RegionSetupManager;
import dev.viper.eventengine.model.ActiveEvent;
import dev.viper.eventengine.model.EventDefinition;
import dev.viper.eventengine.model.ScheduleEntry;
import dev.viper.eventengine.manager.EventManager;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import java.util.*;
import java.util.stream.Collectors;
public class EventCommand implements CommandExecutor, TabCompleter {
private final EventEngine plugin;
public EventCommand(EventEngine plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
String p = plugin.prefix();
if (args.length == 0) {
if (sender instanceof Player player) {
plugin.getEventGUI().openMain(player);
} else {
sendHelp(sender);
}
return true;
}
switch (args[0].toLowerCase()) {
// ─── GUI ───────────────────────────────────────────────────────
case "gui" -> {
requirePlayer(sender, () -> plugin.getEventGUI().openMain((Player) sender));
}
// ─── START ─────────────────────────────────────────────────────
case "start" -> {
requirePerm(sender, () -> {
if (args.length < 2) { sender.sendMessage(p + "§cUsage: /event start <id|random>"); return; }
String id = args[1].toLowerCase();
EventDefinition def;
if (id.equals("random")) {
def = plugin.getEventRegistry().getWeightedRandom().orElse(null);
} else {
def = plugin.getEventRegistry().get(id).orElse(null);
}
if (def == null) { sender.sendMessage(p + "§cEvent nicht gefunden: §f" + id); return; }
Player initiator = sender instanceof Player pl ? pl : null;
plugin.getEventManager().startEvent(def, initiator);
});
}
// ─── STOP ──────────────────────────────────────────────────────
case "stop" -> {
requirePerm(sender, () -> {
String reason = args.length > 1 ? String.join(" ", Arrays.copyOfRange(args, 1, args.length)) : "Admin";
if (!plugin.getEventManager().endEvent(reason)) {
sender.sendMessage(p + "§cKein Event läuft.");
}
});
}
// ─── JOIN/LEAVE ────────────────────────────────────────────────
case "join" -> requirePlayer(sender, () -> plugin.getEventManager().join((Player) sender));
case "leave" -> requirePlayer(sender, () -> plugin.getEventManager().leave((Player) sender));
// ─── INFO ──────────────────────────────────────────────────────
case "info" -> {
if (args.length >= 2) {
// Event-Info
plugin.getEventRegistry().get(args[1]).ifPresentOrElse(def -> {
sender.sendMessage("§8§m══════════════════════════════");
sender.sendMessage("§6 " + def.getDisplayName() + " §8[" + def.getId() + "]");
sender.sendMessage("§7 Kategorie: §f" + def.getCategory().getDisplayName());
sender.sendMessage("§7 Beschreibung: §f" + def.getDescription());
sender.sendMessage("§7 Dauer: §f" + EventManager.formatTime(def.getDurationSeconds()));
sender.sendMessage("§7 Spieler: §f" + def.getMinPlayers() + "" + def.getMaxPlayers());
sender.sendMessage("§7 Custom: §f" + def.isCustom());
sender.sendMessage("§7 Start-Befehle: §f" + def.getStartCommands().size());
sender.sendMessage("§7 Belohnungen: §f" + def.getRewards().size());
sender.sendMessage("§8§m══════════════════════════════");
}, () -> sender.sendMessage(p + "§cEvent nicht gefunden."));
} else {
// Aktuelles Event
ActiveEvent current = plugin.getEventManager().getCurrentEvent();
if (current == null) {
sender.sendMessage(p + "§cKein Event aktiv.");
} else {
sender.sendMessage("§8§m══════════════════════════════");
sender.sendMessage("§6 Aktuelles Event: §e" + current.getDefinition().getDisplayName());
sender.sendMessage("§7 Teilnehmer: §f" + current.getParticipantCount());
sender.sendMessage("§7 Verbleibend: §f" + EventManager.formatTime((int) current.getRemainingSeconds()));
sender.sendMessage("§7 Status: §f" + current.getState());
sender.sendMessage("§8§m══════════════════════════════");
}
}
}
// ─── LIST ──────────────────────────────────────────────────────
case "list" -> {
int page = args.length >= 2 ? parseIntSafe(args[1], 1) - 1 : 0;
List<EventDefinition> all = new ArrayList<>(plugin.getEventRegistry().getAll());
int perPage = 12;
int totalPages = Math.max(1, (int) Math.ceil(all.size() / (double) perPage));
page = Math.max(0, Math.min(page, totalPages - 1));
sender.sendMessage("§8§m══════════════════════════════");
sender.sendMessage("§6 EventEngine Events §8(" + (page + 1) + "/" + totalPages + ") §7[" + all.size() + " total]");
all.stream().skip((long) page * perPage).limit(perPage).forEach(def ->
sender.sendMessage(" §7- §e" + def.getId() + " §8│ §f" + def.getDisplayName() + " §8│ §7" + def.getCategory().getDisplayName())
);
sender.sendMessage("§8§m══════════════════════════════");
if (totalPages > 1) sender.sendMessage("§7Nächste Seite: §f/event list " + (page + 2));
}
// ─── SCHEDULE ──────────────────────────────────────────────────
case "schedule" -> {
List<ScheduleEntry> schedule = plugin.getConfigManager().getSchedule();
sender.sendMessage("§8§m══════════════════════════════");
sender.sendMessage("§6 Geplante Events §8(" + schedule.size() + ")");
if (schedule.isEmpty()) {
sender.sendMessage("§7 Kein Zeitplan konfiguriert.");
sender.sendMessage("§7 Füge Einträge in der config.yml hinzu.");
} else {
schedule.forEach(e -> sender.sendMessage(" §7• §f" + e));
}
sender.sendMessage("§8§m══════════════════════════════");
}
// ─── CREATE ────────────────────────────────────────────────────
case "create" -> {
requirePerm(sender, () -> {
requirePlayer(sender, () -> {
if (args.length < 2) { sender.sendMessage(p + "§cUsage: /event create <id>"); return; }
String id = args[1].toLowerCase().replaceAll("[^a-z0-9_]", "_");
if (plugin.getEventRegistry().exists(id)) {
sender.sendMessage(p + "§cID bereits vorhanden: §f" + id);
return;
}
if (plugin.getEventCreateListener().hasSession((Player) sender)) {
sender.sendMessage(p + "§cDu hast bereits einen laufenden Builder.");
return;
}
plugin.getEventCreateListener().startSession((Player) sender, id);
});
});
}
// ─── DELETE ────────────────────────────────────────────────────
case "delete" -> {
requirePerm(sender, () -> {
if (args.length < 2) { sender.sendMessage(p + "§cUsage: /event delete <id>"); return; }
String id = args[1].toLowerCase();
EventDefinition def = plugin.getEventRegistry().get(id).orElse(null);
if (def == null) { sender.sendMessage(p + "§cEvent nicht gefunden."); return; }
if (!def.isCustom()) { sender.sendMessage(p + "§cEingebaute Events können nicht gelöscht werden."); return; }
plugin.getEventRegistry().remove(id);
sender.sendMessage(p + "§aCustom Event §e'" + id + "' §agelöscht.");
});
}
// ─── SCORE ─────────────────────────────────────────────────────
case "score" -> {
requirePerm(sender, () -> {
if (args.length < 3) { sender.sendMessage(p + "§cUsage: /event score <spieler> <punkte>"); return; }
Player target = Bukkit.getPlayer(args[1]);
if (target == null) { sender.sendMessage(p + "§cSpieler nicht gefunden."); return; }
int points = parseIntSafe(args[2], 0);
ActiveEvent ev = plugin.getEventManager().getCurrentEvent();
if (ev == null) { sender.sendMessage(p + "§cKein Event aktiv."); return; }
ev.addScore(target.getUniqueId(), points);
sender.sendMessage(p + "§a+" + points + " Punkte für §e" + target.getName());
});
}
// ─── ROTATION ──────────────────────────────────────────────────
case "rotation" -> {
requirePerm(sender, () -> {
if (args.length < 3) { sender.sendMessage(p + "§cUsage: /event rotation <add|remove> <id>"); return; }
String action = args[1].toLowerCase();
String id = args[2].toLowerCase();
plugin.getEventRegistry().get(id).ifPresentOrElse(def -> {
boolean rotState = action.equals("add");
def.setInRotation(rotState);
if (def.isCustom()) plugin.getConfigManager().saveCustomEvent(def);
sender.sendMessage(p + "§e" + def.getDisplayName() + " §7→ Rotation: " + (rotState ? "§aAktiv" : "§cInaktiv"));
}, () -> sender.sendMessage(p + "§cEvent nicht gefunden."));
});
}
// ─── RELOAD ────────────────────────────────────────────────────
case "reload" -> {
requirePerm(sender, () -> {
plugin.getConfigManager().load();
plugin.getEventRegistry().init();
plugin.getEventScheduler().restart();
sender.sendMessage(p + "§aKonfiguration neu geladen. §7(" + plugin.getEventRegistry().count() + " Events)");
});
}
// ─── REGION ────────────────────────────────────────────────
case "region" -> {
requirePerm(sender, () -> {
requirePlayer(sender, () -> {
if (args.length < 3) {
sender.sendMessage(p + "§cUsage: /event region <pos1|pos2|clear|info> <id>");
return;
}
String sub = args[1].toLowerCase();
String id = args[2].toLowerCase();
RegionSetupManager rsm = plugin.getRegionSetupManager();
switch (sub) {
case "pos1" -> rsm.handlePos1((Player) sender, id);
case "pos2" -> rsm.handlePos2((Player) sender, id);
case "clear" -> rsm.handleClear((Player) sender, id);
case "info" -> rsm.handleInfo((Player) sender, id);
default -> sender.sendMessage(p + "§cUnbekannte Sub-Option. pos1 | pos2 | clear | info");
}
});
});
}
default -> sendHelp(sender);
}
return true;
}
// ─── Tab-Completer ─────────────────────────────────────────────────────
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
if (args.length == 1) {
return filter(args[0], "gui", "start", "stop", "join", "leave", "info", "list",
"schedule", "create", "delete", "score", "rotation", "region", "reload");
}
if (args.length == 2) {
return switch (args[0].toLowerCase()) {
case "start", "info", "delete" -> {
List<String> ids = plugin.getEventRegistry().getAll().stream()
.map(EventDefinition::getId)
.collect(Collectors.toList());
if (args[0].equalsIgnoreCase("start")) ids.add(0, "random");
yield filter(args[1], ids.toArray(new String[0]));
}
case "rotation" -> filter(args[1], "add", "remove");
case "score" -> null; // Spielernamen
case "region" -> filter(args[1], "pos1", "pos2", "clear", "info");
default -> null;
};
}
if (args.length == 3 && args[0].equalsIgnoreCase("rotation")) {
return plugin.getEventRegistry().getAll().stream()
.map(EventDefinition::getId)
.filter(id -> id.startsWith(args[2].toLowerCase()))
.collect(Collectors.toList());
}
return null;
}
// ─── Hilfsmethoden ─────────────────────────────────────────────────────
private void sendHelp(CommandSender sender) {
sender.sendMessage("§8§m══════════════════════════════");
sender.sendMessage("§6 EventEngine Befehle");
sender.sendMessage("§e /event gui §7- GUI öffnen");
sender.sendMessage("§e /event start <id|random> §7- Event starten");
sender.sendMessage("§e /event stop [grund] §7- Event beenden");
sender.sendMessage("§e /event join/leave §7- Am Event teilnehmen");
sender.sendMessage("§e /event info [id] §7- Event-Info anzeigen");
sender.sendMessage("§e /event list [seite] §7- Alle Events auflisten");
sender.sendMessage("§e /event schedule §7- Zeitplan anzeigen");
sender.sendMessage("§e /event create <id> §7- Custom Event erstellen");
sender.sendMessage("§e /event delete <id> §7- Custom Event löschen");
sender.sendMessage("§e /event score <spieler> <punkte> §7- Punkte vergeben");
sender.sendMessage("§e /event rotation <add|remove> <id> §7- Rotation steuern");
sender.sendMessage("§e /event reload §7- Config neu laden");
sender.sendMessage("§e /event region <pos1|pos2|clear|info> <id> §7- Event-Arena setzen");
sender.sendMessage("§8§m══════════════════════════════");
}
private void requirePerm(CommandSender sender, Runnable r) {
if (!sender.hasPermission("eventengine.admin")) {
sender.sendMessage(plugin.prefix() + "§cKeine Berechtigung.");
return;
}
r.run();
}
private void requirePlayer(CommandSender sender, Runnable r) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.prefix() + "§cNur für Spieler.");
return;
}
r.run();
}
private List<String> filter(String prefix, String... options) {
return Arrays.stream(options)
.filter(s -> s.toLowerCase().startsWith(prefix.toLowerCase()))
.collect(Collectors.toList());
}
private int parseIntSafe(String s, int def) {
try { return Integer.parseInt(s); } catch (Exception e) { return def; }
}
}

View File

@@ -0,0 +1,104 @@
package dev.viper.eventengine.command;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.EventDefinition;
import dev.viper.eventengine.model.EventRegion;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Stellt Pos1/Pos2-Auswahl für Event-Regionen bereit.
* Eingebaut in EventCommand via sub-commands:
*
* /event region pos1 <id> → Pos1 auf Spieler-Position setzen
* /event region pos2 <id> → Pos2 setzen + Region speichern
* /event region clear <id> → Region entfernen
* /event region info <id> → Region anzeigen
*/
public class RegionSetupManager {
private final EventEngine plugin;
// Temporäre Pos1-Speicher pro Spieler: UUID → [eventId, Location]
private final Map<UUID, Object[]> pos1Selection = new HashMap<>();
public RegionSetupManager(EventEngine plugin) {
this.plugin = plugin;
}
public void handlePos1(Player player, String eventId) {
EventDefinition def = plugin.getEventRegistry().get(eventId).orElse(null);
if (def == null) { player.sendMessage(plugin.prefix() + "§cEvent nicht gefunden: §f" + eventId); return; }
pos1Selection.put(player.getUniqueId(), new Object[]{eventId, player.getLocation().clone()});
player.sendMessage(plugin.prefix() + "§aPos1 gesetzt: §f" + formatLoc(player));
player.sendMessage(plugin.prefix() + "§7Jetzt: §f/event region pos2 " + eventId);
}
public void handlePos2(Player player, String eventId) {
EventDefinition def = plugin.getEventRegistry().get(eventId).orElse(null);
if (def == null) { player.sendMessage(plugin.prefix() + "§cEvent nicht gefunden: §f" + eventId); return; }
Object[] sel = pos1Selection.get(player.getUniqueId());
if (sel == null || !sel[0].equals(eventId)) {
player.sendMessage(plugin.prefix() + "§cZuerst Pos1 setzen: §f/event region pos1 " + eventId);
return;
}
org.bukkit.Location pos1 = (org.bukkit.Location) sel[1];
org.bukkit.Location pos2 = player.getLocation().clone();
if (!pos1.getWorld().equals(pos2.getWorld())) {
player.sendMessage(plugin.prefix() + "§cBeide Positionen müssen in der gleichen Welt sein!");
return;
}
EventRegion region = new EventRegion(pos1, pos2);
def.setRegion(region);
// Custom Events direkt speichern; builtin: in memory (gilt bis Reload)
if (def.isCustom()) plugin.getConfigManager().saveCustomEvent(def);
pos1Selection.remove(player.getUniqueId());
player.sendMessage(plugin.prefix() + "§a✔ Region gesetzt für §e" + def.getDisplayName() + "§a:");
player.sendMessage("§7 Welt: §f" + region.getWorldName());
player.sendMessage("§7 Von: §f" + region.getMinX() + ", " + region.getMinY() + ", " + region.getMinZ());
player.sendMessage("§7 Bis: §f" + region.getMaxX() + ", " + region.getMaxY() + ", " + region.getMaxZ());
player.sendMessage("§7 Größe: §f" + region.getSizeX() + "x" + region.getSizeY() + "x" + region.getSizeZ());
}
public void handleClear(Player player, String eventId) {
EventDefinition def = plugin.getEventRegistry().get(eventId).orElse(null);
if (def == null) { player.sendMessage(plugin.prefix() + "§cEvent nicht gefunden: §f" + eventId); return; }
def.setRegion(null);
if (def.isCustom()) plugin.getConfigManager().saveCustomEvent(def);
player.sendMessage(plugin.prefix() + "§7Region für §e" + def.getDisplayName() + " §7entfernt (gesamte Welt).");
}
public void handleInfo(Player player, String eventId) {
EventDefinition def = plugin.getEventRegistry().get(eventId).orElse(null);
if (def == null) { player.sendMessage(plugin.prefix() + "§cEvent nicht gefunden: §f" + eventId); return; }
if (!def.hasRegion()) {
player.sendMessage(plugin.prefix() + "§e" + def.getDisplayName() + " §7hat keine Region (gesamte Welt).");
return;
}
EventRegion r = def.getRegion();
player.sendMessage("§8§m══════════════════════════════");
player.sendMessage("§6 Region: §e" + def.getDisplayName());
player.sendMessage("§7 Welt: §f" + r.getWorldName());
player.sendMessage("§7 Von: §f" + r.getMinX() + ", " + r.getMinY() + ", " + r.getMinZ());
player.sendMessage("§7 Bis: §f" + r.getMaxX() + ", " + r.getMaxY() + ", " + r.getMaxZ());
player.sendMessage("§7 Größe: §f" + r.getSizeX() + "×" + r.getSizeY() + "×" + r.getSizeZ() + " Blöcke");
player.sendMessage("§8§m══════════════════════════════");
}
private String formatLoc(Player p) {
return p.getWorld().getName() + " "
+ p.getLocation().getBlockX() + ", "
+ p.getLocation().getBlockY() + ", "
+ p.getLocation().getBlockZ();
}
}

View File

@@ -0,0 +1,169 @@
package dev.viper.eventengine.config;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.EventDefinition;
import dev.viper.eventengine.model.ScheduleEntry;
import dev.viper.eventengine.util.ColorUtil;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.time.DayOfWeek;
import java.time.LocalTime;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.logging.Logger;
public class ConfigManager {
private final EventEngine plugin;
private final Logger log;
private FileConfiguration mainConfig;
private File customEventsFile;
private FileConfiguration customEventsConfig;
// Geladene Zeitplan-Einträge
private final List<ScheduleEntry> schedule = new ArrayList<>();
// Intervall-Fallback (Minuten), wenn kein Zeitplan aktiv
private int intervalMinutes;
private boolean useInterval;
private boolean randomOnInterval;
private String defaultEventId;
// Ankündigungs-Vorlauf in Sekunden
private int announceBefore;
// Ob Events im Chat-Log erscheinen
private boolean logEvents;
// Prefix für alle Nachrichten
private String prefix;
// Schutz-Einstellungen
private boolean enforceRegionBoundary;
private boolean noExplosionBlockDamage;
private boolean restrictBlockInteraction;
public ConfigManager(EventEngine plugin) {
this.plugin = plugin;
this.log = plugin.getLogger();
}
// ─── Laden ─────────────────────────────────────────────────────────────
public void load() {
plugin.saveDefaultConfig();
plugin.reloadConfig();
mainConfig = plugin.getConfig();
loadSchedule();
loadGeneral();
loadCustomEventsFile();
}
private void loadGeneral() {
intervalMinutes = mainConfig.getInt("settings.interval-minutes", 60);
useInterval = mainConfig.getBoolean("settings.use-interval", false);
randomOnInterval = mainConfig.getBoolean("settings.random-on-interval", true);
defaultEventId = mainConfig.getString("settings.default-event", "RANDOM");
announceBefore = mainConfig.getInt("settings.announce-before-seconds", 30);
logEvents = mainConfig.getBoolean("settings.log-events", true);
enforceRegionBoundary = mainConfig.getBoolean("protection.enforce-region-boundary", true);
noExplosionBlockDamage = mainConfig.getBoolean("protection.no-explosion-block-damage", true);
restrictBlockInteraction = mainConfig.getBoolean("protection.restrict-block-interaction", true);
prefix = ColorUtil.color(mainConfig.getString("settings.prefix", "&8[&6EventEngine&8]&r "));
}
private void loadSchedule() {
schedule.clear();
List<Map<?, ?>> entries = mainConfig.getMapList("schedule");
for (Map<?, ?> entry : entries) {
try {
String timeStr = (String) entry.get("time");
String eventId = (String) entry.get("event");
if (timeStr == null || eventId == null) continue;
LocalTime time = LocalTime.parse(timeStr);
List<DayOfWeek> days = new ArrayList<>();
Object daysRaw = entry.get("days");
if (daysRaw instanceof List<?> dayList) {
for (Object d : dayList) {
String ds = d.toString().toUpperCase();
if (ds.equals("DAILY")) { days.clear(); break; }
try { days.add(DayOfWeek.valueOf(ds)); }
catch (Exception ignored) {}
}
}
schedule.add(new ScheduleEntry(days, time, eventId));
} catch (DateTimeParseException e) {
log.warning("Ungültiger Zeitplan-Eintrag: " + entry);
}
}
log.info("Zeitplan geladen: " + schedule.size() + " Einträge.");
}
private void loadCustomEventsFile() {
customEventsFile = new File(plugin.getDataFolder(), "custom_events.yml");
if (!customEventsFile.exists()) {
try { customEventsFile.createNewFile(); }
catch (IOException e) { log.severe("Konnte custom_events.yml nicht erstellen!"); }
}
customEventsConfig = YamlConfiguration.loadConfiguration(customEventsFile);
}
// ─── Custom Events lesen/schreiben ─────────────────────────────────────
public Map<String, EventDefinition> loadCustomEvents() {
Map<String, EventDefinition> result = new LinkedHashMap<>();
ConfigurationSection root = customEventsConfig.getConfigurationSection("events");
if (root == null) return result;
for (String id : root.getKeys(false)) {
ConfigurationSection sec = root.getConfigurationSection(id);
if (sec != null) {
EventDefinition def = EventDefinition.fromConfig(id, sec);
result.put(id, def);
}
}
log.info("Custom Events geladen: " + result.size());
return result;
}
public void saveCustomEvent(EventDefinition def) {
ConfigurationSection root = customEventsConfig.getConfigurationSection("events");
if (root == null) root = customEventsConfig.createSection("events");
ConfigurationSection sec = root.createSection(def.getId());
def.saveToConfig(sec);
try {
customEventsConfig.save(customEventsFile);
} catch (IOException e) {
log.severe("Konnte custom_events.yml nicht speichern: " + e.getMessage());
}
}
public void deleteCustomEvent(String id) {
if (customEventsConfig.contains("events." + id)) {
customEventsConfig.set("events." + id, null);
try { customEventsConfig.save(customEventsFile); }
catch (IOException e) { log.severe("Speicherfehler: " + e.getMessage()); }
}
}
// ─── Getter ────────────────────────────────────────────────────────────
public List<ScheduleEntry> getSchedule() { return Collections.unmodifiableList(schedule); }
public int getIntervalMinutes() { return intervalMinutes; }
public boolean isUseInterval() { return useInterval; }
public boolean isRandomOnInterval() { return randomOnInterval; }
public String getDefaultEventId() { return defaultEventId; }
public int getAnnounceBefore() { return announceBefore; }
public boolean isLogEvents() { return logEvents; }
public String getPrefix() { return prefix; }
public boolean isEnforceRegionBoundary() { return enforceRegionBoundary; }
public boolean isNoExplosionBlockDamage() { return noExplosionBlockDamage; }
public boolean isRestrictBlockInteraction() { return restrictBlockInteraction; }
public FileConfiguration getMainConfig() { return mainConfig; }
}

View File

@@ -0,0 +1,53 @@
package dev.viper.eventengine.config;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.util.ColorUtil;
import dev.viper.eventengine.model.EventCategory;
import dev.viper.eventengine.model.EventDefinition;
import org.bukkit.configuration.ConfigurationSection;
import java.util.List;
/**
* Liest den "event-overrides" Block aus config.yml und
* überschreibt die Defaults eingebauter EventDefinitions.
*/
public class EventOverrideLoader {
private final EventEngine plugin;
public EventOverrideLoader(EventEngine plugin) {
this.plugin = plugin;
}
public void apply(EventDefinition def) {
ConfigurationSection overrides = plugin.getConfigManager()
.getMainConfig().getConfigurationSection("event-overrides");
if (overrides == null) return;
ConfigurationSection sec = overrides.getConfigurationSection(def.getId());
if (sec == null) return;
if (sec.contains("display-name")) def.setDisplayName(sec.getString("display-name"));
if (sec.contains("description")) def.setDescription(sec.getString("description"));
if (sec.contains("duration-seconds")) def.setDurationSeconds(sec.getInt("duration-seconds"));
if (sec.contains("min-players")) def.setMinPlayers(sec.getInt("min-players"));
if (sec.contains("max-players")) def.setMaxPlayers(sec.getInt("max-players"));
if (sec.contains("announcement")) def.setAnnouncement(ColorUtil.color(sec.getString("announcement")));
if (sec.contains("in-rotation")) def.setInRotation(sec.getBoolean("in-rotation"));
if (sec.contains("weight")) def.setWeight(sec.getInt("weight"));
if (sec.contains("start-commands")) def.setStartCommands(sec.getStringList("start-commands"));
if (sec.contains("end-commands")) def.setEndCommands(sec.getStringList("end-commands"));
if (sec.contains("rewards")) def.setRewards(sec.getStringList("rewards"));
if (sec.contains("category")) {
try { def.setCategory(EventCategory.valueOf(sec.getString("category").toUpperCase())); }
catch (Exception ignored) {}
}
ConfigurationSection settings = sec.getConfigurationSection("settings");
if (settings != null) {
for (String key : settings.getKeys(false)) {
def.setSetting(key, settings.get(key));
}
}
}
}

View File

@@ -0,0 +1,123 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.*;
import org.bukkit.attribute.Attribute;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
import org.bukkit.boss.BossBar;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDeathEvent;
import java.util.UUID;
/**
* Boss Rush:
* - 5 Bosse nacheinander, jeder stärker als der vorherige
* - BossBar zeigt HP
* - Wer den letzten Schlag landet: Bonus-Punkte
*/
public class BossRushHandler implements IEventHandler, Listener {
private static final String[][] BOSSES = {
{"§2Mini-Zomboss", "ZOMBIE"},
{"§6Skelett-König", "SKELETON"},
{"§dHexen-Mutter", "WITCH"},
{"§cRiesen-Creeper", "CREEPER"},
{"§4§lDER ENDGEGNER", "WITHER_SKELETON"}
};
private final EventEngine plugin;
private ActiveEvent currentEvent;
private int bossIndex = 0;
private LivingEntity currentBoss;
private BossBar bossBar;
public BossRushHandler(EventEngine plugin) {
this.plugin = plugin;
}
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
this.bossIndex = 0;
Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§4⚔ §cBoss Rush! §75 Bosse nacheinander. Wer überlebt?");
spawnNextBoss();
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
if (bossBar != null) { bossBar.removeAll(); bossBar = null; }
if (currentBoss != null && !currentBoss.isDead()) currentBoss.remove();
this.currentEvent = null;
}
private void spawnNextBoss() {
if (bossIndex >= BOSSES.length) {
broadcast("§a✔ §eAlle Bosse besiegt! Boss Rush abgeschlossen!");
plugin.getEventManager().endEvent("Alle Bosse besiegt");
return;
}
String[] bossData = BOSSES[bossIndex];
String bossName = bossData[0];
EntityType type;
try { type = EntityType.valueOf(bossData[1]); }
catch (Exception e) { type = EntityType.ZOMBIE; }
// Spawn bei erstem Online-Teilnehmer
Location loc = null;
for (UUID uuid : currentEvent.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p != null) { loc = p.getLocation().add(5, 0, 0); break; }
}
if (loc == null) return;
double hp = 40 + (bossIndex * 40);
currentBoss = (LivingEntity) loc.getWorld().spawnEntity(loc, type);
currentBoss.setCustomName(bossName);
currentBoss.setCustomNameVisible(true);
if (currentBoss.getAttribute(Attribute.MAX_HEALTH) != null) {
currentBoss.getAttribute(Attribute.MAX_HEALTH).setBaseValue(hp);
currentBoss.setHealth(hp);
}
// BossBar
if (bossBar != null) bossBar.removeAll();
bossBar = Bukkit.createBossBar(bossName, BarColor.RED, BarStyle.SEGMENTED_10);
for (UUID uuid : currentEvent.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p != null) bossBar.addPlayer(p);
}
bossBar.setVisible(true);
broadcast("§c⚠ §lBoss " + (bossIndex + 1) + "/" + BOSSES.length + ": " + bossName + " §c§l erscheint!");
bossIndex++;
}
@EventHandler
public void onBossDeath(EntityDeathEvent e) {
if (currentEvent == null || currentBoss == null) return;
if (!e.getEntity().getUniqueId().equals(currentBoss.getUniqueId())) return;
Player killer = e.getEntity().getKiller();
if (killer != null && currentEvent.isParticipant(killer)) {
int bonus = bossIndex * 10;
currentEvent.addScore(killer.getUniqueId(), bonus);
broadcast("§a✔ §f" + killer.getName() + " §7hat den Boss bezwungen! §a+" + bonus + " §7Punkte");
}
if (bossBar != null) bossBar.setVisible(false);
broadcast("§c§l☠ Boss besiegt! §r§7Nächster Boss in 5 Sekunden...");
Bukkit.getScheduler().runTaskLater(plugin, this::spawnNextBoss, 100L);
}
private void broadcast(String msg) { Bukkit.broadcastMessage(msg); }
}

View File

@@ -0,0 +1,99 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.potion.PotionEffect;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* PvP Deathmatch:
* - Kills = Punkte
* - Tod → Respawn nach 3s mit vollen HP
* - Am Ende: Spieler mit meisten Kills gewinnt
*/
public class DeathMatchHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent currentEvent;
private final Map<UUID, Integer> killCount = new HashMap<>();
public DeathMatchHandler(EventEngine plugin) {
this.plugin = plugin;
}
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
killCount.clear();
Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§c⚔ §ePvP ist aktiv! Kills = Punkte. Viel Erfolg!");
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
this.currentEvent = null;
killCount.clear();
// Alle Teilnehmer: PvP-Effekte entfernen
for (UUID uuid : event.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p != null) {
for (PotionEffect eff : p.getActivePotionEffects())
p.removePotionEffect(eff.getType());
p.setHealth(Math.min(p.getMaxHealth(), 20));
}
}
}
@EventHandler
public void onDeath(PlayerDeathEvent e) {
Player victim = e.getEntity();
if (currentEvent == null || !currentEvent.isParticipant(victim)) return;
Player killer = victim.getKiller();
if (killer != null && currentEvent.isParticipant(killer)) {
// Kill → Punkt
currentEvent.addScore(killer.getUniqueId(), 1);
killCount.merge(killer.getUniqueId(), 1, Integer::sum);
int kills = killCount.getOrDefault(killer.getUniqueId(), 0);
killer.sendTitle("§c⚔ Kill!", "§7Kills: §e" + kills, 5, 30, 10);
killer.playSound(killer.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1f, 1.5f);
}
// Respawn nach 3 Sekunden
Location respawn = victim.getWorld().getSpawnLocation();
e.setDeathMessage(null);
Bukkit.getScheduler().runTaskLater(plugin, () -> {
if (victim.isOnline()) {
victim.spigot().respawn();
victim.teleport(respawn);
victim.setHealth(Math.min(victim.getMaxHealth(), 20));
victim.sendMessage(plugin.prefix() + "§7Du bist respawnt — kämpfe weiter!");
}
}, 60L); // 3s
}
@Override
public void onPlayerJoin(ActiveEvent event, Player player) {
player.setHealth(Math.min(player.getMaxHealth(), 20));
player.setFoodLevel(20);
broadcast("§a+ §f" + player.getName() + " §7nimmt am Deathmatch teil!");
}
private void broadcast(String msg) {
Bukkit.broadcastMessage(plugin.prefix() + msg);
}
}

View File

@@ -0,0 +1,112 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.UUID;
/**
* Drop Party:
* - Items regnen alle 2s über allen Online-Spielern
* - Item-Pool: Common/Rare/Epic-Loot
* - Loot landet als Entity am Boden
*/
public class DropPartyHandler implements IEventHandler, Listener {
// Loot-Tabelle: Material, Menge, Gewichtung
private static final Object[][] LOOT = {
// Common (viel)
{Material.BREAD, 8, 30},
{Material.IRON_INGOT, 5, 25},
{Material.COAL, 16, 20},
{Material.ARROW, 32, 20},
{Material.TORCH, 16, 20},
// Uncommon
{Material.GOLD_INGOT, 5, 10},
{Material.EXPERIENCE_BOTTLE, 3, 10},
{Material.GOLDEN_APPLE, 2, 8},
// Rare
{Material.DIAMOND, 3, 4},
{Material.EMERALD, 2, 3},
{Material.ENCHANTED_GOLDEN_APPLE, 1, 1},
{Material.DIAMOND_SWORD, 1, 1},
{Material.ELYTRA, 1, 1},
};
private final EventEngine plugin;
private ActiveEvent currentEvent;
private BukkitRunnable dropper;
private final Random rng = new Random();
public DropPartyHandler(EventEngine plugin) {
this.plugin = plugin;
}
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§6🎉 §eDropParty! §7Items regnen vom Himmel! Schnapp dir so viel du kannst!");
for (Player p : Bukkit.getOnlinePlayers())
p.playSound(p.getLocation(), Sound.ENTITY_FIREWORK_ROCKET_LARGE_BLAST, 1f, 1f);
dropper = new BukkitRunnable() {
@Override
public void run() {
if (currentEvent == null) { cancel(); return; }
dropItems();
}
};
dropper.runTaskTimer(plugin, 20L, 40L); // alle 2s
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
if (dropper != null) dropper.cancel();
this.currentEvent = null;
broadcast("§6🎉 §7Drop Party vorbei! Viel Spaß mit dem Loot!");
}
private void dropItems() {
for (Player p : Bukkit.getOnlinePlayers()) {
if (!p.isOnline()) continue;
// 1-3 Items pro Spieler pro Drop
int count = 1 + rng.nextInt(3);
for (int i = 0; i < count; i++) {
ItemStack item = rollLoot();
Location dropLoc = p.getLocation().clone()
.add((rng.nextDouble() - 0.5) * 8, 8, (rng.nextDouble() - 0.5) * 8);
p.getWorld().dropItemNaturally(dropLoc, item);
}
}
}
private ItemStack rollLoot() {
int totalWeight = Arrays.stream(LOOT).mapToInt(e -> (int) e[2]).sum();
int roll = rng.nextInt(totalWeight);
int cumulative = 0;
for (Object[] entry : LOOT) {
cumulative += (int) entry[2];
if (roll < cumulative) {
return new ItemStack((Material) entry[0], (int) entry[1]);
}
}
return new ItemStack(Material.BREAD);
}
private void broadcast(String msg) { Bukkit.broadcastMessage(msg); }
}

View File

@@ -0,0 +1,146 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.EventType;
import java.util.EnumMap;
import java.util.Map;
import java.util.Optional;
public class EventHandlerRegistry {
private final Map<EventType, IEventHandler> handlers = new EnumMap<>(EventType.class);
public EventHandlerRegistry(EventEngine plugin) {
registerAll(plugin);
}
private void registerAll(EventEngine plugin) {
// ── KAMPF ──────────────────────────────────────────────────────────
register(EventType.PVP_DEATHMATCH, new DeathMatchHandler(plugin));
register(EventType.PVP_FREE_FOR_ALL, new DeathMatchHandler(plugin));
register(EventType.PVP_LAST_MAN_STANDING, new LastManStandingHandler(plugin));
register(EventType.PVP_SUMO, new SumoHandler(plugin));
register(EventType.PVP_SPLEEF, new SpleefHandler(plugin));
register(EventType.PVP_SNOWBALL_FIGHT, new SnowballFightHandler(plugin));
register(EventType.PVP_ONE_VS_ONE, new OneVsOneHandler(plugin));
register(EventType.PVP_TEAM_BATTLE, new TeamBattleHandler(plugin));
register(EventType.PVP_BOW_ONLY, new BowOnlyHandler(plugin));
register(EventType.PVP_SWORD_ONLY, new SwordOnlyHandler(plugin));
register(EventType.PVP_FIST_FIGHT, new FistFightHandler(plugin));
register(EventType.PVP_KIT_PVP, new KitPvPHandler(plugin));
register(EventType.PVP_KING_OF_THE_HILL, new KingOfTheHillHandler(plugin));
register(EventType.PVP_HUNGER_GAMES, new HungerGamesHandler(plugin));
register(EventType.PVP_CAPTURE_THE_FLAG, new CaptureTheFlagHandler(plugin));
register(EventType.PVP_BEDWARS_LITE, new BedWarsLiteHandler(plugin));
register(EventType.PVP_SKYWARS_LITE, new SkyWarsLiteHandler(plugin));
register(EventType.PVP_UHC, new UHCHandler(plugin));
register(EventType.PVP_ELYTRA_PVP, new ElytraPvPHandler(plugin));
register(EventType.PVP_ARENA_SURVIVAL, new ArenaSurvivalHandler(plugin));
// ── ÜBERLEBEN ──────────────────────────────────────────────────────
register(EventType.SURVIVAL_MOB_WAVE, new MobWaveHandler(plugin));
register(EventType.SURVIVAL_BOSS_RUSH, new BossRushHandler(plugin));
register(EventType.SURVIVAL_LAVA_RISING, new LavaRisingHandler(plugin));
register(EventType.SURVIVAL_ZOMBIE_SIEGE, new ZombieSiegeHandler(plugin));
register(EventType.SURVIVAL_WITHER_STORM, new WitherStormHandler(plugin));
register(EventType.SURVIVAL_DRAGON_FIGHT, new DragonFightHandler(plugin));
register(EventType.SURVIVAL_HARDCORE_ROUND,new HardcoreRoundHandler(plugin));
register(EventType.SURVIVAL_ISLAND, new IslandSurvivalHandler(plugin));
register(EventType.SURVIVAL_NETHER_RUN, new NetherRunHandler(plugin));
register(EventType.SURVIVAL_ENDURANCE, new EnduranceHandler(plugin));
register(EventType.SURVIVAL_RAIDS_PLUS, new RaidsPlusHandler(plugin));
register(EventType.SURVIVAL_MONSTER_HUNT, new MonsterHuntHandler(plugin));
register(EventType.SURVIVAL_GRAVITY_SHIFT,new GravityShiftHandler(plugin));
register(EventType.SURVIVAL_RANDOM_SPAWN, new RandomSpawnHandler(plugin));
register(EventType.SURVIVAL_MANHUNT, new ManhuntHandler(plugin));
// ── BAUEN ──────────────────────────────────────────────────────────
register(EventType.BUILD_BATTLE, new BuildBattleHandler(plugin));
register(EventType.BUILD_SPEED_BUILD, new SpeedBuildHandler(plugin));
register(EventType.BUILD_THEME_CHALLENGE, new ThemeChallengeHandler(plugin));
register(EventType.BUILD_PIXEL_ART, new PixelArtHandler(plugin));
register(EventType.BUILD_TALLEST_TOWER, new TallestTowerHandler(plugin));
register(EventType.BUILD_BRIDGE, new BridgeBuildHandler(plugin));
register(EventType.BUILD_REDSTONE, new RedstoneChallengeHandler(plugin));
register(EventType.BUILD_UNDERGROUND, new UndergroundBuildHandler(plugin));
register(EventType.BUILD_SKYBLOCK_STYLE, new SkyblockStyleHandler(plugin));
register(EventType.BUILD_BLINDBUILD, new BlindBuildHandler(plugin));
// ── RENNEN ─────────────────────────────────────────────────────────
register(EventType.RACE_PARKOUR, new ParkourRaceHandler(plugin));
register(EventType.RACE_ELYTRA, new ElytraRaceHandler(plugin));
register(EventType.RACE_BOAT, new BoatRaceHandler(plugin));
register(EventType.RACE_HORSE, new HorseRaceHandler(plugin));
register(EventType.RACE_PIG, new PigRaceHandler(plugin));
register(EventType.RACE_MINECART, new MinecartRaceHandler(plugin));
register(EventType.RACE_SWIMMING, new SwimmingRaceHandler(plugin));
register(EventType.RACE_OBSTACLE, new ObstacleRaceHandler(plugin));
register(EventType.RACE_MAZE, new MazeHandler(plugin));
register(EventType.RACE_ICEBOAT, new IceBoatRaceHandler(plugin));
// ── SAMMELN ────────────────────────────────────────────────────────
register(EventType.COLLECT_SCAVENGER_HUNT,new ScavengerHuntHandler(plugin));
register(EventType.COLLECT_MINING_COMP, new MiningCompHandler(plugin));
register(EventType.COLLECT_FISHING_COMP, new FishingCompHandler(plugin));
register(EventType.COLLECT_FARMING_COMP, new FarmingCompHandler(plugin));
register(EventType.COLLECT_MOB_DROPS, new MobDropsHandler(plugin));
register(EventType.COLLECT_TREASURE_HUNT, new TreasureHuntHandler(plugin));
register(EventType.COLLECT_EASTER_EGG, new EasterEggHandler(plugin));
register(EventType.COLLECT_SPEED_MINE, new SpeedMineHandler(plugin));
register(EventType.COLLECT_WOODCUTTING, new WoodcuttingHandler(plugin));
register(EventType.COLLECT_ENCHANT_RACE, new EnchantRaceHandler(plugin));
// ── SPASS ──────────────────────────────────────────────────────────
register(EventType.FUN_DROP_PARTY, new DropPartyHandler(plugin));
register(EventType.FUN_TNT_RAIN, new TntRainHandler(plugin));
register(EventType.FUN_ITEM_RAIN, new ItemRainHandler(plugin));
register(EventType.FUN_RANDOM_EFFECTS, new RandomEffectsHandler(plugin));
register(EventType.FUN_FIREWORK_SHOW, new FireworkShowHandler(plugin));
register(EventType.FUN_LIGHTNING_STORM, new LightningStormHandler(plugin));
register(EventType.FUN_SPEED_BOOST, new SpeedBoostHandler(plugin));
register(EventType.FUN_CHAOS_MODE, new ChaosModeHandler(plugin));
register(EventType.FUN_TINY_PLAYERS, new TinyPlayersHandler(plugin));
register(EventType.FUN_GIANT_PLAYERS, new GiantPlayersHandler(plugin));
register(EventType.FUN_INVISIBLE_PLAYERS, new InvisiblePlayersHandler(plugin));
register(EventType.FUN_RANDOM_TELEPORT, new RandomTeleportHandler(plugin));
register(EventType.FUN_SWAP_INVENTORIES, new SwapInventoriesHandler(plugin));
register(EventType.FUN_REVERSE_GRAVITY, new ReverseGravityHandler(plugin));
register(EventType.FUN_BOUNCY_BLOCKS, new BouncyBlocksHandler(plugin));
// ── QUIZ ───────────────────────────────────────────────────────────
register(EventType.QUIZ_MINECRAFT_TRIVIA, new TriviaHandler(plugin));
register(EventType.QUIZ_SPEED_QUIZ, new TriviaHandler(plugin));
register(EventType.QUIZ_GENERAL_KNOWLEDGE,new GeneralKnowledgeQuizHandler(plugin));
register(EventType.QUIZ_CRAFTING_CHALLENGE,new CraftingChallengeHandler(plugin));
register(EventType.QUIZ_MOB_QUIZ, new MobQuizHandler(plugin));
// ── WIRTSCHAFT ─────────────────────────────────────────────────────
register(EventType.ECONOMY_LOTTERY, new LotteryHandler(plugin));
register(EventType.ECONOMY_AUCTION, new AuctionHandler(plugin));
register(EventType.ECONOMY_MARKET_RUSH, new MarketRushHandler(plugin));
register(EventType.ECONOMY_TRADE_FRENZY, new TradeFrenzyHandler(plugin));
register(EventType.ECONOMY_BETTING, new BettingHandler(plugin));
// ── TEAM ───────────────────────────────────────────────────────────
register(EventType.TEAM_RELAY_RACE, new TeamRelayRaceHandler(plugin));
register(EventType.TEAM_BUILD_BATTLE, new TeamBuildBattleHandler(plugin));
register(EventType.TEAM_SURVIVAL, new TeamSurvivalHandler(plugin));
register(EventType.TEAM_TREASURE_HUNT, new TeamTreasureHuntHandler(plugin));
register(EventType.TEAM_QUIZ, new TeamQuizHandler(plugin));
register(EventType.TEAM_CAPTURE_POINTS, new CapturePointsHandler(plugin));
register(EventType.TEAM_RESOURCE_RACE, new ResourceRaceHandler(plugin));
register(EventType.TEAM_HIDE_AND_SEEK, new HideAndSeekHandler(plugin));
register(EventType.TEAM_MURDER_MYSTERY, new MurderMysteryHandler(plugin));
register(EventType.TEAM_COLOR_WAR, new ColorWarHandler(plugin));
}
public void register(EventType type, IEventHandler handler) {
handlers.put(type, handler);
}
public Optional<IEventHandler> get(EventType type) {
return Optional.ofNullable(handlers.get(type));
}
}

View File

@@ -0,0 +1,75 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.*;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.inventory.meta.FireworkMeta;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Random;
/**
* Feuerwerk-Show: Feuerwerke steigen über allen Spielern auf
*/
public class FireworkShowHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent currentEvent;
private BukkitRunnable show;
private final Random rng = new Random();
private static final Color[] COLORS = {
Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW,
Color.PURPLE, Color.AQUA, Color.ORANGE, Color.WHITE,
Color.FUCHSIA, Color.LIME
};
public FireworkShowHandler(EventEngine plugin) { this.plugin = plugin; }
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
Bukkit.broadcastMessage(plugin.prefix() + "§e✨ §eFeuerwerk-Show! §7Lehnt euch zurück und genießt!");
show = new BukkitRunnable() {
@Override
public void run() {
if (currentEvent == null) { cancel(); return; }
for (Player p : Bukkit.getOnlinePlayers()) {
spawnFirework(p.getLocation().add(
(rng.nextDouble()-0.5)*10, 5, (rng.nextDouble()-0.5)*10));
}
}
};
show.runTaskTimer(plugin, 5L, 15L);
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
if (show != null) show.cancel();
this.currentEvent = null;
}
private void spawnFirework(Location loc) {
Firework fw = loc.getWorld().spawn(loc, Firework.class);
FireworkMeta meta = fw.getFireworkMeta();
meta.setPower(1 + rng.nextInt(2));
FireworkEffect.Type[] types = FireworkEffect.Type.values();
FireworkEffect effect = FireworkEffect.builder()
.withColor(COLORS[rng.nextInt(COLORS.length)])
.withFade(COLORS[rng.nextInt(COLORS.length)])
.with(types[rng.nextInt(types.length)])
.trail(rng.nextBoolean())
.flicker(rng.nextBoolean())
.build();
meta.addEffect(effect);
fw.setFireworkMeta(meta);
}
}

View File

@@ -0,0 +1,181 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.*;
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Random;
import java.util.UUID;
// ═══════════════════════════════════════════════════════════════════
// TNT-Regen Handler
// ═══════════════════════════════════════════════════════════════════
class TntRainHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent currentEvent;
private BukkitRunnable rain;
private final Random rng = new Random();
TntRainHandler(EventEngine plugin) { this.plugin = plugin; }
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
Bukkit.broadcastMessage(plugin.prefix() + "§c💣 §eTNT-Regen! §7Duck dich! (Spieler haben Blast Protection...)");
// Spielern Blast Protection geben (Rüstung)
for (UUID uuid : event.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p != null) p.addPotionEffect(new PotionEffect(PotionEffectType.RESISTANCE, 99999, 1, false, false));
}
rain = new BukkitRunnable() {
@Override
public void run() {
if (currentEvent == null) { cancel(); return; }
for (Player p : Bukkit.getOnlinePlayers()) {
Location loc = p.getLocation().add(
(rng.nextDouble() - 0.5) * 20, 15, (rng.nextDouble() - 0.5) * 20);
TNTPrimed tnt = p.getWorld().spawn(loc, TNTPrimed.class);
tnt.setFuseTicks(40);
}
}
};
rain.runTaskTimer(plugin, 20L, 30L);
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
if (rain != null) rain.cancel();
for (UUID uuid : event.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p != null) p.removePotionEffect(PotionEffectType.RESISTANCE);
}
this.currentEvent = null;
}
}
// ═══════════════════════════════════════════════════════════════════
// Item-Regen Handler
// ═══════════════════════════════════════════════════════════════════
class ItemRainHandler implements IEventHandler, Listener {
private static final Material[] ITEMS = {
Material.DIAMOND, Material.GOLD_INGOT, Material.IRON_INGOT,
Material.EMERALD, Material.COAL, Material.BREAD, Material.ARROW,
Material.GOLDEN_APPLE, Material.EXPERIENCE_BOTTLE
};
private final EventEngine plugin;
private ActiveEvent currentEvent;
private BukkitRunnable rain;
private final Random rng = new Random();
ItemRainHandler(EventEngine plugin) { this.plugin = plugin; }
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
Bukkit.broadcastMessage(plugin.prefix() + "§d🌧 §eItem-Regen! §7Items fallen vom Himmel!");
rain = new BukkitRunnable() {
@Override
public void run() {
if (currentEvent == null) { cancel(); return; }
for (Player p : Bukkit.getOnlinePlayers()) {
Material mat = ITEMS[rng.nextInt(ITEMS.length)];
Location loc = p.getLocation().add(
(rng.nextDouble() - 0.5) * 12, 12, (rng.nextDouble() - 0.5) * 12);
p.getWorld().dropItemNaturally(loc, new ItemStack(mat, 1 + rng.nextInt(5)));
}
}
};
rain.runTaskTimer(plugin, 10L, 15L);
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
if (rain != null) rain.cancel();
this.currentEvent = null;
}
}
// ═══════════════════════════════════════════════════════════════════
// Blitz-Sturm Handler
// ═══════════════════════════════════════════════════════════════════
class LightningStormHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent currentEvent;
private BukkitRunnable storm;
private final Random rng = new Random();
LightningStormHandler(EventEngine plugin) { this.plugin = plugin; }
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
Bukkit.broadcastMessage(plugin.prefix() + "§e⚡ §eBlitz-Sturm! §7Es blitzt überall!");
storm = new BukkitRunnable() {
@Override
public void run() {
if (currentEvent == null) { cancel(); return; }
for (Player p : Bukkit.getOnlinePlayers()) {
Location loc = p.getLocation().add(
(rng.nextDouble() - 0.5) * 16, 0, (rng.nextDouble() - 0.5) * 16);
p.getWorld().strikeLightningEffect(loc);
}
}
};
storm.runTaskTimer(plugin, 10L, 20L);
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
if (storm != null) storm.cancel();
this.currentEvent = null;
}
}
// ═══════════════════════════════════════════════════════════════════
// Geschwindigkeits-Boost Handler
// ═══════════════════════════════════════════════════════════════════
class SpeedBoostHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent currentEvent;
SpeedBoostHandler(EventEngine plugin) { this.plugin = plugin; }
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
Bukkit.broadcastMessage(plugin.prefix() + "§a💨 §eSpeed Boost! §7Alle Spieler sind für kurze Zeit superschnell!");
for (Player p : Bukkit.getOnlinePlayers()) {
p.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, event.getDefinition().getDurationSeconds() * 20, 4, false, true));
p.addPotionEffect(new PotionEffect(PotionEffectType.JUMP_BOOST, event.getDefinition().getDurationSeconds() * 20, 3, false, true));
}
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
for (Player p : Bukkit.getOnlinePlayers()) {
p.removePotionEffect(PotionEffectType.SPEED);
p.removePotionEffect(PotionEffectType.JUMP_BOOST);
}
this.currentEvent = null;
}
}

View File

@@ -0,0 +1,26 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.entity.Player;
/**
* Optionaler Handler für eingebaute Events mit echter Spiellogik.
* Plugins können über EventHandlerRegistry eigene Handler registrieren.
*/
public interface IEventHandler {
/** Wird beim Start aufgerufen (nach Ankündigung, Sync Main-Thread) */
void onStart(ActiveEvent event);
/** Wird beim Ende aufgerufen */
void onEnd(ActiveEvent event);
/** Ein Spieler tritt bei */
default void onPlayerJoin(ActiveEvent event, Player player) {}
/** Ein Spieler verlässt das Event */
default void onPlayerLeave(ActiveEvent event, Player player) {}
/** Wird jede Sekunde aufgerufen (Tick) */
default void onTick(ActiveEvent event) {}
}

View File

@@ -0,0 +1,87 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* Last Man Standing:
* - Kein Respawn — einmal tot = draußen
* - Letzter Überlebender gewinnt
*/
public class LastManStandingHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent currentEvent;
private final Set<UUID> alive = new HashSet<>();
public LastManStandingHandler(EventEngine plugin) {
this.plugin = plugin;
}
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
alive.clear();
alive.addAll(event.getParticipants());
Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§c☠ §eLast Man Standing! §7Einmal tot = §craus§7.");
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
this.currentEvent = null;
alive.clear();
}
@EventHandler
public void onDeath(PlayerDeathEvent e) {
Player victim = e.getEntity();
if (currentEvent == null || !currentEvent.isParticipant(victim)) return;
alive.remove(victim.getUniqueId());
currentEvent.removeParticipant(victim);
e.setDeathMessage(null);
int remaining = alive.size();
broadcast("§c☠ §f" + victim.getName() + " §7ist ausgeschieden! §8[§e" + remaining + " §7übrig§8]");
victim.sendMessage(plugin.prefix() + "§cDu bist ausgeschieden! Schau dir das Finale an.");
victim.setGameMode(org.bukkit.GameMode.SPECTATOR);
// Noch 1 übrig → Gewinner
if (remaining == 1) {
UUID winnerId = alive.iterator().next();
Player winner = Bukkit.getPlayer(winnerId);
String winName = winner != null ? winner.getName() : "Unbekannt";
currentEvent.addScore(winnerId, 100);
broadcast("§6✦ §e" + winName + " §6ist der letzte Überlebende! §6GEWONNEN!");
if (winner != null) {
winner.playSound(winner.getLocation(), Sound.UI_TOAST_CHALLENGE_COMPLETE, 1f, 1f);
winner.sendTitle("§6GEWONNEN!", "§7Last Man Standing!", 10, 60, 20);
}
plugin.getEventManager().endEvent(winName + " hat gewonnen");
} else if (remaining == 0) {
plugin.getEventManager().endEvent("Unentschieden");
}
}
@Override
public void onPlayerJoin(ActiveEvent event, Player player) {
alive.add(player.getUniqueId());
}
private void broadcast(String msg) { Bukkit.broadcastMessage(msg); }
}

View File

@@ -0,0 +1,105 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.UUID;
/**
* Steigendes Lava:
* - Lava-Level steigt alle 10s um 1 Block
* - Spieler müssen nach oben klettern
* - Wer in der Lava landet = ausgeschieden (Tod)
* - Höchster Überlebender gewinnt (Zeit überleben = Punkte)
*/
public class LavaRisingHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent currentEvent;
private int lavaY = 30;
private BukkitRunnable ticker;
public LavaRisingHandler(EventEngine plugin) {
this.plugin = plugin;
}
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
// Startlevel aus Spieler-Y
lavaY = getLowestPlayerY() - 5;
Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§c🔥 §eDie Lava steigt! §7Klettere nach oben und überlebe so lange wie möglich!");
ticker = new BukkitRunnable() {
int tick = 0;
@Override
public void run() {
if (currentEvent == null) { cancel(); return; }
tick++;
// Punkte pro Sekunde für Überlebende
for (UUID uuid : currentEvent.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p != null) currentEvent.addScore(uuid, 1);
}
// Alle 10s: Lava steigt
if (tick % 10 == 0) {
lavaY++;
// Warnung wenn Lava nah
for (UUID uuid : currentEvent.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p == null) continue;
double dist = p.getLocation().getY() - lavaY;
if (dist < 5) {
p.sendActionBar("§c🔥 LAVA §f" + (int)dist + " §cBlöcke unter dir!");
p.playSound(p.getLocation(), Sound.BLOCK_LAVA_AMBIENT, 1f, 1.5f);
}
}
if (tick % 30 == 0) broadcast("§c🔥 §7Lava-Level: §cY=" + lavaY);
}
// Check: Spieler in/unter Lava
for (UUID uuid : currentEvent.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p != null && p.getLocation().getY() <= lavaY) {
p.setFireTicks(100);
p.damage(4.0);
p.sendActionBar("§c§l🔥 LAVA! Raus da!");
}
}
}
};
ticker.runTaskTimer(plugin, 20L, 20L);
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
if (ticker != null) ticker.cancel();
this.currentEvent = null;
}
private int getLowestPlayerY() {
int lowest = 64;
if (currentEvent == null) return lowest;
for (UUID uuid : currentEvent.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p != null) lowest = Math.min(lowest, p.getLocation().getBlockY());
}
return lowest;
}
private void broadcast(String msg) { Bukkit.broadcastMessage(msg); }
}

View File

@@ -0,0 +1,65 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import java.util.*;
public class LotteryHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent currentEvent;
private final List<UUID> pool = new ArrayList<>();
public LotteryHandler(EventEngine plugin) { this.plugin = plugin; }
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
pool.clear();
Bukkit.getPluginManager().registerEvents(this, plugin);
Bukkit.broadcastMessage(plugin.prefix() + "§6🎟 §eLotterie! §7Nimm teil mit §f/event join §7um ein Los zu erhalten!");
Bukkit.broadcastMessage(plugin.prefix() + "§7Am Ende wird ein §6Gewinner §7gezogen. Viel Glück!");
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
pool.addAll(event.getParticipants());
if (pool.isEmpty()) {
Bukkit.broadcastMessage(plugin.prefix() + "§7Keine Teilnehmer — keine Lotterie.");
this.currentEvent = null;
return;
}
UUID winnerId = pool.get(new Random().nextInt(pool.size()));
Player winner = Bukkit.getPlayer(winnerId);
String name = winner != null ? winner.getName() : "Offline-Spieler";
Bukkit.broadcastMessage("§8§m══════════════════════════════");
Bukkit.broadcastMessage("§6 🎟 Lotterie-Ergebnis!");
Bukkit.broadcastMessage("§7 Teilnehmer: §f" + new HashSet<>(pool).size());
Bukkit.broadcastMessage("§6 🏆 GEWINNER: §e§l" + name + "§r §6🏆");
Bukkit.broadcastMessage("§8§m══════════════════════════════");
if (winner != null) {
winner.playSound(winner.getLocation(), Sound.UI_TOAST_CHALLENGE_COMPLETE, 1f, 1f);
winner.sendTitle("§6GEWONNEN!", "§7Lotterie!", 10, 60, 20);
for (String cmd : event.getDefinition().getRewards())
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd.replace("%player%", winner.getName()));
}
this.currentEvent = null;
}
@Override
public void onPlayerJoin(ActiveEvent event, Player player) {
pool.add(player.getUniqueId());
player.sendMessage(plugin.prefix() + "§a🎟 Los erhalten! §7Du bist im Pool. Viel Glück!");
}
}

View File

@@ -0,0 +1,441 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.*;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.event.player.PlayerHarvestBlockEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
// ══════════════════════════════════════════════════════════
// RENNEN — alle 10
// ══════════════════════════════════════════════════════════
/** Basis für alle Renn-Events: Punkte pro Sekunde, wer am Ende mehr hat gewinnt */
class BaseRaceHandler implements IEventHandler {
protected final EventEngine plugin;
protected final String icon;
protected final String name;
protected BukkitRunnable ticker;
BaseRaceHandler(EventEngine p, String icon, String name) { this.plugin=p; this.icon=icon; this.name=name; }
@Override public void onStart(ActiveEvent e) {
Bukkit.broadcastMessage(plugin.prefix()+icon+" §e"+name+"! §7Bereitet euch vor — die Strecke ist bereit!");
ticker=new BukkitRunnable(){ @Override public void run(){ if(e.getState()==ActiveEvent.State.ENDED){cancel();return;} }};
ticker.runTaskTimer(plugin,20L,20L);
}
@Override public void onEnd(ActiveEvent e){ if(ticker!=null)ticker.cancel(); }
}
class ParkourRaceHandler extends BaseRaceHandler {
ParkourRaceHandler(EventEngine p){super(p,"🏃","Parkour Race");}
@Override public void onStart(ActiveEvent e){ super.onStart(e); Bukkit.broadcastMessage(plugin.prefix()+"§a🏃 §eParkour Race! §7Lauft durch den Kurs — wer zuerst am Ziel ist, gewinnt!"); }
}
class ElytraRaceHandler extends BaseRaceHandler {
ElytraRaceHandler(EventEngine p){super(p,"🪂","Elytra-Rennen");}
@Override public void onStart(ActiveEvent e){
super.onStart(e);
for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null)continue;p.getEquipment().setChestplate(new ItemStack(Material.ELYTRA));p.getInventory().addItem(new ItemStack(Material.FIREWORK_ROCKET,64));}
Bukkit.broadcastMessage(plugin.prefix()+"§b🪂 §eElytra-Rennen! §7Fliegt mit Elytren zum Ziel!");
}
}
class BoatRaceHandler extends BaseRaceHandler {
BoatRaceHandler(EventEngine p){super(p,"","Boot-Rennen");}
@Override public void onStart(ActiveEvent e){ super.onStart(e); for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null)continue;p.getInventory().addItem(new ItemStack(Material.OAK_BOAT));} Bukkit.broadcastMessage(plugin.prefix()+"§b⛵ §eBoot-Rennen! §7Klettert in euer Boot und rast zum Ziel!"); }
}
class HorseRaceHandler extends BaseRaceHandler {
HorseRaceHandler(EventEngine p){super(p,"🐎","Pferde-Rennen");}
@Override public void onStart(ActiveEvent e){ super.onStart(e); Bukkit.broadcastMessage(plugin.prefix()+"§6🐎 §ePferde-Rennen! §7Besteigt eure Pferde — Zügel in die Hand und auf zum Start!"); }
}
class PigRaceHandler extends BaseRaceHandler {
PigRaceHandler(EventEngine p){super(p,"🐷","Schweine-Rennen");}
@Override public void onStart(ActiveEvent e){ super.onStart(e); for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null)continue;p.getInventory().addItem(new ItemStack(Material.CARROT_ON_A_STICK));} Bukkit.broadcastMessage(plugin.prefix()+"§e🐷 §eSchweine-Rennen! §7Schnappt euch eure Karotten-Angel und reitet eure Schweine!"); }
}
class MinecartRaceHandler extends BaseRaceHandler {
MinecartRaceHandler(EventEngine p){super(p,"🚃","Lore-Rennen");}
@Override public void onStart(ActiveEvent e){ super.onStart(e); Bukkit.broadcastMessage(plugin.prefix()+"§7🚃 §eLore-Rennen! §7Setzt euch in eure Lore und rast die Schienen entlang!"); }
}
class SwimmingRaceHandler extends BaseRaceHandler {
SwimmingRaceHandler(EventEngine p){super(p,"🏊","Schwimm-Rennen");}
@Override public void onStart(ActiveEvent e){ super.onStart(e); for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null)continue;p.addPotionEffect(new PotionEffect(PotionEffectType.DOLPHINS_GRACE,e.getDefinition().getDurationSeconds()*20,0));} Bukkit.broadcastMessage(plugin.prefix()+"§9🏊 §eSchwimm-Rennen! §7Los — durch den Kanal zum Ziel!"); }
}
class ObstacleRaceHandler extends BaseRaceHandler {
ObstacleRaceHandler(EventEngine p){super(p,"🏅","Hindernislauf");}
@Override public void onStart(ActiveEvent e){ super.onStart(e); Bukkit.broadcastMessage(plugin.prefix()+"§e🏅 §eHindernislauf! §7Überwindet alle Hindernisse und erreicht das Ziel!"); }
}
class MazeHandler extends BaseRaceHandler {
MazeHandler(EventEngine p){super(p,"🌀","Labyrinth");}
@Override public void onStart(ActiveEvent e){ super.onStart(e); Bukkit.broadcastMessage(plugin.prefix()+"§d🌀 §eLabyrinth! §7Findet den Weg durch das Labyrinth — wer zuerst herauskommt gewinnt!"); }
}
class IceBoatRaceHandler extends BaseRaceHandler {
IceBoatRaceHandler(EventEngine p){super(p,"","Eisboot-Rennen");}
@Override public void onStart(ActiveEvent e){ super.onStart(e); for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null)continue;p.getInventory().addItem(new ItemStack(Material.OAK_BOAT));} Bukkit.broadcastMessage(plugin.prefix()+"§b❄ §eEisboot-Rennen! §7Rast auf dem Eis — Boote auf Blaueis sind blitzschnell!"); }
}
// ══════════════════════════════════════════════════════════
// SAMMEL EVENTS — alle 10
// ══════════════════════════════════════════════════════════
class ScavengerHuntHandler implements IEventHandler {
private final EventEngine plugin;
ScavengerHuntHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){ Bukkit.broadcastMessage(plugin.prefix()+"§6🔍 §eSchatzsuche! §7Findet alle versteckten Items in der Arena. Hinweise folgen im Chat!"); scheduleHints(e); }
@Override public void onEnd(ActiveEvent e){}
private void scheduleHints(ActiveEvent e){
String[] hints={"§7Tipp 1: §fSchau in der Nähe von Bäumen!","§7Tipp 2: §fUnter der Erde könnte etwas versteckt sein...","§7Tipp 3: §fDas Wasser verbirgt Geheimnisse!"};
for(int i=0;i<hints.length;i++){final String h=hints[i]; new BukkitRunnable(){@Override public void run(){if(e.getState()!=ActiveEvent.State.ENDED)Bukkit.broadcastMessage(plugin.prefix()+h);}}.runTaskLater(plugin,(i+1)*60L*20L);}
}
}
class MiningCompHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
private static final Map<Material,Integer> ORE_SCORES=new EnumMap<>(Material.class);
static{ORE_SCORES.put(Material.COAL_ORE,1);ORE_SCORES.put(Material.DEEPSLATE_COAL_ORE,1);ORE_SCORES.put(Material.IRON_ORE,2);ORE_SCORES.put(Material.DEEPSLATE_IRON_ORE,2);ORE_SCORES.put(Material.GOLD_ORE,4);ORE_SCORES.put(Material.DEEPSLATE_GOLD_ORE,4);ORE_SCORES.put(Material.DIAMOND_ORE,10);ORE_SCORES.put(Material.DEEPSLATE_DIAMOND_ORE,10);ORE_SCORES.put(Material.EMERALD_ORE,8);ORE_SCORES.put(Material.ANCIENT_DEBRIS,20);}
MiningCompHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){current=e;Bukkit.getPluginManager().registerEvents(this,plugin);Bukkit.broadcastMessage(plugin.prefix()+"§7⛏ §eMining-Wettbewerb! §7Baut so viele Erze wie möglich ab. Diamanten = 10 Punkte!");}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);current=null;}
@EventHandler public void onBreak(BlockBreakEvent e){if(current==null||!current.isParticipant(e.getPlayer()))return;Integer pts=ORE_SCORES.get(e.getBlock().getType());if(pts!=null){current.addScore(e.getPlayer().getUniqueId(),pts);e.getPlayer().sendActionBar("§7+"+pts+" §7["+e.getBlock().getType().name()+"]");}}
}
class FishingCompHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
FishingCompHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){current=e;Bukkit.getPluginManager().registerEvents(this,plugin);for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null)continue;p.getInventory().addItem(new ItemStack(Material.FISHING_ROD));}Bukkit.broadcastMessage(plugin.prefix()+"§9🎣 §eAngel-Wettbewerb! §7Angelt so viele Fische wie möglich. Schatz-Funde geben Bonuspunkte!");}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);current=null;}
@EventHandler public void onFish(PlayerFishEvent e){
if(current==null||!current.isParticipant(e.getPlayer()))return;
if(e.getState()!=PlayerFishEvent.State.CAUGHT_FISH&&e.getState()!=PlayerFishEvent.State.CAUGHT_ENTITY)return;
int pts=e.getState()==PlayerFishEvent.State.CAUGHT_ENTITY?5:2;
current.addScore(e.getPlayer().getUniqueId(),pts);
e.getPlayer().sendActionBar("§9+"+pts+" §7Angelpunkte!");
}
}
class FarmingCompHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
private static final Map<Material,Integer> CROP_SCORES=new EnumMap<>(Material.class);
static{CROP_SCORES.put(Material.WHEAT,1);CROP_SCORES.put(Material.CARROT,1);CROP_SCORES.put(Material.POTATO,1);CROP_SCORES.put(Material.BEETROOT,1);CROP_SCORES.put(Material.MELON,2);CROP_SCORES.put(Material.PUMPKIN,2);CROP_SCORES.put(Material.SWEET_BERRIES,1);CROP_SCORES.put(Material.COCOA_BEANS,1);}
FarmingCompHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){current=e;Bukkit.getPluginManager().registerEvents(this,plugin);Bukkit.broadcastMessage(plugin.prefix()+"§a🌾 §eFarm-Wettbewerb! §7Erntet so viele Crops wie möglich!");}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);current=null;}
@EventHandler public void onHarvest(PlayerHarvestBlockEvent e){if(current==null||!current.isParticipant(e.getPlayer()))return;for(ItemStack item:e.getItemsHarvested()){Integer pts=CROP_SCORES.get(item.getType());if(pts!=null){current.addScore(e.getPlayer().getUniqueId(),pts*item.getAmount());e.getPlayer().sendActionBar("§a+"+pts+" §7pro Ernte");break;}}}
}
class MobDropsHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
private static final Map<org.bukkit.entity.EntityType,Integer> MOB_SCORES=new EnumMap<>(org.bukkit.entity.EntityType.class);
static{MOB_SCORES.put(org.bukkit.entity.EntityType.ZOMBIE,1);MOB_SCORES.put(org.bukkit.entity.EntityType.SKELETON,1);MOB_SCORES.put(org.bukkit.entity.EntityType.SPIDER,1);MOB_SCORES.put(org.bukkit.entity.EntityType.CREEPER,2);MOB_SCORES.put(org.bukkit.entity.EntityType.ENDERMAN,5);MOB_SCORES.put(org.bukkit.entity.EntityType.BLAZE,4);MOB_SCORES.put(org.bukkit.entity.EntityType.WITCH,3);MOB_SCORES.put(org.bukkit.entity.EntityType.WITHER_SKELETON,8);}
MobDropsHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){current=e;Bukkit.getPluginManager().registerEvents(this,plugin);Bukkit.broadcastMessage(plugin.prefix()+"§c🗡 §eMob-Drops! §7Töte Mobs und sammle ihre Drops. Seltene Mobs = mehr Punkte!");}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);current=null;}
@EventHandler public void onKill(EntityDeathEvent e){if(current==null)return;Player k=e.getEntity().getKiller();if(k==null||!current.isParticipant(k))return;Integer pts=MOB_SCORES.get(e.getEntityType());if(pts!=null){current.addScore(k.getUniqueId(),pts);k.sendActionBar("§c+"+pts+" §7Punkte");}}
}
class TreasureHuntHandler implements IEventHandler {
private final EventEngine plugin;
TreasureHuntHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(plugin.prefix()+"§6💎 §eSchatz finden! §7Ein versteckter Schatz liegt irgendwo in der Arena. Findet ihn zuerst und gewinnt alles darin!");scheduleHints(e);}
@Override public void onEnd(ActiveEvent e){}
private void scheduleHints(ActiveEvent e){new BukkitRunnable(){@Override public void run(){if(e.getState()!=ActiveEvent.State.ENDED)Bukkit.broadcastMessage(plugin.prefix()+"§7💡 §eTipp: §fDer Schatz liegt in der Nähe von Wasser!");}}.runTaskLater(plugin,60*20L);}
}
class EasterEggHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
EasterEggHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){current=e;Bukkit.getPluginManager().registerEvents(this,plugin);Bukkit.broadcastMessage(plugin.prefix()+"§d🥚 §eEier suchen! §7Findet alle versteckten Eier in der Arena. Wer die meisten hat, gewinnt!");}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);current=null;}
}
class SpeedMineHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
SpeedMineHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
current=e;Bukkit.getPluginManager().registerEvents(this,plugin);
for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null)continue;p.addPotionEffect(new PotionEffect(PotionEffectType.HASTE,e.getDefinition().getDurationSeconds()*20,1));}
Bukkit.broadcastMessage(plugin.prefix()+"§7⛏ §eSpeed Mining! §7Baut so schnell wie möglich! Alle erhalten Eile II!");
}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p!=null)p.removePotionEffect(PotionEffectType.HASTE);}current=null;}
@EventHandler public void onBreak(BlockBreakEvent e){if(current==null||!current.isParticipant(e.getPlayer()))return;current.addScore(e.getPlayer().getUniqueId(),1);}
}
class WoodcuttingHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
private static final Map<Material,Integer> WOOD_SCORES=new EnumMap<>(Material.class);
static{WOOD_SCORES.put(Material.OAK_LOG,1);WOOD_SCORES.put(Material.BIRCH_LOG,1);WOOD_SCORES.put(Material.SPRUCE_LOG,1);WOOD_SCORES.put(Material.JUNGLE_LOG,2);WOOD_SCORES.put(Material.ACACIA_LOG,2);WOOD_SCORES.put(Material.DARK_OAK_LOG,3);WOOD_SCORES.put(Material.MANGROVE_LOG,2);WOOD_SCORES.put(Material.CHERRY_LOG,3);}
WoodcuttingHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){current=e;Bukkit.getPluginManager().registerEvents(this,plugin);Bukkit.broadcastMessage(plugin.prefix()+"§2🪓 §eHolzfäll-Comp! §7Fällt so viele Bäume wie möglich. Dunkles Holz = mehr Punkte!");}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);current=null;}
@EventHandler public void onBreak(BlockBreakEvent e){if(current==null||!current.isParticipant(e.getPlayer()))return;Integer pts=WOOD_SCORES.get(e.getBlock().getType());if(pts!=null){current.addScore(e.getPlayer().getUniqueId(),pts);}}
}
class EnchantRaceHandler implements IEventHandler {
private final EventEngine plugin;
EnchantRaceHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(plugin.prefix()+"§5✨ §eVerzauberungsrennen! §7Sammelt Erfahrung und verzaubert euer Item zuerst auf Stufe 30! Wer zuerst fertig ist, gewinnt!");}
@Override public void onEnd(ActiveEvent e){}
}
// ══════════════════════════════════════════════════════════
// BUILD EVENTS — alle 10
// ══════════════════════════════════════════════════════════
class BuildBattleHandler implements IEventHandler {
protected final EventEngine p; private final String theme;
BuildBattleHandler(EventEngine p){this.p=p;this.theme=null;}
BuildBattleHandler(EventEngine p,String theme){this.p=p;this.theme=theme;}
@Override public void onStart(ActiveEvent e){
String t=theme!=null?theme:pickTheme();
Bukkit.broadcastMessage(p.prefix()+"§a🏗 §eBuild Battle! §7Thema: §6§l"+t);
Bukkit.broadcastMessage(p.prefix()+"§7Ihr habt §e"+e.getDefinition().getDurationSeconds()/60+" Minuten §7- Los geht's!");
}
@Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7✦ §eBauzeit vorbei! §7Alle Bauten werden jetzt bewertet.");}
private String pickTheme(){String[]themes={"Burg","Unterwasserwelt","Vulkan","Raumstation","Verzauberte Waldlichtung","Drachen-Nest","Piratenschiff","Zukunftsstadt","Dschungeltempel","Eispalast"};return themes[new Random().nextInt(themes.length)];}
}
class SpeedBuildHandler extends BuildBattleHandler { SpeedBuildHandler(EventEngine p){super(p);} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§e⚡ §eSpeed Build! §7Nur 2 Minuten! Thema kommt gleich..."); super.onStart(e);} }
class ThemeChallengeHandler extends BuildBattleHandler { ThemeChallengeHandler(EventEngine p){super(p);} }
class PixelArtHandler implements IEventHandler { private final EventEngine p; PixelArtHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§d🎨 §ePixel Art Contest! §7Malt ein Pixel-Art-Bild auf dem flachen Boden. Motiv: §6Creeper-Gesicht");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Pinsel runter! Alle Bilder werden bewertet.");} }
class TallestTowerHandler implements IEventHandler, Listener { private final EventEngine plugin; private ActiveEvent current; TallestTowerHandler(EventEngine p){this.plugin=p;} @Override public void onStart(ActiveEvent e){current=e;Bukkit.getPluginManager().registerEvents(this,plugin);Bukkit.broadcastMessage(plugin.prefix()+"§e🗼 §eHöchster Turm! §7Baut so hoch wie möglich! Am Ende wird die Höhe gemessen.");} @Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);if(current==null)return;int best=0;UUID winner=null;for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null)continue;int y=p.getLocation().getBlockY();if(y>best){best=y;winner=u;}}if(winner!=null){e.addScore(winner,100);Player wp=Bukkit.getPlayer(winner);Bukkit.broadcastMessage(plugin.prefix()+"§6✦ §7Höchster Punkt: §e"+(wp!=null?wp.getName():"?")+" §7bei Y=§e"+best);}current=null;} }
class BridgeBuildHandler implements IEventHandler { private final EventEngine p; BridgeBuildHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7🌉 §eBrücke bauen! §7Baut eine Brücke von Punkt A zu Punkt B. Schnellste und schönste Brücke gewinnt!");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Bauzeit vorbei! §eDie Brücken werden jetzt bewertet.");} }
class RedstoneChallengeHandler implements IEventHandler { private final EventEngine p; RedstoneChallengeHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§c⚡ §eRedstone Challenge! §7Aufgabe: §6Baut eine automatisch öffnende Tür mit Druckplatten!");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Zeit abgelaufen! §eSchaltkreise werden geprüft.");} }
class UndergroundBuildHandler implements IEventHandler { private final EventEngine p; UndergroundBuildHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§8⛏ §eUnterirdisch bauen! §7Grabt euch ein und baut eure Anlage NUR unterhalb der Erde!");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Bauten werden begutachtet — die kreativste unterirdische Anlage gewinnt!");} }
class SkyblockStyleHandler implements IEventHandler { private final EventEngine p; SkyblockStyleHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§e☁ §eSkyblock Style! §7Ihr startet auf eurer Insel — baut sie so weit wie möglich aus! Kreativste Insel am Ende gewinnt.");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Inselentwicklung vorbei — Bewertung beginnt!");} }
class BlindBuildHandler implements IEventHandler, Listener { private final EventEngine plugin; private ActiveEvent current; BlindBuildHandler(EventEngine p){this.plugin=p;} @Override public void onStart(ActiveEvent e){current=e;Bukkit.getPluginManager().registerEvents(this,plugin);for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null)continue;p.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS,e.getDefinition().getDurationSeconds()*20,0));}Bukkit.broadcastMessage(plugin.prefix()+"§8👁 §eBlind bauen! §7Ihr könnt kaum etwas sehen — baut das Thema: §6Haus");} @Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p!=null)p.removePotionEffect(PotionEffectType.BLINDNESS);}Bukkit.broadcastMessage(plugin.prefix()+"§7Blindheit weg! §eSchaut euch gegenseitig eure Werke an 😂");current=null;} }
// ══════════════════════════════════════════════════════════
// QUIZ — 3 fehlende
// ══════════════════════════════════════════════════════════
class GeneralKnowledgeQuizHandler extends TriviaHandler {
private static final List<dev.viper.eventengine.events.builtin.TriviaHandler.QuestionEntry> GENERAL_QUESTIONS=List.of(
new dev.viper.eventengine.events.builtin.TriviaHandler.QuestionEntry("Was ist die Hauptstadt von Deutschland?","Berlin",10),
new dev.viper.eventengine.events.builtin.TriviaHandler.QuestionEntry("Wie viele Kontinente gibt es?","7",10),
new dev.viper.eventengine.events.builtin.TriviaHandler.QuestionEntry("Welches ist das größte Land der Welt?","Russland",10),
new dev.viper.eventengine.events.builtin.TriviaHandler.QuestionEntry("Wie viele Planeten hat unser Sonnensystem?","8",15),
new dev.viper.eventengine.events.builtin.TriviaHandler.QuestionEntry("Was ist H2O?","Wasser",5)
);
GeneralKnowledgeQuizHandler(EventEngine p){super(p,GENERAL_QUESTIONS);}
}
class CraftingChallengeHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
private static final String[][] CHALLENGES={
{"Goldener Apfel","Crafting: 8 Goldbarren + 1 Apfel in der Mitte"},
{"Verzauberungstisch","Crafting: Buch, Diamant x2, Obsidian x4"},
{"Enderauge","Crafting: Enderpearl + Blaze Powder"},
{"TNT","Crafting: 5x Sand + 4x Schwarzpulver (Schachbrett)"}
};
CraftingChallengeHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
current=e;Bukkit.getPluginManager().registerEvents(this,plugin);
String[]challenge=CHALLENGES[new Random().nextInt(CHALLENGES.length)];
Bukkit.broadcastMessage(plugin.prefix()+"§6🔨 §eCrafting-Challenge! §7Craftet als Erstes: §e"+challenge[0]);
Bukkit.broadcastMessage(plugin.prefix()+"§7Tipp: §f"+challenge[1]);
}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);current=null;}
}
class MobQuizHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
private final List<String[]> questions=Arrays.asList(
new String[]{"Ich lebe im Nether, fliege und schieße Feuerbälle. Wer bin ich?","Ghast"},
new String[]{"Ich bin grün, habe keine Arme und explodiere. Wer bin ich?","Creeper"},
new String[]{"Ich bin sehr groß, lila und droppe Enderpearls. Wer bin ich?","Enderman"},
new String[]{"Ich schwimme, lebe im Meer und bin der seltenste Boss. Wer bin ich?","Elder Guardian"},
new String[]{"Ich werfe Tränke und trage immer einen Hut. Wer bin ich?","Witch"}
);
private int idx=0; private boolean answered=false;
MobQuizHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
current=e;idx=0;answered=false;Bukkit.getPluginManager().registerEvents(this,plugin);
Bukkit.broadcastMessage(plugin.prefix()+"§2🐾 §eMob-Quiz! §7Erkenne den Mob anhand der Beschreibung!");
nextQuestion(e);
}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);current=null;}
private void nextQuestion(ActiveEvent e){if(idx>=questions.size()){plugin.getEventManager().endEvent("Alle Fragen beantwortet");return;}answered=false;String[]q=questions.get(idx);Bukkit.broadcastMessage("§2❓ §f"+q[0]);}
@EventHandler public void onChat(org.bukkit.event.player.AsyncPlayerChatEvent e){
if(current==null||answered) return;
Player p=e.getPlayer();if(!current.isParticipant(p))return;
String[]q=questions.get(idx);
if(e.getMessage().trim().equalsIgnoreCase(q[1])){answered=true;current.addScore(p.getUniqueId(),10);Bukkit.broadcastMessage("§a✔ §f"+p.getName()+" §7hat es gewusst! §a+10 Punkte");idx++;Bukkit.getScheduler().runTaskLater(plugin,()->nextQuestion(current),40L);}
}
}
// ══════════════════════════════════════════════════════════
// ECONOMY — 4 fehlende
// ══════════════════════════════════════════════════════════
class AuctionHandler implements IEventHandler { private final EventEngine p; AuctionHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§6🔨 §eAuktion! §7Ein Item wird gleich versteigert. Biete im Chat mit einem Betrag! Höchstes Gebot gewinnt!");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Auktion beendet! §eDer Gewinner erhält sein Item.");} }
class MarketRushHandler implements IEventHandler { private final EventEngine p; MarketRushHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§e💹 §eMarkt-Rush! §7Für die nächsten §c"+e.getDefinition().getDurationSeconds()/60+" Minuten §7werden §6Eisenbarren §7zum 3-fachen Preis eingekauft! Sammelt so viel wie möglich!");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Markt-Rush vorbei! §7Der Sonderpreis ist nicht mehr aktiv.");} }
class TradeFrenzyHandler implements IEventHandler { private final EventEngine p; TradeFrenzyHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§a🤝 §eHandels-Frenzy! §7Handelt so viel wie möglich mit anderen Spielern! Jeder abgeschlossene Handel gibt Bonus-Punkte.");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Handels-Zeit vorbei!");} }
class BettingHandler implements IEventHandler { private final EventEngine p; BettingHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§6🎲 §eWetten-Event! §7Setzt auf den Gewinner des nächsten Events! Nutzt die Wetten-Befehle um mitzumachen.");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Wetten sind geschlossen — Gewinner wird ausgezahlt!");} }
// ══════════════════════════════════════════════════════════
// TEAM EVENTS — alle 10
// ══════════════════════════════════════════════════════════
class TeamRelayRaceHandler implements IEventHandler { private final EventEngine p; TeamRelayRaceHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§e🏅 §eStaffellauf! §7Teams treten im Staffelrennen an. Erst wenn Spieler A das Ziel erreicht, startet Spieler B!");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Staffellauf beendet — das schnellste Team gewinnt!");} }
class TeamBuildBattleHandler implements IEventHandler { private final EventEngine p; TeamBuildBattleHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§a👥 §eTeam Build Battle! §7Baut gemeinsam im Team zum Thema: §6Verlassene Burg!");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Bauzeit vorbei — Teams werden bewertet!");} }
class TeamSurvivalHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
TeamSurvivalHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){current=e;Bukkit.getPluginManager().registerEvents(this,plugin);Bukkit.broadcastMessage(plugin.prefix()+"§2👥 §eTeam Survival! §7Überlebt gemeinsam so lange wie möglich gegen Mobs und die Umwelt!");}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);current=null;}
}
class TeamTreasureHuntHandler implements IEventHandler { private final EventEngine p; TeamTreasureHuntHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§6👥 §eTeam Schatzsuche! §7Findet gemeinsam alle versteckten Truhen in der Arena. Das erste Team das alle findet, gewinnt!");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Schatzsuche beendet!");} }
class TeamQuizHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
TeamQuizHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){current=e;Bukkit.getPluginManager().registerEvents(this,plugin);Bukkit.broadcastMessage(plugin.prefix()+"§e👥❓ §eTeam-Quiz! §7Teams beantworten Fragen — schnellste richtige Antwort gewinnt die Runde!");nextQuestion();}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);current=null;}
private final String[][]questions={{"Was ist die härteste Materie?","Diamant"},{"Wie heißt der End-Boss?","Ender Dragon"},{"Was dropped ein Creeper?","Gunpowder"}};
private int qi=0;
private void nextQuestion(){if(qi>=questions.length){plugin.getEventManager().endEvent("Quiz beendet");return;}Bukkit.broadcastMessage("§e❓ §f"+questions[qi][0]);}
@EventHandler public void onChat(org.bukkit.event.player.AsyncPlayerChatEvent e){if(current==null||qi>=questions.length)return;if(!current.isParticipant(e.getPlayer()))return;if(e.getMessage().trim().equalsIgnoreCase(questions[qi][1])){current.addScore(e.getPlayer().getUniqueId(),10);Bukkit.broadcastMessage("§a✔ §f"+e.getPlayer().getName()+"! §a+10");qi++;Bukkit.getScheduler().runTaskLater(plugin,this::nextQuestion,40L);}}
}
class CapturePointsHandler implements IEventHandler {
private final EventEngine plugin; private BukkitRunnable ticker;
CapturePointsHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
Bukkit.broadcastMessage(plugin.prefix()+"§e🚩 §ePunkte-Capture! §7Steht auf den markierten Punkten um Punkte zu sammeln. Mehr Spieler auf einem Punkt = schnellere Einnahme!");
ticker=new BukkitRunnable(){ @Override public void run(){ if(e.getState()==ActiveEvent.State.ENDED){cancel();return;} /* Punkt-Check hier — benötigt vorbereitete Punkte-Positionen in den Settings */ for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null)continue;/* Placeholder: jeder Spieler auf einem Kontrollpunkt bekommt Punkte */} }};
ticker.runTaskTimer(plugin,20L,20L);
}
@Override public void onEnd(ActiveEvent e){ if(ticker!=null)ticker.cancel(); }
}
class ResourceRaceHandler implements IEventHandler { private final EventEngine p; ResourceRaceHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7👥 §eRessourcen-Rennen! §7Sammelt gemeinsam: §e64x Eisen, 32x Gold, 16x Diamant §7— gebt alles in der Truhe ab!");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Ressourcen-Zeit vorbei — wer hat die Liste zuerst erfüllt?");} }
class HideAndSeekHandler implements IEventHandler { private final EventEngine p; HideAndSeekHandler(EventEngine pp){this.p=pp;} @Override public void onStart(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§8👁 §eVerstecken! §7Ein Team versteckt sich — das andere sucht. §c30 Sekunden §7zum Verstecken — lauft!");} @Override public void onEnd(ActiveEvent e){Bukkit.broadcastMessage(p.prefix()+"§7Verstecken beendet! §eDie Sucher haben alle gefunden (oder nicht 😄)");} }
class MurderMysteryHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current; private UUID murderer; private UUID detective;
MurderMysteryHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
current=e;Bukkit.getPluginManager().registerEvents(this,plugin);
List<UUID>parts=new ArrayList<>(e.getParticipants());Collections.shuffle(parts);
if(parts.size()<3){Bukkit.broadcastMessage(plugin.prefix()+"§cMindestens 3 Spieler benötigt!");return;}
murderer=parts.get(0);detective=parts.get(1);
Player mp=Bukkit.getPlayer(murderer);Player dp=Bukkit.getPlayer(detective);
if(mp!=null){mp.sendTitle("§c§lDU BIST DER MÖRDER!","§7Töte alle ohne entdeckt zu werden!",10,60,20);mp.getInventory().setItem(0,new ItemStack(Material.IRON_SWORD));}
if(dp!=null){dp.sendTitle("§9§lDU BIST DER DETEKTIV!","§7Finde den Mörder und bringe ihn zur Strecke!",10,60,20);dp.getInventory().setItem(0,new ItemStack(Material.BOW));dp.getInventory().addItem(new ItemStack(Material.ARROW,1));}
Bukkit.broadcastMessage(plugin.prefix()+"§8🔍 §eMurder Mystery! §7Der Mörder ist unter euch. Detektiv: finde ihn!");
}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);current=null;murderer=null;detective=null;}
@EventHandler public void onDeath(org.bukkit.event.entity.PlayerDeathEvent e){
if(current==null||!current.isParticipant(e.getEntity()))return;
e.setDeathMessage(null);
if(e.getEntity().getUniqueId().equals(murderer)){Bukkit.broadcastMessage(plugin.prefix()+"§a✔ §7Der Mörder wurde gefangen! §9Detektiv und Unschuldige §7gewinnen!");if(detective!=null){current.addScore(detective,100);}plugin.getEventManager().endEvent("Mörder gefangen");}
else if(e.getEntity().getUniqueId().equals(detective)){Bukkit.broadcastMessage(plugin.prefix()+"§c§lDer Detektiv ist tot! §r§7Der Mörder macht weiter...");e.getEntity().setGameMode(GameMode.SPECTATOR);}
else{e.getEntity().setGameMode(GameMode.SPECTATOR);Bukkit.broadcastMessage("§7"+e.getEntity().getName()+" §7wurde ermordet...");}
}
}
class ColorWarHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current; private final Map<UUID,Material> teamColors=new HashMap<>();
ColorWarHandler(EventEngine p){this.plugin=p;}
private static final Material[]COLORS={Material.RED_WOOL,Material.BLUE_WOOL,Material.GREEN_WOOL,Material.YELLOW_WOOL};
@Override public void onStart(ActiveEvent e){
current=e;Bukkit.getPluginManager().registerEvents(this,plugin);
List<UUID>parts=new ArrayList<>(e.getParticipants());
for(int i=0;i<parts.size();i++){Material col=COLORS[i%COLORS.length];teamColors.put(parts.get(i),col);Player p=Bukkit.getPlayer(parts.get(i));if(p!=null){p.getInventory().addItem(new ItemStack(col,64));p.sendMessage(plugin.prefix()+"§7Deine Farbe: §f"+col.name());}}
Bukkit.broadcastMessage(plugin.prefix()+"§e🎨 §eFarben-Krieg! §7Bedeckt so viel Fläche wie möglich mit eurer Teamfarbe!");
}
@Override public void onEnd(ActiveEvent e){
HandlerList.unregisterAll(this);
// Zähle Blöcke pro Farbe in der Region
if(e.getDefinition().hasRegion()){
org.bukkit.World w=e.getDefinition().getRegion().getWorld();
if(w!=null){Map<Material,Integer>counts=new EnumMap<>(Material.class);dev.viper.eventengine.model.EventRegion r=e.getDefinition().getRegion();for(int x=r.getMinX();x<=r.getMaxX();x++)for(int z=r.getMinZ();z<=r.getMaxZ();z++){Material t=w.getBlockAt(x,r.getMinY(),z).getType();if(Arrays.asList(COLORS).contains(t))counts.merge(t,1,Integer::sum);}Bukkit.broadcastMessage(plugin.prefix()+"§e🎨 §7Farben-Ergebnis:");counts.forEach((m,cnt)->Bukkit.broadcastMessage(" §7"+m.name()+": §e"+cnt+" §7Blöcke"));}
}
current=null;teamColors.clear();
}
// Damit ist der Import nötig
private static final Material[] COLORS_REF = COLORS;
}
// ══════════════════════════════════════════════════════════
// FUN EVENTS — 7 fehlende
// ══════════════════════════════════════════════════════════
class TinyPlayersHandler implements IEventHandler {
private final EventEngine p;
TinyPlayersHandler(EventEngine pp){this.p=pp;}
@Override public void onStart(ActiveEvent e){
for(UUID u:e.getParticipants()){Player pl=Bukkit.getPlayer(u);if(pl==null)continue;pl.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS,e.getDefinition().getDurationSeconds()*20,0,false,false));pl.addPotionEffect(new PotionEffect(PotionEffectType.JUMP_BOOST,e.getDefinition().getDurationSeconds()*20,2,false,false));}
Bukkit.broadcastMessage(p.prefix()+"§e🐭 §eMini-Spieler! §7Alle sind jetzt winzig klein!");
}
@Override public void onEnd(ActiveEvent e){for(UUID u:e.getParticipants()){Player pl=Bukkit.getPlayer(u);if(pl!=null){pl.removePotionEffect(PotionEffectType.SLOWNESS);pl.removePotionEffect(PotionEffectType.JUMP_BOOST);}}}
}
class GiantPlayersHandler implements IEventHandler {
private final EventEngine p;
GiantPlayersHandler(EventEngine pp){this.p=pp;}
@Override public void onStart(ActiveEvent e){
for(UUID u:e.getParticipants()){Player pl=Bukkit.getPlayer(u);if(pl==null)continue;pl.addPotionEffect(new PotionEffect(PotionEffectType.SPEED,e.getDefinition().getDurationSeconds()*20,1,false,false));pl.addPotionEffect(new PotionEffect(PotionEffectType.STRENGTH,e.getDefinition().getDurationSeconds()*20,1,false,false));}
Bukkit.broadcastMessage(p.prefix()+"§6🦣 §eRiesen-Spieler! §7Alle sind jetzt riesig! Stärke und Geschwindigkeit erhöht!");
}
@Override public void onEnd(ActiveEvent e){for(UUID u:e.getParticipants()){Player pl=Bukkit.getPlayer(u);if(pl!=null){pl.removePotionEffect(PotionEffectType.SPEED);pl.removePotionEffect(PotionEffectType.STRENGTH);}}}
}
class InvisiblePlayersHandler implements IEventHandler {
private final EventEngine p;
InvisiblePlayersHandler(EventEngine pp){this.p=pp;}
@Override public void onStart(ActiveEvent e){
for(UUID u:e.getParticipants()){Player pl=Bukkit.getPlayer(u);if(pl==null)continue;pl.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY,e.getDefinition().getDurationSeconds()*20,0,false,false));}
Bukkit.broadcastMessage(p.prefix()+"§7👻 §eUnsichtbarkeit! §7Alle Spieler sind unsichtbar!");
}
@Override public void onEnd(ActiveEvent e){for(UUID u:e.getParticipants()){Player pl=Bukkit.getPlayer(u);if(pl!=null)pl.removePotionEffect(PotionEffectType.INVISIBILITY);}}
}
class RandomTeleportHandler implements IEventHandler {
private final EventEngine plugin; private BukkitRunnable tpRunner;
RandomTeleportHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
Bukkit.broadcastMessage(plugin.prefix()+"§d🌀 §eZufalls-TP! §7Alle 5 Sekunden wird jemand teleportiert!");
final Random rng=new Random();
tpRunner=new BukkitRunnable(){@Override public void run(){if(e.getState()==ActiveEvent.State.ENDED){cancel();return;} for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null||rng.nextInt(3)!=0)continue;Location loc=e.getDefinition().hasRegion()?e.getDefinition().getRegion().randomLocation(rng):p.getLocation().add((rng.nextDouble()-0.5)*30,0,(rng.nextDouble()-0.5)*30);if(loc!=null)p.teleport(loc);p.sendActionBar("§d⚡ ZUFALLS-TP!");}}};
tpRunner.runTaskTimer(plugin,20L,100L);
}
@Override public void onEnd(ActiveEvent e){ if(tpRunner!=null)tpRunner.cancel(); }
}
class SwapInventoriesHandler implements IEventHandler {
private final EventEngine p;
SwapInventoriesHandler(EventEngine pp){this.p=pp;}
@Override public void onStart(ActiveEvent e){
List<UUID>parts=new ArrayList<>(e.getParticipants());
if(parts.size()<2){Bukkit.broadcastMessage(p.prefix()+"§cMindestens 2 Spieler benötigt!");return;}
Collections.shuffle(parts);
List<ItemStack[]>inventories=new ArrayList<>();
for(UUID u:parts){Player pl=Bukkit.getPlayer(u);inventories.add(pl!=null?pl.getInventory().getContents().clone():new ItemStack[41]);}
for(int i=0;i<parts.size();i++){Player pl=Bukkit.getPlayer(parts.get(i));if(pl!=null)pl.getInventory().setContents(inventories.get((i+1)%parts.size()));}
Bukkit.broadcastMessage(p.prefix()+"§e🔄 §eInventar-Tausch! §7Alle Inventare wurden zufällig getauscht!");
}
@Override public void onEnd(ActiveEvent e){}
}
class ReverseGravityHandler implements IEventHandler {
private final EventEngine plugin; private BukkitRunnable ticker;
ReverseGravityHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
Bukkit.broadcastMessage(plugin.prefix()+"§9⬆ §eUmgekehrte Schwerkraft! §7Alle werden hochgezogen!");
final Random rng=new Random();
ticker=new BukkitRunnable(){@Override public void run(){if(e.getState()==ActiveEvent.State.ENDED){cancel();return;}for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null)continue;p.setVelocity(p.getVelocity().setY(0.5+rng.nextDouble()*0.5));}}};
ticker.runTaskTimer(plugin,20L,15L);
}
@Override public void onEnd(ActiveEvent e){ if(ticker!=null)ticker.cancel(); }
}
class BouncyBlocksHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
BouncyBlocksHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){current=e;Bukkit.getPluginManager().registerEvents(this,plugin);Bukkit.broadcastMessage(plugin.prefix()+"§a🤸 §eHüpfende Blöcke! §7Bestimmte Blöcke katapultieren euch in die Luft wenn ihr draufsteht!");}
@Override public void onEnd(ActiveEvent e){HandlerList.unregisterAll(this);current=null;}
@EventHandler public void onMove(org.bukkit.event.player.PlayerMoveEvent e){
if(current==null||!current.isParticipant(e.getPlayer()))return;
Material below=e.getPlayer().getLocation().subtract(0,1,0).getBlock().getType();
if(below==Material.SLIME_BLOCK||below==Material.HONEY_BLOCK){e.getPlayer().setVelocity(e.getPlayer().getVelocity().setY(1.5));e.getPlayer().sendActionBar("§a🤸 BOING!");}
}
}

View File

@@ -0,0 +1,153 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.*;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.UUID;
/**
* Mob-Wellen:
* - Alle 30s eine neue Welle mit mehr/stärkeren Mobs
* - Kills = Punkte
* - Nach 10 Wellen oder Ende: Gewinner mit meisten Kills
*/
public class MobWaveHandler implements IEventHandler, Listener {
private static final int MAX_WAVES = 10;
private static final int WAVE_INTERVAL_SEC = 30;
private final EventEngine plugin;
private ActiveEvent currentEvent;
private int currentWave = 0;
private BukkitRunnable waveRunner;
public MobWaveHandler(EventEngine plugin) {
this.plugin = plugin;
}
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
this.currentWave = 0;
Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§c🌊 §eMob-Wellen! §7Überlebe alle " + MAX_WAVES + " Wellen! Kills = Punkte.");
waveRunner = new BukkitRunnable() {
@Override
public void run() {
if (currentEvent == null) { cancel(); return; }
currentWave++;
if (currentWave > MAX_WAVES) {
cancel();
plugin.getEventManager().endEvent("Alle Wellen überstanden!");
return;
}
spawnWave(currentWave);
}
};
waveRunner.runTaskTimer(plugin, 60L, WAVE_INTERVAL_SEC * 20L);
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
if (waveRunner != null) waveRunner.cancel();
this.currentEvent = null;
}
private void spawnWave(int wave) {
broadcast("§c🌊 §eWelle §c" + wave + "§e/" + MAX_WAVES + " §7startet!");
// Spawn-Punkt = erster Teilnehmer oder Welt-Spawn
Location spawnLoc = null;
for (UUID uuid : currentEvent.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p != null) { spawnLoc = p.getLocation(); break; }
}
if (spawnLoc == null) return;
World world = spawnLoc.getWorld();
int mobCount = 3 + (wave * 2);
for (int i = 0; i < mobCount; i++) {
// Zufälliger Offset
double offsetX = (Math.random() - 0.5) * 20;
double offsetZ = (Math.random() - 0.5) * 20;
Location loc = spawnLoc.clone().add(offsetX, 0, offsetZ);
EntityType type = getMobForWave(wave);
try {
Entity mob = world.spawnEntity(loc, type);
// HP skalieren
if (mob instanceof LivingEntity le) {
double baseHp = 20 + (wave * 4);
if (le.getAttribute(Attribute.MAX_HEALTH) != null) {
le.getAttribute(Attribute.MAX_HEALTH).setBaseValue(baseHp);
le.setHealth(baseHp);
}
}
} catch (Exception ignored) {}
}
// Boss ab Welle 5
if (wave == 5) spawnBoss(spawnLoc, "Mini-Boss der Welle 5", EntityType.ELDER_GUARDIAN);
if (wave == 10) spawnBoss(spawnLoc, "§c⚠ ENDGEGNER", EntityType.WITHER_SKELETON);
}
private EntityType getMobForWave(int wave) {
EntityType[] early = {EntityType.ZOMBIE, EntityType.SKELETON, EntityType.SPIDER};
EntityType[] mid = {EntityType.CREEPER, EntityType.WITCH, EntityType.HUSK};
EntityType[] late = {EntityType.VINDICATOR, EntityType.RAVAGER, EntityType.PIGLIN_BRUTE};
if (wave <= 3) return early[(int)(Math.random() * early.length)];
if (wave <= 6) return mid[(int)(Math.random() * mid.length)];
return late[(int)(Math.random() * late.length)];
}
private void spawnBoss(Location loc, String name, EntityType type) {
try {
Entity boss = loc.getWorld().spawnEntity(loc, type);
if (boss instanceof LivingEntity le) {
le.setCustomName("§c§l" + name);
le.setCustomNameVisible(true);
if (le.getAttribute(Attribute.MAX_HEALTH) != null) {
le.getAttribute(Attribute.MAX_HEALTH).setBaseValue(200);
le.setHealth(200);
}
}
broadcast("§c⚠ §l" + name + " §c§ltaucht auf!");
} catch (Exception ignored) {}
}
@EventHandler
public void onMobDeath(EntityDeathEvent e) {
if (currentEvent == null) return;
Player killer = e.getEntity().getKiller();
if (killer == null || !currentEvent.isParticipant(killer)) return;
int points = getMobPoints(e.getEntityType());
currentEvent.addScore(killer.getUniqueId(), points);
killer.sendActionBar("§c+" + points + " §7Punkte (Welle §e" + currentWave + "§7)");
}
private int getMobPoints(EntityType type) {
return switch (type) {
case ZOMBIE, SKELETON, SPIDER -> 1;
case CREEPER, WITCH, HUSK -> 2;
case VINDICATOR, RAVAGER -> 5;
case ELDER_GUARDIAN, WITHER_SKELETON, PIGLIN_BRUTE -> 10;
default -> 1;
};
}
private void broadcast(String msg) { Bukkit.broadcastMessage(msg); }
}

View File

@@ -0,0 +1,136 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.List;
import java.util.Random;
/**
* Zufalls-Effekte: Alle 15s bekommt jeder Spieler einen zufälligen Potion-Effekt
*/
class RandomEffectsHandler implements IEventHandler, Listener {
private static final List<PotionEffectType> EFFECTS = List.of(
PotionEffectType.SPEED, PotionEffectType.SLOWNESS, PotionEffectType.JUMP_BOOST,
PotionEffectType.STRENGTH, PotionEffectType.WEAKNESS, PotionEffectType.BLINDNESS,
PotionEffectType.NIGHT_VISION, PotionEffectType.INVISIBILITY, PotionEffectType.NAUSEA,
PotionEffectType.REGENERATION, PotionEffectType.FIRE_RESISTANCE, PotionEffectType.POISON
);
private final EventEngine plugin;
private ActiveEvent currentEvent;
private BukkitRunnable roller;
private final Random rng = new Random();
RandomEffectsHandler(EventEngine plugin) { this.plugin = plugin; }
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
Bukkit.broadcastMessage(plugin.prefix() + "§5🎲 §eZufalls-Effekte! §7Alle 15s ein neuer zufälliger Trank-Effekt!");
roller = new BukkitRunnable() {
@Override
public void run() {
if (currentEvent == null) { cancel(); return; }
for (Player p : Bukkit.getOnlinePlayers()) {
PotionEffectType type = EFFECTS.get(rng.nextInt(EFFECTS.size()));
int amp = rng.nextInt(3); // 0-2
p.addPotionEffect(new PotionEffect(type, 300, amp, false, true));
p.sendActionBar("§5🎲 Effekt: §f" + formatEffect(type) + " §7(Stufe " + (amp + 1) + ")");
}
}
};
roller.runTaskTimer(plugin, 20L, 300L); // 15s
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
if (roller != null) roller.cancel();
for (Player p : Bukkit.getOnlinePlayers())
EFFECTS.forEach(p::removePotionEffect);
this.currentEvent = null;
}
private String formatEffect(PotionEffectType type) {
return type.getName().replace("_", " ").toLowerCase()
.substring(0, 1).toUpperCase() + type.getName().replace("_", " ").toLowerCase().substring(1);
}
}
/**
* Chaos-Modus: Verschiedene verrückte Effekte gleichzeitig
*/
class ChaosModeHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent currentEvent;
private BukkitRunnable chaos;
private final Random rng = new Random();
ChaosModeHandler(EventEngine plugin) { this.plugin = plugin; }
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
Bukkit.broadcastMessage(plugin.prefix() + "§c§l⚡ CHAOS MODUS! §r§7Alles ist möglich!");
chaos = new BukkitRunnable() {
int tick = 0;
@Override
public void run() {
if (currentEvent == null) { cancel(); return; }
tick++;
for (Player p : Bukkit.getOnlinePlayers()) {
int action = rng.nextInt(6);
switch (action) {
case 0 -> { // Random Teleport in der Nähe
var loc = p.getLocation().add(
(rng.nextDouble()-0.5)*30, 0, (rng.nextDouble()-0.5)*30);
p.teleport(loc);
p.sendActionBar("§c⚡ TELEPORT!");
}
case 1 -> { // Zufällige Geschwindigkeit
p.addPotionEffect(new PotionEffect(PotionEffectType.SPEED,
100, rng.nextInt(5), false, false));
}
case 2 -> { // Feuern
if (rng.nextBoolean()) p.setFireTicks(40);
}
case 3 -> { // In die Luft schleudern
p.setVelocity(p.getVelocity().setY(1.5 + rng.nextDouble()));
p.sendActionBar("§6⬆ YEET!");
}
case 4 -> { // Unsichtbar machen
p.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY,
100, 0, false, false));
}
case 5 -> { /* Nichts */ }
}
}
}
};
chaos.runTaskTimer(plugin, 20L, 40L); // alle 2s
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
if (chaos != null) chaos.cancel();
for (Player p : Bukkit.getOnlinePlayers()) {
p.setFireTicks(0);
p.removePotionEffect(PotionEffectType.SPEED);
p.removePotionEffect(PotionEffectType.INVISIBILITY);
}
this.currentEvent = null;
}
}

View File

@@ -0,0 +1,471 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.*;
import org.bukkit.attribute.Attribute;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
// ═══════════════════════════════════════════════════════════════════
// 1v1 Turnier — genau 2 Spieler, wer zuerst stirbt verliert
// ═══════════════════════════════════════════════════════════════════
class OneVsOneHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent current;
OneVsOneHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) {
current = e;
Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§61v1 §e zwei Spieler, ein Gewinner. Kein Respawn!");
}
@Override public void onEnd(ActiveEvent e) { HandlerList.unregisterAll(this); current = null; }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
@EventHandler public void onDeath(PlayerDeathEvent e) {
if (current == null || !current.isParticipant(e.getEntity())) return;
e.setDeathMessage(null);
Player loser = e.getEntity();
current.removeParticipant(loser);
loser.setGameMode(GameMode.SPECTATOR);
// Übriggebliebener = Gewinner
current.getParticipants().stream().findFirst().ifPresent(uuid -> {
current.addScore(uuid, 100);
Player w = Bukkit.getPlayer(uuid);
if (w != null) { w.sendTitle("§6GEWONNEN!", "§71v1 Champion!", 10,60,20); }
});
plugin.getEventManager().endEvent(loser.getName() + " wurde besiegt");
}
}
// ═══════════════════════════════════════════════════════════════════
// Nur Bogen — Kills mit Bogen = Punkte, Nahkampfschaden = 0
// ═══════════════════════════════════════════════════════════════════
class BowOnlyHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent current;
BowOnlyHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) {
current = e;
Bukkit.getPluginManager().registerEvents(this, plugin);
for (UUID uuid : e.getParticipants()) {
Player p = Bukkit.getPlayer(uuid); if (p == null) continue;
p.getInventory().clear();
p.getInventory().setItem(0, enchant(new ItemStack(Material.BOW), Enchantment.INFINITY, 1));
p.getInventory().setItem(9, new ItemStack(Material.ARROW, 1));
p.setHealth(Math.min(p.getMaxHealth(),20));
}
broadcast("§9🏹 §eNur Bogen! §7Nahkampf macht keinen Schaden.");
}
@Override public void onEnd(ActiveEvent e) { HandlerList.unregisterAll(this); current = null; }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
@EventHandler public void onDamage(EntityDamageByEntityEvent e) {
if (current == null || !(e.getEntity() instanceof Player victim)) return;
if (!current.isParticipant(victim)) return;
if (e.getCause() != org.bukkit.event.entity.EntityDamageEvent.DamageCause.PROJECTILE)
e.setDamage(0);
}
@EventHandler public void onDeath(PlayerDeathEvent e) {
if (current == null || !current.isParticipant(e.getEntity())) return;
e.setDeathMessage(null);
Player killer = e.getEntity().getKiller();
if (killer != null && current.isParticipant(killer)) current.addScore(killer.getUniqueId(),1);
Bukkit.getScheduler().runTaskLater(plugin, () -> { if(e.getEntity().isOnline()){ e.getEntity().spigot().respawn(); resetKit(e.getEntity()); }}, 60L);
}
private void resetKit(Player p) {
p.getInventory().clear();
p.getInventory().setItem(0, enchant(new ItemStack(Material.BOW), Enchantment.INFINITY, 1));
p.getInventory().setItem(9, new ItemStack(Material.ARROW, 1));
p.setHealth(Math.min(p.getMaxHealth(),20));
}
private ItemStack enchant(ItemStack i, Enchantment e, int lvl) {
ItemMeta m = i.getItemMeta(); m.addEnchant(e, lvl, true); i.setItemMeta(m); return i;
}
}
// ═══════════════════════════════════════════════════════════════════
// Nur Schwert — nur Schwertschaden zählt
// ═══════════════════════════════════════════════════════════════════
class SwordOnlyHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent current;
SwordOnlyHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) {
current = e;
Bukkit.getPluginManager().registerEvents(this, plugin);
for (UUID uuid : e.getParticipants()) {
Player p = Bukkit.getPlayer(uuid); if (p == null) continue;
p.getInventory().clear();
p.getInventory().setItem(0, new ItemStack(Material.IRON_SWORD));
p.setHealth(Math.min(p.getMaxHealth(),20));
}
broadcast("§c⚔ §eNur Schwert! §7Bogen-Schaden wird blockiert.");
}
@Override public void onEnd(ActiveEvent e) { HandlerList.unregisterAll(this); current = null; }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
@EventHandler public void onDamage(EntityDamageByEntityEvent e) {
if (current == null || !(e.getEntity() instanceof Player victim)) return;
if (!current.isParticipant(victim)) return;
if (e.getCause() == org.bukkit.event.entity.EntityDamageEvent.DamageCause.PROJECTILE)
e.setDamage(0);
}
@EventHandler public void onDeath(PlayerDeathEvent e) {
if (current == null || !current.isParticipant(e.getEntity())) return;
e.setDeathMessage(null);
Player killer = e.getEntity().getKiller();
if (killer != null && current.isParticipant(killer)) current.addScore(killer.getUniqueId(),1);
Bukkit.getScheduler().runTaskLater(plugin, () -> { if(e.getEntity().isOnline()){ e.getEntity().spigot().respawn(); e.getEntity().getInventory().setItem(0, new ItemStack(Material.IRON_SWORD)); e.getEntity().setHealth(Math.min(e.getEntity().getMaxHealth(),20)); }}, 60L);
}
}
// ═══════════════════════════════════════════════════════════════════
// Faustkampf — kein Item-Schaden
// ═══════════════════════════════════════════════════════════════════
class FistFightHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent current;
FistFightHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) {
current = e;
Bukkit.getPluginManager().registerEvents(this, plugin);
for (UUID uuid : e.getParticipants()) {
Player p = Bukkit.getPlayer(uuid); if (p == null) continue;
p.getInventory().clear();
p.setHealth(Math.min(p.getMaxHealth(),20));
}
broadcast("§e✊ §eFaustkampf! §7Kein Item erlaubt — nur Fäuste!");
}
@Override public void onEnd(ActiveEvent e) { HandlerList.unregisterAll(this); current = null; }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
@EventHandler public void onDamage(EntityDamageByEntityEvent e) {
if (current == null || !(e.getEntity() instanceof Player victim)) return;
if (!current.isParticipant(victim)) return;
// Nur Hand-Schaden (ENTITY_ATTACK mit leerem Item)
if (e.getDamager() instanceof Player attacker) {
if (attacker.getInventory().getItemInMainHand().getType() != Material.AIR
&& attacker.getInventory().getItemInMainHand().getType() != Material.AIR)
e.setDamage(1.5); // normaler Faust-Schaden
}
}
@EventHandler public void onDeath(PlayerDeathEvent e) {
if (current == null || !current.isParticipant(e.getEntity())) return;
e.setDeathMessage(null);
Player killer = e.getEntity().getKiller();
if (killer != null && current.isParticipant(killer)) current.addScore(killer.getUniqueId(),1);
Bukkit.getScheduler().runTaskLater(plugin, () -> { if(e.getEntity().isOnline()){ e.getEntity().spigot().respawn(); e.getEntity().getInventory().clear(); e.getEntity().setHealth(Math.min(e.getEntity().getMaxHealth(),20)); }}, 60L);
}
}
// ═══════════════════════════════════════════════════════════════════
// Kit PvP — alle Spieler kriegen gleiches Kit
// ═══════════════════════════════════════════════════════════════════
class KitPvPHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent current;
KitPvPHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) {
current = e;
Bukkit.getPluginManager().registerEvents(this, plugin);
for (UUID uuid : e.getParticipants()) giveKit(Bukkit.getPlayer(uuid));
broadcast("§6🗡 §eKit PvP! §7Alle erhalten gleiches Kit — nur Skill entscheidet!");
}
@Override public void onEnd(ActiveEvent e) { HandlerList.unregisterAll(this); current = null; }
@Override public void onPlayerJoin(ActiveEvent e, Player p) { giveKit(p); }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
private void giveKit(Player p) {
if (p == null) return;
p.getInventory().clear();
p.getInventory().setItem(0, new ItemStack(Material.IRON_SWORD));
p.getInventory().setItem(1, enchant(new ItemStack(Material.BOW), Enchantment.INFINITY,1));
p.getInventory().setItem(2, new ItemStack(Material.GOLDEN_APPLE, 3));
p.getInventory().setItem(9, new ItemStack(Material.ARROW,1));
p.getEquipment().setHelmet(new ItemStack(Material.IRON_HELMET));
p.getEquipment().setChestplate(new ItemStack(Material.IRON_CHESTPLATE));
p.getEquipment().setLeggings(new ItemStack(Material.IRON_LEGGINGS));
p.getEquipment().setBoots(new ItemStack(Material.IRON_BOOTS));
p.setHealth(Math.min(p.getMaxHealth(),20)); p.setFoodLevel(20);
}
@EventHandler public void onDeath(PlayerDeathEvent e) {
if (current == null || !current.isParticipant(e.getEntity())) return;
e.setDeathMessage(null);
Player killer = e.getEntity().getKiller();
if (killer != null && current.isParticipant(killer)) current.addScore(killer.getUniqueId(),1);
Bukkit.getScheduler().runTaskLater(plugin, () -> { if(e.getEntity().isOnline()){ e.getEntity().spigot().respawn(); giveKit(e.getEntity()); }},60L);
}
private ItemStack enchant(ItemStack i, Enchantment e, int lvl) {
ItemMeta m = i.getItemMeta(); m.addEnchant(e,lvl,true); i.setItemMeta(m); return i;
}
}
// ═══════════════════════════════════════════════════════════════════
// King of the Hill — Zentrum halten = Punkte pro Sekunde
// ═══════════════════════════════════════════════════════════════════
class KingOfTheHillHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent current;
private BukkitRunnable ticker;
KingOfTheHillHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) {
current = e;
Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§6👑 §eKing of the Hill! §7Halte die Mitte und sammle Punkte!");
ticker = new BukkitRunnable() {
@Override public void run() {
if (current == null) { cancel(); return; }
org.bukkit.Location center = current.getDefinition().hasRegion()
? current.getDefinition().getRegion().getCenter() : null;
if (center == null) return;
for (UUID uuid : current.getParticipants()) {
Player p = Bukkit.getPlayer(uuid); if (p == null) continue;
if (p.getLocation().distance(center) <= 5) {
current.addScore(uuid, 1);
p.sendActionBar("§6👑 §eAuf dem Hügel! §7+" + 1 + " Punkt");
}
}
}
};
ticker.runTaskTimer(plugin, 20L, 20L);
}
@Override public void onEnd(ActiveEvent e) { HandlerList.unregisterAll(this); if(ticker!=null)ticker.cancel(); current=null; }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
@EventHandler public void onDeath(PlayerDeathEvent e) {
if (current == null || !current.isParticipant(e.getEntity())) return;
e.setDeathMessage(null);
Bukkit.getScheduler().runTaskLater(plugin, () -> { if(e.getEntity().isOnline()) e.getEntity().spigot().respawn(); }, 60L);
}
}
// ═══════════════════════════════════════════════════════════════════
// Team Battle — 2 Teams, Kills = Teampunkte
// ═══════════════════════════════════════════════════════════════════
class TeamBattleHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent current;
private final Map<UUID, Integer> teamMap = new HashMap<>(); // 0 = rot, 1 = blau
TeamBattleHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) {
current = e; teamMap.clear();
Bukkit.getPluginManager().registerEvents(this, plugin);
List<UUID> participants = new ArrayList<>(e.getParticipants());
for (int i = 0; i < participants.size(); i++) teamMap.put(participants.get(i), i % 2);
broadcast("§cTeam Rot §7vs §9Team Blau §7 Kills gewinnen!");
for (UUID uuid : teamMap.keySet()) {
Player p = Bukkit.getPlayer(uuid); if (p == null) continue;
p.sendMessage(plugin.prefix() + "Dein Team: " + (teamMap.get(uuid)==0 ? "§cRot":"§9Blau"));
}
}
@Override public void onEnd(ActiveEvent e) { HandlerList.unregisterAll(this); current=null; teamMap.clear(); }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
@EventHandler public void onDeath(PlayerDeathEvent e) {
if (current == null || !current.isParticipant(e.getEntity())) return;
e.setDeathMessage(null);
Player killer = e.getEntity().getKiller();
if (killer != null && current.isParticipant(killer)) {
// Team des Killers bekommt Punkt
Integer killerTeam = teamMap.get(killer.getUniqueId());
if (killerTeam != null) {
teamMap.forEach((uuid,team) -> { if(team.equals(killerTeam)) current.addScore(uuid,1); });
}
}
Bukkit.getScheduler().runTaskLater(plugin, () -> { if(e.getEntity().isOnline()){ e.getEntity().spigot().respawn(); e.getEntity().setHealth(Math.min(e.getEntity().getMaxHealth(),20)); }},60L);
}
}
// ═══════════════════════════════════════════════════════════════════
// Elytra PvP — Spieler mit Elytra + Bogen, keine Gravity
// ═══════════════════════════════════════════════════════════════════
class ElytraPvPHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent current;
ElytraPvPHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) {
current = e;
Bukkit.getPluginManager().registerEvents(this, plugin);
for (UUID uuid : e.getParticipants()) {
Player p = Bukkit.getPlayer(uuid); if (p == null) continue;
p.getInventory().clear();
p.getEquipment().setChestplate(new ItemStack(Material.ELYTRA));
ItemStack bow = new ItemStack(Material.BOW);
ItemMeta bm = bow.getItemMeta(); bm.addEnchant(Enchantment.INFINITY,1,true); bow.setItemMeta(bm);
p.getInventory().setItem(0, bow);
p.getInventory().setItem(9, new ItemStack(Material.ARROW,1));
p.getInventory().setItem(1, new ItemStack(Material.FIREWORK_ROCKET, 64));
p.setHealth(Math.min(p.getMaxHealth(),20));
}
broadcast("§b🪂 §eElytra PvP! §7Fliege und schieße deine Gegner ab!");
}
@Override public void onEnd(ActiveEvent e) { HandlerList.unregisterAll(this); current=null; }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
@EventHandler public void onDeath(PlayerDeathEvent e) {
if (current==null||!current.isParticipant(e.getEntity())) return;
e.setDeathMessage(null);
Player killer = e.getEntity().getKiller();
if (killer!=null&&current.isParticipant(killer)) current.addScore(killer.getUniqueId(),1);
Bukkit.getScheduler().runTaskLater(plugin,()->{ if(e.getEntity().isOnline()) e.getEntity().spigot().respawn(); },60L);
}
}
// ═══════════════════════════════════════════════════════════════════
// Arena Survival — PvP + Mobs gleichzeitig, beide geben Punkte
// ═══════════════════════════════════════════════════════════════════
class ArenaSurvivalHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent current;
private BukkitRunnable spawner;
ArenaSurvivalHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) {
current = e;
Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§c⚔🧟 §eArena Survival! §7Besiege Spieler UND Mobs für Punkte!");
spawner = new BukkitRunnable() {
final org.bukkit.entity.EntityType[] mobs = {
org.bukkit.entity.EntityType.ZOMBIE,org.bukkit.entity.EntityType.SKELETON,org.bukkit.entity.EntityType.SPIDER
};
final Random rng = new Random();
@Override public void run() {
if (current==null){cancel();return;}
for (UUID uuid : current.getParticipants()) {
Player p = Bukkit.getPlayer(uuid); if(p==null) continue;
org.bukkit.Location loc = p.getLocation().add((rng.nextDouble()-0.5)*10,0,(rng.nextDouble()-0.5)*10);
p.getWorld().spawnEntity(loc, mobs[rng.nextInt(mobs.length)]);
}
}
};
spawner.runTaskTimer(plugin, 100L, 100L);
}
@Override public void onEnd(ActiveEvent e) { HandlerList.unregisterAll(this); if(spawner!=null)spawner.cancel(); current=null; }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
@EventHandler public void onPlayerDeath(PlayerDeathEvent e) {
if (current==null||!current.isParticipant(e.getEntity())) return;
e.setDeathMessage(null);
Player killer=e.getEntity().getKiller();
if (killer!=null&&current.isParticipant(killer)) current.addScore(killer.getUniqueId(),3);
Bukkit.getScheduler().runTaskLater(plugin,()->{ if(e.getEntity().isOnline()){ e.getEntity().spigot().respawn(); e.getEntity().setHealth(Math.min(e.getEntity().getMaxHealth(),20)); }},60L);
}
@EventHandler public void onMobDeath(org.bukkit.event.entity.EntityDeathEvent e) {
if (current==null) return;
Player killer=e.getEntity().getKiller();
if (killer!=null&&current.isParticipant(killer)) current.addScore(killer.getUniqueId(),1);
}
}
// ═══════════════════════════════════════════════════════════════════
// UHC — kein natürliches Heilen, Goldenäpfel heilen
// ═══════════════════════════════════════════════════════════════════
class UHCHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent current;
private final Set<UUID> alive = new HashSet<>();
UHCHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) {
current = e; alive.clear(); alive.addAll(e.getParticipants());
Bukkit.getPluginManager().registerEvents(this, plugin);
for (UUID uuid : e.getParticipants()) {
Player p = Bukkit.getPlayer(uuid); if(p==null) continue;
p.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 0, 0)); // sicherstellen keine regen
}
broadcast("§c☠ §eUltra Hardcore! §7Keine natürliche Regeneration. Nur Goldäpfel heilen!");
}
@Override public void onEnd(ActiveEvent e) { HandlerList.unregisterAll(this); current=null; alive.clear(); }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
@EventHandler public void onDeath(PlayerDeathEvent e) {
if (current==null||!current.isParticipant(e.getEntity())) return;
e.setDeathMessage(null); alive.remove(e.getEntity().getUniqueId());
if (alive.size()==1) {
UUID w=alive.iterator().next(); current.addScore(w,100);
Player wp=Bukkit.getPlayer(w); String wn=wp!=null?wp.getName():"?";
broadcast("§6✦ §e"+wn+" §6gewinnt Ultra Hardcore!");
plugin.getEventManager().endEvent(wn+" hat gewonnen");
}
}
// Natürliche Regeneration durch hunger blockieren
@EventHandler public void onRegen(org.bukkit.event.entity.EntityRegainHealthEvent e) {
if (current==null||!(e.getEntity() instanceof Player p)) return;
if (!current.isParticipant(p)) return;
if (e.getRegainReason()==org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED||
e.getRegainReason()==org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN)
e.setCancelled(true);
}
}
// ═══════════════════════════════════════════════════════════════════
// Hunger Games — starte ohne Items, sammle Loot, letzter gewinnt
// ═══════════════════════════════════════════════════════════════════
class HungerGamesHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent current;
private final Set<UUID> alive = new HashSet<>();
HungerGamesHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) {
current = e; alive.clear(); alive.addAll(e.getParticipants());
Bukkit.getPluginManager().registerEvents(this, plugin);
for (UUID uuid : e.getParticipants()) {
Player p = Bukkit.getPlayer(uuid); if(p==null) continue;
p.getInventory().clear(); p.setHealth(Math.min(p.getMaxHealth(),20));
}
broadcast("§2🌲 §eHunger Games! §7Keine Ausrüstung — sammle Loot und überlebe!");
}
@Override public void onEnd(ActiveEvent e) { HandlerList.unregisterAll(this); current=null; alive.clear(); }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
@EventHandler public void onDeath(PlayerDeathEvent e) {
if (current==null||!current.isParticipant(e.getEntity())) return;
e.setDeathMessage(null); alive.remove(e.getEntity().getUniqueId());
e.getEntity().setGameMode(GameMode.SPECTATOR);
Player killer=e.getEntity().getKiller();
if (killer!=null&&current.isParticipant(killer)) current.addScore(killer.getUniqueId(),5);
broadcast("§c☠ §f"+e.getEntity().getName()+" §7scheidet aus! §8[§e"+alive.size()+" §7übrig§8]");
if (alive.size()==1) {
UUID w=alive.iterator().next(); current.addScore(w,100);
Player wp=Bukkit.getPlayer(w); String wn=wp!=null?wp.getName():"?";
broadcast("§6✦ §e"+wn+" §6gewinnt die Hunger Games!"); plugin.getEventManager().endEvent(wn+" hat gewonnen");
} else if (alive.isEmpty()) plugin.getEventManager().endEvent("Unentschieden");
}
}
// Capture the Flag, BedWars Lite, SkyWars Lite: Arena-abhängig, Basislogik
class CaptureTheFlagHandler implements IEventHandler {
private final EventEngine plugin;
CaptureTheFlagHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) { Bukkit.broadcastMessage(plugin.prefix()+"§e🚩 Capture the Flag! §7Stehle die Flagge des Gegners und bringe sie zu deiner Basis!"); }
@Override public void onEnd(ActiveEvent e) {}
}
class BedWarsLiteHandler implements IEventHandler {
private final EventEngine plugin;
BedWarsLiteHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) { Bukkit.broadcastMessage(plugin.prefix()+"§e🛏 BedWars Lite! §7Schütze dein Bett und zerstöre das der Gegner!"); }
@Override public void onEnd(ActiveEvent e) {}
}
class SkyWarsLiteHandler implements IEventHandler {
private final EventEngine plugin;
SkyWarsLiteHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) { Bukkit.broadcastMessage(plugin.prefix()+"§e☁ SkyWars Lite! §7Starte auf deiner Insel — sammle Loot und besiege alle anderen!"); }
@Override public void onEnd(ActiveEvent e) {}
}

View File

@@ -0,0 +1,75 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.entity.Snowball;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
/**
* Schneeballschlacht:
* - Jeder Treffer = 1 Punkt
* - Spieler bekommen unendlich Schneebälle
* - Kein normaler Schaden
*/
public class SnowballFightHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent currentEvent;
public SnowballFightHandler(EventEngine plugin) {
this.plugin = plugin;
}
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
Bukkit.getPluginManager().registerEvents(this, plugin);
// Schneebälle verteilen
for (var uuid : event.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p != null) {
p.getInventory().clear();
p.getInventory().setItem(0, new ItemStack(Material.SNOWBALL, 64));
p.setHealth(Math.min(p.getMaxHealth(), 20));
}
}
broadcast("§b❄ §eSchneeballschlacht! §7Treffe Gegner für Punkte!");
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
this.currentEvent = null;
}
@EventHandler
public void onHit(EntityDamageByEntityEvent e) {
if (!(e.getEntity() instanceof Player victim)) return;
if (!(e.getDamager() instanceof Snowball snowball)) return;
if (!(snowball.getShooter() instanceof Player shooter)) return;
if (currentEvent == null) return;
if (!currentEvent.isParticipant(shooter) || !currentEvent.isParticipant(victim)) return;
if (shooter.equals(victim)) return;
e.setDamage(0); // Kein Schaden
currentEvent.addScore(shooter.getUniqueId(), 1);
int score = currentEvent.getScore(shooter.getUniqueId());
shooter.sendActionBar("§b❄ Treffer! §7Punkte: §e" + score);
shooter.playSound(shooter.getLocation(), Sound.BLOCK_GLASS_BREAK, 0.5f, 1.5f);
// Nachladen
if (!shooter.getInventory().contains(Material.SNOWBALL)) {
shooter.getInventory().addItem(new ItemStack(Material.SNOWBALL, 64));
}
}
private void broadcast(String msg) { Bukkit.broadcastMessage(msg); }
}

View File

@@ -0,0 +1,122 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.inventory.ItemStack;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* Spleef:
* - Spieler graben Schnee/Eis unter Gegnern weg
* - Fallen = ausgeschieden
* - Kein normaler Block-Break außerhalb der Spleef-Arena-Materialien
*/
public class SpleefHandler implements IEventHandler, Listener {
private static final Set<Material> SPLEEF_MATERIALS = Set.of(
Material.SNOW_BLOCK, Material.ICE, Material.PACKED_ICE,
Material.BLUE_ICE, Material.WHITE_CONCRETE
);
private final EventEngine plugin;
private ActiveEvent currentEvent;
private final Set<UUID> alive = new HashSet<>();
public SpleefHandler(EventEngine plugin) {
this.plugin = plugin;
}
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
alive.clear();
alive.addAll(event.getParticipants());
Bukkit.getPluginManager().registerEvents(this, plugin);
// Jedem Spieler eine Schneeschaufel geben
for (UUID uuid : event.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p != null) {
p.getInventory().addItem(new ItemStack(Material.DIAMOND_SHOVEL));
}
}
broadcast("§a⛏ §eSpleef! §7Grabe Schnee unter deinen Gegnern weg. §7Wer fällt, verliert!");
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
this.currentEvent = null;
alive.clear();
}
@EventHandler
public void onBlockBreak(BlockBreakEvent e) {
Player p = e.getPlayer();
if (currentEvent == null || !currentEvent.isParticipant(p)) return;
// Nur Spleef-Materialien erlaubt
if (!SPLEEF_MATERIALS.contains(e.getBlock().getType())) {
e.setCancelled(true);
return;
}
e.setDropItems(false); // Kein Item-Drop
p.playSound(p.getLocation(), Sound.BLOCK_SNOW_BREAK, 1f, 1f);
}
@EventHandler
public void onDamage(EntityDamageEvent e) {
if (!(e.getEntity() instanceof Player p)) return;
if (currentEvent == null || !currentEvent.isParticipant(p)) return;
if (e.getCause() == EntityDamageEvent.DamageCause.FALL ||
e.getCause() == EntityDamageEvent.DamageCause.VOID) {
e.setCancelled(true);
eliminate(p);
} else {
e.setDamage(0); // Kein PvP-Schaden
}
}
@EventHandler
public void onDeath(PlayerDeathEvent e) {
if (currentEvent == null || !currentEvent.isParticipant(e.getEntity())) return;
e.setDeathMessage(null);
}
private void eliminate(Player p) {
if (!alive.contains(p.getUniqueId())) return;
alive.remove(p.getUniqueId());
currentEvent.removeParticipant(p);
p.setGameMode(org.bukkit.GameMode.SPECTATOR);
broadcast("§c⬇ §f" + p.getName() + " §7ist gefallen! §8[§e" + alive.size() + " §7übrig§8]");
checkWinner();
}
private void checkWinner() {
if (alive.size() == 1) {
UUID winnerId = alive.iterator().next();
Player winner = Bukkit.getPlayer(winnerId);
String name = winner != null ? winner.getName() : "?";
currentEvent.addScore(winnerId, 100);
broadcast("§6✦ §e" + name + " §6gewinnt Spleef!");
if (winner != null) winner.playSound(winner.getLocation(), Sound.UI_TOAST_CHALLENGE_COMPLETE, 1f, 1f);
plugin.getEventManager().endEvent(name + " hat gewonnen");
} else if (alive.isEmpty()) {
plugin.getEventManager().endEvent("Unentschieden");
}
}
private void broadcast(String msg) { Bukkit.broadcastMessage(msg); }
}

View File

@@ -0,0 +1,123 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* Sumo:
* - Kein normaler Schaden (nur Knockback)
* - Fall in Void/Wasser = ausgeschieden
* - Spieler erhalten Speed I + kein Schaden-Handling außer Knockback
*/
public class SumoHandler implements IEventHandler, Listener {
private final EventEngine plugin;
private ActiveEvent currentEvent;
private final Set<UUID> alive = new HashSet<>();
private BukkitRunnable voidChecker;
public SumoHandler(EventEngine plugin) {
this.plugin = plugin;
}
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
alive.clear();
alive.addAll(event.getParticipants());
Bukkit.getPluginManager().registerEvents(this, plugin);
// Teilnehmer vorbereiten
for (UUID uuid : event.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p == null) continue;
p.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 0, false, false));
p.setHealth(Math.min(p.getMaxHealth(), 20));
}
// Void-Check alle 5 Ticks
voidChecker = new BukkitRunnable() {
@Override
public void run() {
if (currentEvent == null) { cancel(); return; }
for (UUID uuid : new HashSet<>(alive)) {
Player p = Bukkit.getPlayer(uuid);
if (p != null && p.getLocation().getY() < 0) {
eliminate(p);
}
}
}
};
voidChecker.runTaskTimer(plugin, 5L, 5L);
broadcast("§b🌊 §eSumo! §7Stoße deine Gegner in den Void! §7Kein Schaden — nur Knockback.");
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
if (voidChecker != null) voidChecker.cancel();
for (UUID uuid : event.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p != null) p.removePotionEffect(PotionEffectType.SPEED);
}
this.currentEvent = null;
alive.clear();
}
// Schaden blockieren (außer Knockback bleibt)
@EventHandler
public void onDamage(EntityDamageEvent e) {
if (!(e.getEntity() instanceof Player p)) return;
if (currentEvent == null || !currentEvent.isParticipant(p)) return;
if (e.getCause() == EntityDamageEvent.DamageCause.VOID) {
e.setCancelled(true);
eliminate(p);
return;
}
// Kein HP-Verlust, aber Knockback bleibt
e.setDamage(0);
}
@EventHandler
public void onDeath(PlayerDeathEvent e) {
if (currentEvent == null || !currentEvent.isParticipant(e.getEntity())) return;
e.setDeathMessage(null);
e.getEntity().spigot().respawn();
}
private void eliminate(Player p) {
if (!alive.contains(p.getUniqueId())) return;
alive.remove(p.getUniqueId());
currentEvent.removeParticipant(p);
p.setGameMode(org.bukkit.GameMode.SPECTATOR);
broadcast("§c💧 §f" + p.getName() + " §7ist ins Wasser gefallen! §8[§e" + alive.size() + " §7übrig§8]");
if (alive.size() == 1) {
UUID winnerId = alive.iterator().next();
Player winner = Bukkit.getPlayer(winnerId);
String name = winner != null ? winner.getName() : "?";
currentEvent.addScore(winnerId, 100);
broadcast("§6✦ §e" + name + " §6gewinnt das Sumo-Event!");
if (winner != null) winner.playSound(winner.getLocation(), Sound.UI_TOAST_CHALLENGE_COMPLETE, 1f, 1f);
plugin.getEventManager().endEvent(name + " hat gewonnen");
}
}
private void broadcast(String msg) { Bukkit.broadcastMessage(msg); }
}

View File

@@ -0,0 +1,308 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.*;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
// ═══════════════════════════════════════════════════════════════════
// Zombie Belagerung
// ═══════════════════════════════════════════════════════════════════
class ZombieSiegeHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
private BukkitRunnable spawner; private int wave = 0;
ZombieSiegeHandler(EventEngine p) { this.plugin = p; }
@Override public void onStart(ActiveEvent e) {
current = e;
Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§2🧟 §eZombie-Belagerung! §7Halte die Stellung — Zombies kommen in Wellen!");
spawner = new BukkitRunnable() {
@Override public void run() {
if (current==null){cancel();return;}
wave++;
broadcast("§2🧟 §eZombie-Welle §c"+wave+"§e kommt!");
Location loc = getSpawnLoc();
if (loc==null) return;
int count = 5 + wave * 3;
Random rng = new Random();
for (int i=0;i<count;i++) {
Location sl = loc.clone().add((rng.nextDouble()-0.5)*20,0,(rng.nextDouble()-0.5)*20);
Zombie z = (Zombie) loc.getWorld().spawnEntity(sl, EntityType.ZOMBIE);
if (wave > 3) z.addPotionEffect(new PotionEffect(PotionEffectType.SPEED,99999,1));
}
}
};
spawner.runTaskTimer(plugin, 20L, 30*20L);
}
@Override public void onEnd(ActiveEvent e) { HandlerList.unregisterAll(this); if(spawner!=null)spawner.cancel(); current=null; }
@EventHandler public void onKill(EntityDeathEvent e) {
if (current==null||!(e.getEntity() instanceof Zombie)) return;
Player killer=e.getEntity().getKiller();
if (killer!=null&&current.isParticipant(killer)) { current.addScore(killer.getUniqueId(),1); killer.sendActionBar("§2+1 §7Zombie Kill"); }
}
private Location getSpawnLoc() { for (UUID u:current.getParticipants()){Player p=Bukkit.getPlayer(u);if(p!=null)return p.getLocation();} return null; }
private void broadcast(String m){Bukkit.broadcastMessage(m);}
}
// ═══════════════════════════════════════════════════════════════════
// Wither Sturm
// ═══════════════════════════════════════════════════════════════════
class WitherStormHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current; private Wither wither;
WitherStormHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e) {
current=e; Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§8☠ §lWITHER STURM! §r§7Besiegt den Wither gemeinsam! Wer den letzten Schlag landet gewinnt den Jackpot!");
Location loc=getCenter(); if(loc==null)return;
wither=(Wither)loc.getWorld().spawnEntity(loc.add(0,5,0), EntityType.WITHER);
wither.setCustomName("§8§l☠ DER WITHER ☠");
wither.setCustomNameVisible(true);
}
@Override public void onEnd(ActiveEvent e){ HandlerList.unregisterAll(this); if(wither!=null&&!wither.isDead())wither.remove(); current=null; }
@EventHandler public void onWitherDeath(EntityDeathEvent e){
if(current==null||!(e.getEntity() instanceof Wither)) return;
Player killer=e.getEntity().getKiller();
if(killer!=null&&current.isParticipant(killer)){
current.addScore(killer.getUniqueId(),100);
broadcast("§6✦ §f"+killer.getName()+" §6hat den Wither besiegt und bekommt 100 Punkte!");
}
plugin.getEventManager().endEvent("Wither besiegt");
}
private Location getCenter(){if(current.getDefinition().hasRegion())return current.getDefinition().getRegion().getCenter(); for(UUID u:current.getParticipants()){Player p=Bukkit.getPlayer(u);if(p!=null)return p.getLocation();}return null;}
private void broadcast(String m){Bukkit.broadcastMessage(m);}
}
// ═══════════════════════════════════════════════════════════════════
// Drachen Event
// ═══════════════════════════════════════════════════════════════════
class DragonFightHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
DragonFightHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
current=e; Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§5🐉 §eDrachen-Event! §7Besiegt den Ender-Dragon! Wer den Killing Blow landet gewinnt den Jackpot!");
}
@Override public void onEnd(ActiveEvent e){ HandlerList.unregisterAll(this); current=null; }
@EventHandler public void onDragonDeath(EntityDeathEvent e){
if(current==null||!(e.getEntity() instanceof EnderDragon)) return;
Player killer=e.getEntity().getKiller();
if(killer!=null&&current.isParticipant(killer)){
current.addScore(killer.getUniqueId(),200);
broadcast("§6✦ §f"+killer.getName()+" §6hat den Drachen getötet! §e+200 Punkte!");
}
broadcast("§5🐉 §eDer Drache ist gefallen! §7Alle Teilnehmer erhalten eine Belohnung!");
plugin.getEventManager().endEvent("Drache besiegt");
}
private void broadcast(String m){Bukkit.broadcastMessage(m);}
}
// ═══════════════════════════════════════════════════════════════════
// Hardcore Runde — kein Respawn, wer lebt gewinnt
// ═══════════════════════════════════════════════════════════════════
class HardcoreRoundHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current; private final Set<UUID> alive=new HashSet<>();
HardcoreRoundHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
current=e; alive.clear(); alive.addAll(e.getParticipants());
Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§c💀 §eHardcore-Runde! §7Kein Respawn — stirb einmal und du bist raus!");
}
@Override public void onEnd(ActiveEvent e){ HandlerList.unregisterAll(this); current=null; alive.clear(); }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
@EventHandler public void onDeath(PlayerDeathEvent e){
if(current==null||!current.isParticipant(e.getEntity())) return;
e.setDeathMessage(null); alive.remove(e.getEntity().getUniqueId());
e.getEntity().setGameMode(GameMode.SPECTATOR);
broadcast("§c💀 §f"+e.getEntity().getName()+" §7ist ausgeschieden! §8[§e"+alive.size()+" §7übrig§8]");
if(alive.size()==1){ UUID w=alive.iterator().next(); current.addScore(w,100); Player wp=Bukkit.getPlayer(w); broadcast("§6✦ "+(wp!=null?wp.getName():"?")+" §6gewinnt die Hardcore-Runde!"); plugin.getEventManager().endEvent("Gewinner ermittelt"); }
else if(alive.isEmpty()) plugin.getEventManager().endEvent("Unentschieden");
}
}
// ═══════════════════════════════════════════════════════════════════
// Insel Überleben — punkte pro Sekunde
// ═══════════════════════════════════════════════════════════════════
class IslandSurvivalHandler implements IEventHandler {
private final EventEngine plugin; private BukkitRunnable ticker;
IslandSurvivalHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
Bukkit.broadcastMessage(plugin.prefix()+"§2🏝 §eInsel-Überleben! §7Überlebt und sammelt Punkte pro Sekunde!");
ticker=new BukkitRunnable(){ @Override public void run(){ if(e.getState()==dev.viper.eventengine.model.ActiveEvent.State.ENDED){cancel();return;} for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p!=null)e.addScore(u,1);} }};
ticker.runTaskTimer(plugin,20L,20L);
}
@Override public void onEnd(ActiveEvent e){ if(ticker!=null)ticker.cancel(); }
}
// ═══════════════════════════════════════════════════════════════════
// Nether Sprint — Punkte für Nether-Items
// ═══════════════════════════════════════════════════════════════════
class NetherRunHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
private static final Map<Material,Integer> NETHER_SCORES=new EnumMap<>(Material.class);
static { NETHER_SCORES.put(Material.BLAZE_ROD,5); NETHER_SCORES.put(Material.NETHER_QUARTZ_ORE,2); NETHER_SCORES.put(Material.MAGMA_CREAM,3); NETHER_SCORES.put(Material.GHAST_TEAR,8); NETHER_SCORES.put(Material.WITHER_SKELETON_SKULL,20); NETHER_SCORES.put(Material.ANCIENT_DEBRIS,15); }
NetherRunHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){ current=e; Bukkit.getPluginManager().registerEvents(this,plugin); broadcast("§c🔥 §eNether-Sprint! §7Sammle Nether-Items für Punkte! Wer hat am Ende das meiste?"); }
@Override public void onEnd(ActiveEvent e){
HandlerList.unregisterAll(this);
// Inventar-Scan beim Ende
for(UUID uuid:e.getParticipants()){ Player p=Bukkit.getPlayer(uuid); if(p==null)continue; for(ItemStack item:p.getInventory().getContents()){ if(item==null)continue; Integer pts=NETHER_SCORES.get(item.getType()); if(pts!=null) e.addScore(uuid,pts*item.getAmount()); } }
current=null;
}
private void broadcast(String m){Bukkit.broadcastMessage(m);}
}
// ═══════════════════════════════════════════════════════════════════
// Ausdauer Test — Schaden über Zeit, wer überlebt länger = mehr Punkte
// ═══════════════════════════════════════════════════════════════════
class EnduranceHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current; private BukkitRunnable ticker;
EnduranceHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
current=e; Bukkit.getPluginManager().registerEvents(this,plugin);
broadcast("§9⏱ §eAusdauer-Test! §7Jede Sekunde wachsen die Gefahren — wer hält am längsten durch?");
ticker=new BukkitRunnable(){
int tick=0;
@Override public void run(){
if(current==null){cancel();return;} tick++;
for(UUID uuid:current.getParticipants()){
Player p=Bukkit.getPlayer(uuid); if(p==null) continue;
current.addScore(uuid,1);
// Nach 30s: Gift; nach 60s: Hunger; nach 90s: Langsamkeit
if(tick>=30) p.addPotionEffect(new PotionEffect(PotionEffectType.POISON,40,0,false,false));
if(tick>=60) p.setFoodLevel(Math.max(0,p.getFoodLevel()-1));
if(tick>=90) p.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS,40,1,false,false));
}
}
};
ticker.runTaskTimer(plugin,20L,20L);
}
@Override public void onEnd(ActiveEvent e){ HandlerList.unregisterAll(this); if(ticker!=null)ticker.cancel(); current=null; }
private void broadcast(String m) { Bukkit.broadcastMessage(m); }
@EventHandler public void onDeath(PlayerDeathEvent e){ if(current!=null&&current.isParticipant(e.getEntity())){ e.setDeathMessage(null); current.removeParticipant(e.getEntity()); e.getEntity().setGameMode(GameMode.SPECTATOR); } }
}
// ═══════════════════════════════════════════════════════════════════
// Raid Plus — verstärkte Raid-Wellen
// ═══════════════════════════════════════════════════════════════════
class RaidsPlusHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current; private BukkitRunnable spawner;
private static final EntityType[] RAID_MOBS={EntityType.PILLAGER,EntityType.VINDICATOR,EntityType.WITCH,EntityType.EVOKER,EntityType.RAVAGER};
RaidsPlusHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
current=e; Bukkit.getPluginManager().registerEvents(this,plugin);
broadcast("§4🏹 §eRaid+! §7Verstärkte Illager-Angriffe — besiegt alle Wellen!");
spawner=new BukkitRunnable(){
int wave=0; final Random rng=new Random();
@Override public void run(){
if(current==null){cancel();return;} wave++;
broadcast("§4🏹 §eRaid-Welle §c"+wave+"§e startet!");
Location loc=getCenter(); if(loc==null)return;
int count=4+wave*2;
for(int i=0;i<count;i++){
EntityType type=RAID_MOBS[rng.nextInt(Math.min(wave+1,RAID_MOBS.length))];
Location sl=loc.clone().add((rng.nextDouble()-0.5)*20,0,(rng.nextDouble()-0.5)*20);
try{ LivingEntity mob=(LivingEntity)loc.getWorld().spawnEntity(sl,type); if(mob.getAttribute(Attribute.MAX_HEALTH)!=null){double hp=20+wave*5;mob.getAttribute(Attribute.MAX_HEALTH).setBaseValue(hp);mob.setHealth(hp);} }catch(Exception ignored){}
}
}
};
spawner.runTaskTimer(plugin,60L,25*20L);
}
@Override public void onEnd(ActiveEvent e){ HandlerList.unregisterAll(this); if(spawner!=null)spawner.cancel(); current=null; }
@EventHandler public void onKill(EntityDeathEvent e){ if(current==null)return; Player k=e.getEntity().getKiller(); if(k!=null&&current.isParticipant(k)){ int pts=e.getEntity().getType()==EntityType.RAVAGER?10:e.getEntity().getType()==EntityType.EVOKER?8:3; current.addScore(k.getUniqueId(),pts); k.sendActionBar("§4+"+pts+" §7Raid-Kill"); } }
private Location getCenter(){ if(current.getDefinition().hasRegion())return current.getDefinition().getRegion().getCenter(); for(UUID u:current.getParticipants()){Player p=Bukkit.getPlayer(u);if(p!=null)return p.getLocation();} return null; }
private void broadcast(String m){Bukkit.broadcastMessage(m);}
}
// ═══════════════════════════════════════════════════════════════════
// Monster Jagd — töte bestimmte Mobs für Punkte
// ═══════════════════════════════════════════════════════════════════
class MonsterHuntHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current;
private static final Map<EntityType,Integer> BOUNTY=new EnumMap<>(EntityType.class);
static{ BOUNTY.put(EntityType.ZOMBIE,1);BOUNTY.put(EntityType.SKELETON,1);BOUNTY.put(EntityType.CREEPER,2);BOUNTY.put(EntityType.ENDERMAN,3);BOUNTY.put(EntityType.WITCH,4);BOUNTY.put(EntityType.ELDER_GUARDIAN,10);BOUNTY.put(EntityType.WITHER_SKELETON,6);BOUNTY.put(EntityType.BLAZE,5); }
MonsterHuntHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){ current=e; Bukkit.getPluginManager().registerEvents(this,plugin); broadcast("§c🎯 §eMonster-Jagd! §7Töte Mobs für Punkte. Rare Mobs = mehr Punkte!"); }
@Override public void onEnd(ActiveEvent e){ HandlerList.unregisterAll(this); current=null; }
@EventHandler public void onKill(EntityDeathEvent e){ if(current==null) return; Player k=e.getEntity().getKiller(); if(k==null||!current.isParticipant(k))return; Integer pts=BOUNTY.get(e.getEntityType()); if(pts!=null){ current.addScore(k.getUniqueId(),pts); k.sendActionBar("§c+"+pts+" §7["+e.getEntityType().name()+"]"); } }
private void broadcast(String m){Bukkit.broadcastMessage(m);}
}
// ═══════════════════════════════════════════════════════════════════
// Schwerkraft Chaos — Spieler werden hochgeworfen
// ═══════════════════════════════════════════════════════════════════
class GravityShiftHandler implements IEventHandler {
private final EventEngine plugin; private BukkitRunnable ticker;
GravityShiftHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
Bukkit.broadcastMessage(plugin.prefix()+"§b🌀 §eSchwerkraft-Chaos! §7Die Schwerkraft verhält sich zufällig!");
final Random rng=new Random();
ticker=new BukkitRunnable(){ @Override public void run(){ if(e.getState()==dev.viper.eventengine.model.ActiveEvent.State.ENDED){cancel();return;} for(UUID u:e.getParticipants()){Player p=Bukkit.getPlayer(u);if(p==null)continue; if(rng.nextInt(5)==0) p.setVelocity(p.getVelocity().setY(1.5+rng.nextDouble()*2)); e.addScore(u,1); } }};
ticker.runTaskTimer(plugin,20L,20L);
}
@Override public void onEnd(ActiveEvent e){ if(ticker!=null)ticker.cancel(); }
}
// ═══════════════════════════════════════════════════════════════════
// Random Spawn — Spieler werden zufällig in Arena gespawnt, kein Respawn
// ═══════════════════════════════════════════════════════════════════
class RandomSpawnHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current; private final Set<UUID> alive=new HashSet<>();
RandomSpawnHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
current=e; alive.clear(); alive.addAll(e.getParticipants());
Bukkit.getPluginManager().registerEvents(this,plugin);
final Random rng=new Random();
for(UUID uuid:e.getParticipants()){ Player p=Bukkit.getPlayer(uuid); if(p==null)continue; Location loc=e.getDefinition().hasRegion()?e.getDefinition().getRegion().randomLocation(rng):p.getWorld().getSpawnLocation(); p.teleport(loc); }
broadcast("§d🎲 §eRandom Spawn! §7Alle wurden zufällig verteilt — kein Respawn. Letzter gewinnt!");
}
@Override public void onEnd(ActiveEvent e){ HandlerList.unregisterAll(this); current=null; alive.clear(); }
@EventHandler public void onDeath(PlayerDeathEvent e){ if(current==null||!current.isParticipant(e.getEntity()))return; e.setDeathMessage(null); alive.remove(e.getEntity().getUniqueId()); e.getEntity().setGameMode(GameMode.SPECTATOR); broadcast("§c☠ §f"+e.getEntity().getName()+" §7scheidet aus! §8[§e"+alive.size()+" §7übrig§8]"); if(alive.size()==1){UUID w=alive.iterator().next();current.addScore(w,100);Player wp=Bukkit.getPlayer(w);broadcast("§6✦ "+(wp!=null?wp.getName():"?")+" §6gewinnt!");plugin.getEventManager().endEvent("Gewinner ermittelt");}else if(alive.isEmpty())plugin.getEventManager().endEvent("Unentschieden"); }
private void broadcast(String m){Bukkit.broadcastMessage(m);}
}
// ═══════════════════════════════════════════════════════════════════
// Manhunt — 1 Gejagter, alle anderen Jäger
// ═══════════════════════════════════════════════════════════════════
class ManhuntHandler implements IEventHandler, Listener {
private final EventEngine plugin; private ActiveEvent current; private UUID target;
ManhuntHandler(EventEngine p){this.plugin=p;}
@Override public void onStart(ActiveEvent e){
current=e; Bukkit.getPluginManager().registerEvents(this,plugin);
List<UUID> parts=new ArrayList<>(e.getParticipants());
if(parts.isEmpty())return;
target=parts.get(new Random().nextInt(parts.size()));
Player tp=Bukkit.getPlayer(target);
broadcast("§c🎯 §eManhunt! §fGejagter: §c"+(tp!=null?tp.getName():"?")+" §7— alle anderen sind Jäger!");
if(tp!=null){ tp.sendTitle("§cDU BIST GEJAGT!","§7Überlebe so lange wie möglich!",10,60,20); tp.addPotionEffect(new PotionEffect(PotionEffectType.SPEED,99999,0,false,false)); }
}
@Override public void onEnd(ActiveEvent e){ HandlerList.unregisterAll(this); current=null; target=null; }
@EventHandler public void onDeath(PlayerDeathEvent e){
if(current==null||!current.isParticipant(e.getEntity()))return;
e.setDeathMessage(null);
if(e.getEntity().getUniqueId().equals(target)){
broadcast("§6✦ §7Die Jäger haben gewonnen! §c"+(e.getEntity().getName())+" §7wurde gefangen!");
for(UUID u:current.getParticipants()) if(!u.equals(target)) current.addScore(u,50);
plugin.getEventManager().endEvent("Gejagter gefangen");
} else {
broadcast("§7Ein Jäger ist gestorben. §c"+e.getEntity().getName()+" §7scheidet aus.");
e.getEntity().setGameMode(GameMode.SPECTATOR);
}
}
// Kompatibilitätsmethode
private void addPotion(Player p, PotionEffect effect){ p.addPotionEffect(effect); }
private void broadcast(String m){Bukkit.broadcastMessage(m);}
}

View File

@@ -0,0 +1,124 @@
package dev.viper.eventengine.events.builtin;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
/**
* Minecraft-Trivia:
* - Frage wird im Chat gestellt
* - Erster der richtig antwortet bekommt Punkte
* - 10 Fragen, danach endet das Event
*/
public class TriviaHandler implements IEventHandler, Listener {
/** Öffentlich für Subklassen (GeneralKnowledgeQuizHandler etc.) */
public static final class QuestionEntry {
public final String question, answer; public final int points;
public QuestionEntry(String q, String a, int p){this.question=q;this.answer=a;this.points=p;}
}
private static final List<QuestionEntry> QUESTIONS = List.of(
new QuestionEntry("Wie viele Blöcke hoch ist eine Karotte wenn sie voll gewachsen ist?", "1", 10),
new QuestionEntry("Was braucht man um ein Bett zu craften? (Material)", "Wolle", 10),
new QuestionEntry("Wie heißt der End-Boss?", "Ender Dragon", 15),
new QuestionEntry("Was dropped ein Blaze?", "Blaze Rod", 10),
new QuestionEntry("Aus wie vielen Blöcken besteht ein Chunk?", "16", 15),
new QuestionEntry("Welches Erz ist das seltenste in Minecraft?", "Netherit", 20),
new QuestionEntry("Was ist die maximale Verzauberungsstufe in Vanilla?", "30", 10),
new QuestionEntry("Wie nennt man den grünen feindlichen Mob ohne Arme?", "Creeper", 5),
new QuestionEntry("Welches Tier liefert Wolle?", "Schaf", 5),
new QuestionEntry("Was dropped ein Ender Dragon?", "Dragon Egg", 20),
new QuestionEntry("Wie heißt der Minecraft-Entwickler?", "Notch", 10),
new QuestionEntry("Aus welchem Material werden Schienen gecraftet?", "Eisen", 10),
new QuestionEntry("Was ist die tiefste Y-Koordinate in 1.18+?", "-64", 15),
new QuestionEntry("Wie viele Lebensherzen hat ein Spieler maximal (vanilla)?", "10", 10),
new QuestionEntry("Was braucht man um einen Kompass zu craften?", "Redstone", 15)
);
private final EventEngine plugin;
private ActiveEvent currentEvent;
private QuestionEntry currentQuestion;
private boolean answered;
private int questionIndex = 0;
private final List<QuestionEntry> shuffled = new ArrayList<>();
private BukkitRunnable questionRunner;
public TriviaHandler(EventEngine plugin) { this.plugin = plugin; this.externalQuestions = null; }
private final List<QuestionEntry> externalQuestions;
public TriviaHandler(EventEngine plugin, List<QuestionEntry> questions) { this.plugin = plugin; this.externalQuestions = questions; }
@Override
public void onStart(ActiveEvent event) {
this.currentEvent = event;
this.questionIndex = 0;
this.answered = false;
shuffled.clear();
shuffled.addAll(externalQuestions != null ? externalQuestions : QUESTIONS);
Collections.shuffle(shuffled);
Bukkit.getPluginManager().registerEvents(this, plugin);
broadcast("§e❓ §eMinecraft-Quiz! §7Beantworte Fragen im Chat!");
questionRunner = new BukkitRunnable() {
@Override
public void run() {
if (currentEvent == null) { cancel(); return; }
if (questionIndex >= Math.min(10, shuffled.size())) {
cancel();
plugin.getEventManager().endEvent("Alle Fragen beantwortet");
return;
}
if (!answered && currentQuestion != null) {
broadcast("§c⏰ §7Zu langsam! Die Antwort war: §e" + currentQuestion.answer);
}
nextQuestion();
}
};
questionRunner.runTaskTimer(plugin, 60L, 200L); // 10s pro Frage
}
@Override
public void onEnd(ActiveEvent event) {
HandlerList.unregisterAll(this);
if (questionRunner != null) questionRunner.cancel();
this.currentEvent = null;
}
private void nextQuestion() {
if (questionIndex >= shuffled.size()) return;
currentQuestion = shuffled.get(questionIndex++);
answered = false;
broadcast("§8§m══════════════════════════════");
broadcast("§e❓ Frage " + questionIndex + ": §f" + currentQuestion.question);
broadcast("§7Punkte: §e" + currentQuestion.points + " §8| §7Tippe die Antwort im Chat!");
}
@EventHandler(priority = EventPriority.LOWEST)
public void onChat(AsyncPlayerChatEvent e) {
if (currentEvent == null || currentQuestion == null || answered) return;
Player p = e.getPlayer();
String msg = e.getMessage().trim();
if (msg.equalsIgnoreCase(currentQuestion.answer)) {
answered = true;
currentEvent.addScore(p.getUniqueId(), currentQuestion.points);
broadcast("§a✔ §f" + p.getName() + " §7hat die Antwort gewusst! §a+" + currentQuestion.points + " §7Punkte");
Bukkit.getScheduler().runTask(plugin, () ->
p.playSound(p.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1f, 1.5f));
}
}
private void broadcast(String msg) { Bukkit.broadcastMessage(msg); }
}

View File

@@ -0,0 +1,219 @@
package dev.viper.eventengine.events.custom;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.util.ColorUtil;
import dev.viper.eventengine.model.EventCategory;
import dev.viper.eventengine.model.EventDefinition;
import org.bukkit.entity.Player;
import java.util.*;
/**
* Geführter CLI-Wizard für Admins zum Erstellen von Custom Events.
*
* Ablauf:
* /event create <id> → Startet den Wizard
* → Spieler antwortet auf Fragen über Chat
*
* Wird über EventCreateListener empfangen.
*/
public class CustomEventBuilder {
public enum Step {
DISPLAY_NAME,
DESCRIPTION,
CATEGORY,
DURATION,
MIN_PLAYERS,
MAX_PLAYERS,
ANNOUNCEMENT,
START_COMMANDS,
END_COMMANDS,
REWARDS,
CONFIRM
}
private final EventEngine plugin;
private final Player player;
private final EventDefinition def;
private Step currentStep;
public CustomEventBuilder(EventEngine plugin, Player player, String id) {
this.plugin = plugin;
this.player = player;
this.def = new EventDefinition(id.toLowerCase());
this.currentStep = Step.DISPLAY_NAME;
promptCurrentStep();
}
// ─── Eingabe verarbeiten ───────────────────────────────────────────────
public boolean handleInput(String input) {
switch (currentStep) {
case DISPLAY_NAME -> {
def.setDisplayName(input);
advance();
}
case DESCRIPTION -> {
def.setDescription(input);
advance();
}
case CATEGORY -> {
try {
EventCategory cat = EventCategory.valueOf(input.toUpperCase());
def.setCategory(cat);
advance();
} catch (Exception e) {
sendError("Ungültige Kategorie. Wähle: " + getCategoryList());
}
}
case DURATION -> {
if (input.equalsIgnoreCase("skip") || input.equals("0")) {
def.setDurationSeconds(0);
advance();
} else {
try {
int sec = Integer.parseInt(input);
if (sec < 0) throw new NumberFormatException();
def.setDurationSeconds(sec);
advance();
} catch (NumberFormatException e) {
sendError("Bitte eine Zahl in Sekunden eingeben (0 = unbegrenzt).");
}
}
}
case MIN_PLAYERS -> {
try {
int n = Integer.parseInt(input);
if (n < 1) throw new NumberFormatException();
def.setMinPlayers(n);
advance();
} catch (NumberFormatException e) {
sendError("Bitte eine Zahl ≥ 1 eingeben.");
}
}
case MAX_PLAYERS -> {
try {
int n = Integer.parseInt(input);
if (n < def.getMinPlayers()) throw new NumberFormatException();
def.setMaxPlayers(n);
advance();
} catch (NumberFormatException e) {
sendError("Bitte eine Zahl ≥ " + def.getMinPlayers() + " eingeben.");
}
}
case ANNOUNCEMENT -> {
if (input.equalsIgnoreCase("skip")) {
// Default beibehalten
} else {
def.setAnnouncement(ColorUtil.color(input));
}
advance();
}
case START_COMMANDS -> {
if (!input.equalsIgnoreCase("skip")) {
List<String> cmds = parseCommandList(input);
def.setStartCommands(cmds);
}
advance();
}
case END_COMMANDS -> {
if (!input.equalsIgnoreCase("skip")) {
List<String> cmds = parseCommandList(input);
def.setEndCommands(cmds);
}
advance();
}
case REWARDS -> {
if (!input.equalsIgnoreCase("skip")) {
List<String> rewards = parseCommandList(input);
def.setRewards(rewards);
}
advance();
}
case CONFIRM -> {
if (input.equalsIgnoreCase("ja") || input.equalsIgnoreCase("yes")) {
plugin.getEventRegistry().register(def);
send("§a✔ Custom Event §e'" + def.getDisplayName() + "' §awurde erstellt und gespeichert!");
send("§7ID: §f" + def.getId() + " §8| §7Start: §f/event start " + def.getId());
return true; // fertig
} else {
send("§cAbgebrochen. Das Event wurde nicht gespeichert.");
return true;
}
}
}
return false; // noch nicht fertig
}
// ─── Navigation ────────────────────────────────────────────────────────
private void advance() {
Step[] steps = Step.values();
int idx = currentStep.ordinal() + 1;
if (idx < steps.length) {
currentStep = steps[idx];
promptCurrentStep();
}
}
private void promptCurrentStep() {
String p = plugin.prefix();
switch (currentStep) {
case DISPLAY_NAME -> send(p + "§e[1/10] §7Anzeigename des Events: §f(z.B. 'Mein Spaß-Event')");
case DESCRIPTION -> send(p + "§e[2/10] §7Beschreibung: §f(kurze Info was passiert)");
case CATEGORY -> send(p + "§e[3/10] §7Kategorie: §f" + getCategoryList());
case DURATION -> send(p + "§e[4/10] §7Dauer in Sekunden: §f(0 oder 'skip' = unbegrenzt)");
case MIN_PLAYERS -> send(p + "§e[5/10] §7Mindestspieler: §f(Standard: 1)");
case MAX_PLAYERS -> send(p + "§e[6/10] §7Maximale Spieler: §f(Standard: 50)");
case ANNOUNCEMENT -> send(p + "§e[7/10] §7Ankündigungstext: §f(oder 'skip' für Standard, &c = Farbe)");
case START_COMMANDS -> send(p + "§e[8/10] §7Start-Befehle: §f(kommagetrennt, %player%=Spieler, oder 'skip')");
case END_COMMANDS -> send(p + "§e[9/10] §7End-Befehle: §f(kommagetrennt, oder 'skip')");
case REWARDS -> send(p + "§e[10/10] §7Belohnungen: §f(Befehle pro Teilnehmer, %player%, oder 'skip')");
case CONFIRM -> {
sendSummary();
send(p + "§eSpeichern? §a[ja] §c[nein]");
}
}
}
private void sendSummary() {
send("§8§m══════════════════════════════");
send("§6 Event Zusammenfassung");
send("§7 ID: §f" + def.getId());
send("§7 Name: §f" + def.getDisplayName());
send("§7 Kategorie: §f" + def.getCategory().getDisplayName());
send("§7 Dauer: §f" + (def.getDurationSeconds() == 0 ? "" : def.getDurationSeconds() + "s"));
send("§7 Spieler: §f" + def.getMinPlayers() + "" + def.getMaxPlayers());
send("§7 Start-Befehle: §f" + def.getStartCommands().size());
send("§7 Belohnungen: §f" + def.getRewards().size());
send("§8§m══════════════════════════════");
}
// ─── Hilfsmethoden ─────────────────────────────────────────────────────
private List<String> parseCommandList(String input) {
List<String> result = new ArrayList<>();
for (String part : input.split(",")) {
String trimmed = part.trim();
if (!trimmed.isEmpty()) result.add(trimmed);
}
return result;
}
private String getCategoryList() {
StringBuilder sb = new StringBuilder();
for (EventCategory cat : EventCategory.values()) {
if (sb.length() > 0) sb.append("§7, ");
sb.append("§e").append(cat.name());
}
return sb.toString();
}
private void send(String msg) { player.sendMessage(msg); }
private void sendError(String msg) { player.sendMessage("§c✗ " + msg); }
public Step getCurrentStep() { return currentStep; }
public EventDefinition getDef() { return def; }
public Player getPlayer() { return player; }
}

View File

@@ -0,0 +1,225 @@
package dev.viper.eventengine.gui;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.EventCategory;
import dev.viper.eventengine.model.EventDefinition;
import dev.viper.eventengine.manager.EventManager;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.*;
import java.util.stream.Collectors;
/**
* Haupt-GUI für EventEngine:
* Seite 1 → Kategorien-Übersicht
* Seite 2 → Events der gewählten Kategorie
* Klick auf Event → Startet das Event (Admin)
*/
public class EventGUI implements Listener {
private static final String MAIN_TITLE = "§8✦ §6EventEngine §8✦ Kategorien";
private static final String EVENT_TITLE_PREFIX = "§8✦ §6Events: ";
private final EventEngine plugin;
// Welche Kategorie der Spieler gerade betrachtet
private final Map<UUID, EventCategory> categoryView = new HashMap<>();
// Welche Seite der Spieler bei Events ist
private final Map<UUID, Integer> pagemap = new HashMap<>();
public EventGUI(EventEngine plugin) {
this.plugin = plugin;
}
// ─── Öffnen ────────────────────────────────────────────────────────────
public void openMain(Player player) {
Inventory inv = Bukkit.createInventory(null, 54, MAIN_TITLE);
fillBorder(inv, Material.BLACK_STAINED_GLASS_PANE);
// Kategorien anzeigen
EventCategory[] cats = EventCategory.values();
int[] slots = {10, 11, 12, 13, 14, 15, 16, 28, 29, 30};
for (int i = 0; i < cats.length && i < slots.length; i++) {
EventCategory cat = cats[i];
long count = plugin.getEventRegistry().getAll().stream()
.filter(d -> d.getCategory() == cat).count();
ItemStack item = makeItem(cat.getIcon(),
"§6" + cat.getDisplayName(),
Arrays.asList("§7" + count + " Events", "", "§eKlicken zum Anzeigen"));
inv.setItem(slots[i], item);
}
// Status-Info
String statusText;
if (plugin.getEventManager().isRunning()) {
statusText = "§a▶ Läuft: §f" + plugin.getEventManager().getCurrentEvent().getDefinition().getDisplayName();
} else {
statusText = "§7Kein Event aktiv";
}
ItemStack status = makeItem(Material.CLOCK, "§eStatus", Arrays.asList(statusText,
"§7Gesamt Events: §f" + plugin.getEventRegistry().count()));
inv.setItem(4, status);
// Zufälliges Event starten
ItemStack random = makeItem(Material.ENDER_PEARL, "§d✦ Zufälliges Event",
Arrays.asList("§7Startet ein zufälliges Event", "§7aus der Rotation.", "", "§eKlicken"));
inv.setItem(40, random);
player.openInventory(inv);
}
public void openCategory(Player player, EventCategory category, int page) {
List<EventDefinition> events = plugin.getEventRegistry().getByCategory(category);
int perPage = 28;
int totalPages = Math.max(1, (int) Math.ceil(events.size() / (double) perPage));
page = Math.max(0, Math.min(page, totalPages - 1));
categoryView.put(player.getUniqueId(), category);
pagemap.put(player.getUniqueId(), page);
String title = EVENT_TITLE_PREFIX + category.getDisplayName() + " §8(" + (page + 1) + "/" + totalPages + ")";
Inventory inv = Bukkit.createInventory(null, 54, title);
fillBorder(inv, Material.GRAY_STAINED_GLASS_PANE);
List<EventDefinition> pageEvents = events.stream()
.skip((long) page * perPage)
.limit(perPage)
.collect(Collectors.toList());
int[] contentSlots = buildContentSlots();
for (int i = 0; i < pageEvents.size() && i < contentSlots.length; i++) {
EventDefinition def = pageEvents.get(i);
List<String> lore = new ArrayList<>();
lore.add("§7" + def.getDescription());
lore.add("");
lore.add("§7Dauer: §f" + EventManager.formatTime(def.getDurationSeconds()));
lore.add("§7Spieler: §f" + def.getMinPlayers() + "" + def.getMaxPlayers());
if (def.isCustom()) lore.add("§d✦ Custom Event");
lore.add("");
lore.add("§aKlicken zum Starten");
Material icon = def.getCategory().getIcon();
if (plugin.getEventManager().isRunning() &&
plugin.getEventManager().getCurrentEvent().getDefinition().getId().equals(def.getId())) {
icon = Material.LIME_CONCRETE;
}
inv.setItem(contentSlots[i], makeItem(icon, "§e" + def.getDisplayName(), lore));
}
// Navigation
if (page > 0) {
inv.setItem(45, makeItem(Material.ARROW, "§7◀ Zurück", List.of("§7Seite " + page)));
}
inv.setItem(49, makeItem(Material.BARRIER, "§c← Hauptmenü", List.of("§7Zurück zur Kategorien-Übersicht")));
if (page < totalPages - 1) {
inv.setItem(53, makeItem(Material.ARROW, "§7Weiter ▶", List.of("§7Seite " + (page + 2))));
}
player.openInventory(inv);
}
// ─── Click-Handler ─────────────────────────────────────────────────────
@EventHandler
public void onClick(InventoryClickEvent event) {
if (!(event.getWhoClicked() instanceof Player player)) return;
String title = event.getView().getTitle();
if (!title.startsWith("§8✦ §6EventEngine") && !title.startsWith(EVENT_TITLE_PREFIX)) return;
event.setCancelled(true);
ItemStack clicked = event.getCurrentItem();
if (clicked == null || clicked.getType() == Material.AIR) return;
if (clicked.getType() == Material.BLACK_STAINED_GLASS_PANE ||
clicked.getType() == Material.GRAY_STAINED_GLASS_PANE) return;
String itemName = ChatColor.stripColor(clicked.getItemMeta() != null ?
clicked.getItemMeta().getDisplayName() : "");
if (title.equals(MAIN_TITLE)) {
handleMainClick(player, itemName, clicked);
} else {
handleCategoryClick(player, title, itemName, clicked, event.getSlot());
}
}
private void handleMainClick(Player player, String itemName, ItemStack item) {
if (itemName.equals("✦ Zufälliges Event")) {
plugin.getEventRegistry().getWeightedRandom()
.ifPresent(def -> plugin.getEventManager().startEvent(def, player));
player.closeInventory();
return;
}
// Kategorien-Match
for (EventCategory cat : EventCategory.values()) {
if (item.getType() == cat.getIcon()) {
openCategory(player, cat, 0);
return;
}
}
}
private void handleCategoryClick(Player player, String title, String itemName, ItemStack item, int slot) {
if (item.getType() == Material.BARRIER) {
openMain(player);
return;
}
if (item.getType() == Material.ARROW) {
EventCategory cat = categoryView.get(player.getUniqueId());
int page = pagemap.getOrDefault(player.getUniqueId(), 0);
if (slot == 45) openCategory(player, cat, page - 1);
else openCategory(player, cat, page + 1);
return;
}
// Event-Klick: Name raussuchen
String stripped = itemName.trim();
plugin.getEventRegistry().getAll().stream()
.filter(d -> d.getDisplayName().equals(stripped))
.findFirst()
.ifPresent(def -> {
player.closeInventory();
plugin.getEventManager().startEvent(def, player);
});
}
// ─── Utility ───────────────────────────────────────────────────────────
private ItemStack makeItem(Material mat, String name, List<String> lore) {
ItemStack item = new ItemStack(mat);
ItemMeta meta = item.getItemMeta();
if (meta == null) return item;
meta.setDisplayName(name);
meta.setLore(lore);
item.setItemMeta(meta);
return item;
}
private void fillBorder(Inventory inv, Material mat) {
ItemStack glass = makeItem(mat, " ", List.of());
int size = inv.getSize();
for (int i = 0; i < 9; i++) inv.setItem(i, glass);
for (int i = size - 9; i < size; i++) inv.setItem(i, glass);
for (int i = 9; i < size - 9; i += 9) inv.setItem(i, glass);
for (int i = 17; i < size - 9; i += 9) inv.setItem(i, glass);
}
private int[] buildContentSlots() {
// Slots 10-16, 19-25, 28-34, 37-43 (ohne Rand)
List<Integer> slots = new ArrayList<>();
for (int row = 1; row <= 4; row++) {
for (int col = 1; col <= 7; col++) {
slots.add(row * 9 + col);
}
}
return slots.stream().mapToInt(Integer::intValue).toArray();
}
}

View File

@@ -0,0 +1,67 @@
package dev.viper.eventengine.listener;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.events.custom.CustomEventBuilder;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Leitet Chat-Nachrichten von Admins im Builder-Modus an CustomEventBuilder weiter.
*/
public class EventCreateListener implements Listener {
private final EventEngine plugin;
// Laufende Builder-Sessions
private final Map<UUID, CustomEventBuilder> sessions = new HashMap<>();
public EventCreateListener(EventEngine plugin) {
this.plugin = plugin;
}
public void startSession(Player player, String id) {
if (sessions.containsKey(player.getUniqueId())) {
player.sendMessage(plugin.prefix() + "§cDu hast bereits einen laufenden Builder. Schreibe 'abbrechen' um ihn zu stoppen.");
return;
}
sessions.put(player.getUniqueId(), new CustomEventBuilder(plugin, player, id));
}
public boolean hasSession(Player player) {
return sessions.containsKey(player.getUniqueId());
}
@EventHandler(priority = EventPriority.LOWEST)
public void onChat(AsyncPlayerChatEvent event) {
Player player = event.getPlayer();
CustomEventBuilder builder = sessions.get(player.getUniqueId());
if (builder == null) return;
event.setCancelled(true); // Eingabe nicht im globalen Chat zeigen
String input = event.getMessage().trim();
if (input.equalsIgnoreCase("abbrechen") || input.equalsIgnoreCase("cancel")) {
sessions.remove(player.getUniqueId());
player.sendMessage(plugin.prefix() + "§cEvent-Builder abgebrochen.");
return;
}
// An Builder weitergeben — synchron auf Main-Thread
plugin.getServer().getScheduler().runTask(plugin, () -> {
boolean done = builder.handleInput(input);
if (done) sessions.remove(player.getUniqueId());
});
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
sessions.remove(event.getPlayer().getUniqueId());
}
}

View File

@@ -0,0 +1,127 @@
package dev.viper.eventengine.listener;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.ActiveEvent;
import dev.viper.eventengine.model.EventRegion;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.PlayerMoveEvent;
/**
* Schützt Event-Regionen während laufender Events:
*
* 1. TNT / Explosionen → kein Block-Schaden innerhalb der Region
* 2. Spieler die die Region verlassen → werden zurückteleportiert
* 3. Block-Interaktionen außerhalb der Region durch Teilnehmer → geblockt
*/
public class EventProtectionListener implements Listener {
private final EventEngine plugin;
public EventProtectionListener(EventEngine plugin) {
this.plugin = plugin;
}
// ─── 1. Explosionen (TNT, Creeper, Ghast, ...) ────────────────────────
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onExplode(EntityExplodeEvent e) {
ActiveEvent active = plugin.getEventManager().getCurrentEvent();
// Immer wenn ein Event läuft: TNT-Blockschaden deaktivieren
if (active == null) return;
if (!plugin.getConfigManager().isNoExplosionBlockDamage()) return;
EventRegion region = active.getDefinition().getRegion();
if (region != null) {
// Nur Blöcke INNERHALB der Region schützen — Explosion außerhalb normal
e.blockList().removeIf(block -> region.contains(block.getLocation()));
} else {
// Kein Region definiert → global während Event kein Block-Schaden durch Explosionen
e.blockList().clear();
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onEntityDamageByExplosion(EntityDamageEvent e) {
// Spieler-Schaden durch Explosionen während Events: behalten (nur Block-Schaden deaktiviert)
// Nichts tun — Spieler sollen Schaden nehmen können
}
// ─── 2. Spieler-Bewegung: Region-Grenze prüfen ────────────────────────
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onMove(PlayerMoveEvent e) {
Player player = e.getPlayer();
ActiveEvent active = plugin.getEventManager().getCurrentEvent();
if (active == null) return;
// Nur für Event-Teilnehmer
if (!active.isParticipant(player)) return;
EventRegion region = active.getDefinition().getRegion();
if (region == null) return; // keine Region → frei bewegen
if (!plugin.getConfigManager().isEnforceRegionBoundary()) return;
Location to = e.getTo();
if (to == null) return;
// Nur prüfen wenn Spieler Block-Grenze überschreitet (Performance)
if (e.getFrom().getBlockX() == to.getBlockX()
&& e.getFrom().getBlockY() == to.getBlockY()
&& e.getFrom().getBlockZ() == to.getBlockZ()) return;
if (!region.contains(to)) {
// Zurückteleportieren zur letzten gültigen Position
e.setCancelled(true);
player.sendActionBar("§c⚠ Du kannst die Event-Arena nicht verlassen!");
}
}
// ─── 3. Block-Break/Place außerhalb der Region ────────────────────────
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent e) {
Player player = e.getPlayer();
ActiveEvent active = plugin.getEventManager().getCurrentEvent();
if (active == null) return;
if (!active.isParticipant(player)) return;
EventRegion region = active.getDefinition().getRegion();
if (region == null) return;
if (!plugin.getConfigManager().isRestrictBlockInteraction()) return;
if (!region.contains(e.getBlock().getLocation())) {
e.setCancelled(true);
player.sendActionBar("§c⚠ Du kannst außerhalb der Event-Arena keine Blöcke abbauen!");
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent e) {
Player player = e.getPlayer();
ActiveEvent active = plugin.getEventManager().getCurrentEvent();
if (active == null) return;
if (!active.isParticipant(player)) return;
EventRegion region = active.getDefinition().getRegion();
if (region == null) return;
if (!plugin.getConfigManager().isRestrictBlockInteraction()) return;
if (!region.contains(e.getBlock().getLocation())) {
e.setCancelled(true);
player.sendActionBar("§c⚠ Du kannst außerhalb der Event-Arena keine Blöcke setzen!");
}
}
}

View File

@@ -0,0 +1,188 @@
package dev.viper.eventengine.manager;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.events.builtin.EventHandlerRegistry;
import dev.viper.eventengine.events.builtin.IEventHandler;
import dev.viper.eventengine.model.ActiveEvent;
import dev.viper.eventengine.model.EventDefinition;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
import java.util.logging.Logger;
/**
* Steuert den Lebenszyklus von Events:
* start → announce → run → end → reward
*/
public class EventManager {
private final EventEngine plugin;
private final Logger log;
private final EventHandlerRegistry handlerRegistry;
private ActiveEvent currentEvent = null;
private final Deque<EventDefinition> queue = new ArrayDeque<>();
public EventManager(EventEngine plugin) {
this.plugin = plugin;
this.log = plugin.getLogger();
this.handlerRegistry = new EventHandlerRegistry(plugin);
}
public boolean startEvent(EventDefinition def, Player initiator) {
if (currentEvent != null && currentEvent.getState() != ActiveEvent.State.ENDED) {
if (initiator != null)
initiator.sendMessage(plugin.prefix() + "§cEin Event läuft bereits: §e"
+ currentEvent.getDefinition().getDisplayName());
return false;
}
currentEvent = new ActiveEvent(def);
currentEvent.setState(ActiveEvent.State.RUNNING);
broadcast(def.getAnnouncement());
if (def.getDurationSeconds() > 0)
broadcast(plugin.prefix() + "§7Dauer: §e" + formatTime(def.getDurationSeconds()));
if (plugin.getConfigManager().isLogEvents()) {
String by = initiator != null ? initiator.getName() : "Zeitplan";
log.info("Event gestartet von " + by + ": " + def.getDisplayName());
}
runCommands(def.getStartCommands(), null);
handlerRegistry.get(def.getType()).ifPresent(h -> h.onStart(currentEvent));
if (def.getDurationSeconds() > 0) {
final ActiveEvent snap = currentEvent;
if (def.getDurationSeconds() > 70)
new BukkitRunnable() { @Override public void run() {
if (currentEvent == snap && currentEvent.getState() == ActiveEvent.State.RUNNING)
broadcast(plugin.prefix() + "§e⏰ Noch §c60 Sekunden §ebis das Event endet!");
}}.runTaskLater(plugin, (def.getDurationSeconds() - 60) * 20L);
if (def.getDurationSeconds() > 15)
new BukkitRunnable() { @Override public void run() {
if (currentEvent == snap && currentEvent.getState() == ActiveEvent.State.RUNNING)
broadcast(plugin.prefix() + "§c⏰ Noch 10 Sekunden!");
}}.runTaskLater(plugin, (def.getDurationSeconds() - 10) * 20L);
int taskId = (int) new BukkitRunnable() { @Override public void run() {
if (currentEvent == snap && currentEvent.getState() == ActiveEvent.State.RUNNING)
endEvent("Zeit abgelaufen");
}}.runTaskLater(plugin, def.getDurationSeconds() * 20L).getTaskId();
currentEvent.setTaskId(taskId);
}
return true;
}
public boolean endEvent(String reason) {
if (currentEvent == null || currentEvent.getState() == ActiveEvent.State.ENDED) return false;
EventDefinition def = currentEvent.getDefinition();
currentEvent.setState(ActiveEvent.State.ENDED);
if (currentEvent.getTaskId() != -1)
Bukkit.getScheduler().cancelTask(currentEvent.getTaskId());
handlerRegistry.get(def.getType()).ifPresent(h -> h.onEnd(currentEvent));
broadcast(plugin.prefix() + "§6✦ §e" + def.getDisplayName()
+ " §7ist beendet! §7(" + reason + ")");
showLeaderboard();
runCommands(def.getEndCommands(), null);
distributeRewards(def);
if (plugin.getConfigManager().isLogEvents())
log.info("Event beendet: " + def.getDisplayName() + " [" + reason + "]");
currentEvent = null;
if (!queue.isEmpty()) {
EventDefinition next = queue.poll();
Bukkit.getScheduler().runTaskLater(plugin, () -> startEvent(next, null), 100L);
}
return true;
}
public boolean join(Player player) {
if (currentEvent == null || currentEvent.getState() == ActiveEvent.State.ENDED) {
player.sendMessage(plugin.prefix() + "§cKein Event aktiv."); return false;
}
if (currentEvent.isParticipant(player)) {
player.sendMessage(plugin.prefix() + "§cDu nimmst bereits teil."); return false;
}
EventDefinition def = currentEvent.getDefinition();
if (currentEvent.getParticipantCount() >= def.getMaxPlayers()) {
player.sendMessage(plugin.prefix() + "§cDas Event ist voll!"); return false;
}
currentEvent.addParticipant(player);
broadcast(plugin.prefix() + "§a" + player.getName() + " §7nimmt teil! §8("
+ currentEvent.getParticipantCount() + "/" + def.getMaxPlayers() + ")");
handlerRegistry.get(def.getType()).ifPresent(h -> h.onPlayerJoin(currentEvent, player));
return true;
}
public void leave(Player player) {
if (currentEvent == null) { player.sendMessage(plugin.prefix() + "§cKein Event aktiv."); return; }
if (!currentEvent.isParticipant(player)) { player.sendMessage(plugin.prefix() + "§cDu nimmst nicht teil."); return; }
currentEvent.removeParticipant(player);
handlerRegistry.get(currentEvent.getDefinition().getType())
.ifPresent(h -> h.onPlayerLeave(currentEvent, player));
player.sendMessage(plugin.prefix() + "§7Du hast das Event verlassen.");
}
private void showLeaderboard() {
if (currentEvent == null) return;
List<Map.Entry<UUID, Integer>> lb = currentEvent.getLeaderboard();
if (lb.isEmpty()) return;
broadcast("§8§m══════════════════════════════");
broadcast("§6 🏆 Event Leaderboard §8 §e" + currentEvent.getDefinition().getDisplayName());
int rank = 1;
for (Map.Entry<UUID, Integer> e : lb) {
if (rank > 5) break;
Player p = Bukkit.getPlayer(e.getKey());
String name = p != null ? p.getName() : "Unbekannt";
String medal = switch (rank) { case 1 -> "§6🥇"; case 2 -> "§7🥈"; case 3 -> "§c🥉"; default -> "§7 " + rank + "."; };
broadcast(" " + medal + " §f" + name + " §8 §e" + e.getValue() + " Punkte");
rank++;
}
broadcast("§8§m══════════════════════════════");
}
private void distributeRewards(EventDefinition def) {
if (def.getRewards().isEmpty() || currentEvent == null) return;
for (UUID uuid : currentEvent.getParticipants()) {
Player p = Bukkit.getPlayer(uuid);
if (p == null) continue;
for (String cmd : def.getRewards())
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd.replace("%player%", p.getName()));
}
}
private void runCommands(List<String> cmds, Player player) {
for (String cmd : cmds) {
String filled = player != null ? cmd.replace("%player%", player.getName()) : cmd;
try { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), filled); }
catch (Exception ex) { log.warning("Befehl fehlgeschlagen: " + filled); }
}
}
private void broadcast(String msg) { Bukkit.broadcastMessage(msg); }
public static String formatTime(int seconds) {
if (seconds <= 0) return "";
int m = seconds / 60, s = seconds % 60;
if (m == 0) return s + "s";
if (s == 0) return m + "m";
return m + "m " + s + "s";
}
public void enqueue(EventDefinition def) { queue.add(def); }
public void clearQueue() { queue.clear(); }
public int queueSize() { return queue.size(); }
public ActiveEvent getCurrentEvent() { return currentEvent; }
public boolean isRunning() { return currentEvent != null && currentEvent.getState() == ActiveEvent.State.RUNNING; }
public EventHandlerRegistry getHandlerRegistry() { return handlerRegistry; }
}

View File

@@ -0,0 +1,142 @@
package dev.viper.eventengine.manager;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.util.ColorUtil;
import dev.viper.eventengine.config.EventOverrideLoader;
import dev.viper.eventengine.model.EventCategory;
import dev.viper.eventengine.model.EventDefinition;
import dev.viper.eventengine.model.EventType;
import java.util.*;
import java.util.stream.Collectors;
/**
* Zentrales Registry für alle EventDefinitions.
* Enthält alle 100+ eingebauten Events und beliebig viele Custom-Events.
*/
public class EventRegistry {
private final EventEngine plugin;
// Geordnete Map: id → Definition
private final Map<String, EventDefinition> events = new LinkedHashMap<>();
public EventRegistry(EventEngine plugin) {
this.plugin = plugin;
}
// ─── Initialisierung ───────────────────────────────────────────────────
public void init() {
events.clear();
registerBuiltins();
loadCustom();
plugin.getLogger().info("EventRegistry: " + events.size() + " Events registriert.");
}
private void registerBuiltins() {
EventOverrideLoader overrideLoader = new EventOverrideLoader(plugin);
for (EventType type : EventType.values()) {
if (type == EventType.CUSTOM) continue;
EventDefinition def = createBuiltin(type);
overrideLoader.apply(def); // config.yml overrides anwenden
events.put(def.getId(), def);
}
}
/**
* Erstellt eine EventDefinition mit sinnvollen Defaults pro Typ.
* Hier können Standardwerte (Dauer, Spielerzahl) pro Event gesetzt werden.
*/
private EventDefinition createBuiltin(EventType type) {
EventDefinition def = new EventDefinition(type);
// Spezifische Overrides pro Typ
switch (type) {
case PVP_ONE_VS_ONE -> { def.setMinPlayers(2); def.setMaxPlayers(2); }
case PVP_TEAM_BATTLE -> { def.setMinPlayers(4); def.setMaxPlayers(40); }
case PVP_UHC -> { def.setDurationSeconds(3600); def.setMinPlayers(4); }
case PVP_HUNGER_GAMES -> { def.setDurationSeconds(1800); def.setMinPlayers(8); }
case SURVIVAL_BOSS_RUSH -> { def.setDurationSeconds(600); def.setMinPlayers(1); }
case SURVIVAL_WITHER_STORM -> { def.setDurationSeconds(900); def.setMinPlayers(2); }
case BUILD_BATTLE -> { def.setDurationSeconds(300); def.setMinPlayers(2); }
case BUILD_SPEED_BUILD -> { def.setDurationSeconds(120); def.setMinPlayers(1); }
case RACE_PARKOUR -> { def.setDurationSeconds(180); def.setMinPlayers(1); }
case FUN_DROP_PARTY -> { def.setDurationSeconds(60); def.setMinPlayers(1); def.setMaxPlayers(200); }
case FUN_TNT_RAIN -> { def.setDurationSeconds(30); def.setMinPlayers(1); def.setMaxPlayers(200); }
case QUIZ_SPEED_QUIZ -> { def.setDurationSeconds(120); def.setMinPlayers(1); }
case ECONOMY_LOTTERY -> { def.setDurationSeconds(120); def.setMinPlayers(1); def.setMaxPlayers(200); }
default -> { /* Defaults aus Konstruktor */ }
}
// Ankündigungs-Texte
def.setAnnouncement("&6✦ &e" + type.getDisplayName() + " &7[" + type.getCategory().getDisplayName() + "&7] &6startet jetzt! &7Viel Erfolg!");
return def;
}
private void loadCustom() {
Map<String, EventDefinition> custom = plugin.getConfigManager().loadCustomEvents();
events.putAll(custom);
}
// ─── API ───────────────────────────────────────────────────────────────
public Optional<EventDefinition> get(String id) {
return Optional.ofNullable(events.get(id.toLowerCase()));
}
public Collection<EventDefinition> getAll() {
return Collections.unmodifiableCollection(events.values());
}
public List<EventDefinition> getByCategory(EventCategory category) {
return events.values().stream()
.filter(d -> d.getCategory() == category)
.collect(Collectors.toList());
}
public List<EventDefinition> getRotation() {
return events.values().stream()
.filter(EventDefinition::isInRotation)
.collect(Collectors.toList());
}
/**
* Wählt ein zufälliges Event aus der Rotation, gewichtet.
*/
public Optional<EventDefinition> getWeightedRandom() {
List<EventDefinition> rotation = getRotation();
if (rotation.isEmpty()) return Optional.empty();
int totalWeight = rotation.stream().mapToInt(EventDefinition::getWeight).sum();
int roll = new Random().nextInt(Math.max(totalWeight, 1));
int cumulative = 0;
for (EventDefinition def : rotation) {
cumulative += def.getWeight();
if (roll < cumulative) return Optional.of(def);
}
return Optional.of(rotation.get(0));
}
public void register(EventDefinition def) {
events.put(def.getId().toLowerCase(), def);
if (def.isCustom()) {
plugin.getConfigManager().saveCustomEvent(def);
}
}
public boolean remove(String id) {
EventDefinition def = events.remove(id.toLowerCase());
if (def != null && def.isCustom()) {
plugin.getConfigManager().deleteCustomEvent(id);
return true;
}
return def != null;
}
public boolean exists(String id) {
return events.containsKey(id.toLowerCase());
}
public int count() { return events.size(); }
}

View File

@@ -0,0 +1,75 @@
package dev.viper.eventengine.model;
import org.bukkit.entity.Player;
import java.util.*;
/**
* Repräsentiert eine aktuell laufende Event-Instanz.
*/
public class ActiveEvent {
public enum State { WAITING, RUNNING, ENDED }
private final EventDefinition definition;
private State state;
private final long startTime;
private final Set<UUID> participants;
private final Map<UUID, Integer> scores;
private int taskId = -1;
public ActiveEvent(EventDefinition definition) {
this.definition = definition;
this.state = State.WAITING;
this.startTime = System.currentTimeMillis();
this.participants = new LinkedHashSet<>();
this.scores = new HashMap<>();
}
public void addParticipant(Player player) {
participants.add(player.getUniqueId());
scores.putIfAbsent(player.getUniqueId(), 0);
}
public void removeParticipant(Player player) {
participants.remove(player.getUniqueId());
}
public boolean isParticipant(Player player) {
return participants.contains(player.getUniqueId());
}
public void addScore(UUID uuid, int points) {
scores.merge(uuid, points, Integer::sum);
}
public int getScore(UUID uuid) {
return scores.getOrDefault(uuid, 0);
}
/** Gibt Spieler sortiert nach Score zurück */
public List<Map.Entry<UUID, Integer>> getLeaderboard() {
List<Map.Entry<UUID, Integer>> entries = new ArrayList<>(scores.entrySet());
entries.sort((a, b) -> b.getValue() - a.getValue());
return entries;
}
public long getElapsedSeconds() {
return (System.currentTimeMillis() - startTime) / 1000;
}
public long getRemainingSeconds() {
if (definition.getDurationSeconds() == 0) return -1;
long remaining = definition.getDurationSeconds() - getElapsedSeconds();
return Math.max(0, remaining);
}
public EventDefinition getDefinition() { return definition; }
public State getState() { return state; }
public void setState(State state) { this.state = state; }
public Set<UUID> getParticipants() { return Collections.unmodifiableSet(participants); }
public Map<UUID, Integer> getScores() { return scores; }
public int getTaskId() { return taskId; }
public void setTaskId(int taskId) { this.taskId = taskId; }
public int getParticipantCount() { return participants.size(); }
}

View File

@@ -0,0 +1,27 @@
package dev.viper.eventengine.model;
import org.bukkit.Material;
public enum EventCategory {
COMBAT("⚔ Kampf", Material.DIAMOND_SWORD),
SURVIVAL("🌲 Überleben", Material.COOKED_BEEF),
BUILDING("🏗 Bauen", Material.BRICKS),
RACING("🏁 Rennen", Material.GOLDEN_BOOTS),
COLLECTION("📦 Sammeln", Material.CHEST),
FUN("🎉 Spaß", Material.FIREWORK_ROCKET),
QUIZ("❓ Quiz", Material.BOOK),
ECONOMY("💰 Wirtschaft", Material.GOLD_INGOT),
TEAM("👥 Team", Material.YELLOW_BANNER),
CUSTOM("⭐ Custom", Material.COMMAND_BLOCK);
private final String displayName;
private final Material icon;
EventCategory(String displayName, Material icon) {
this.displayName = displayName;
this.icon = icon;
}
public String getDisplayName() { return displayName; }
public Material getIcon() { return icon; }
}

View File

@@ -0,0 +1,191 @@
package dev.viper.eventengine.model;
import dev.viper.eventengine.util.ColorUtil;
import dev.viper.eventengine.model.EventRegion;
import org.bukkit.configuration.ConfigurationSection;
import java.util.*;
/**
* Repräsentiert ein einzelnes Event — sowohl eingebaute als auch Custom-Events.
* Custom-Events werden in custom_events.yml gespeichert.
*/
public class EventDefinition {
private final String id;
private String displayName;
private String description;
private EventType type;
private EventCategory category;
// Zeitlimit in Sekunden (0 = unbegrenzt)
private int durationSeconds;
// Mindest-/Höchst-Spielerzahl
private int minPlayers;
private int maxPlayers;
// Befehle die beim Start/Ende ausgeführt werden
private List<String> startCommands;
private List<String> endCommands;
// Belohnungen
private List<String> rewards;
// Ankündigungs-Text
private String announcement;
// Ob das Event in der Rotation ist
private boolean inRotation;
// Gewichtung in der Rotation
private int weight;
// Custom-Einstellungen (Key-Value)
private Map<String, Object> customSettings;
// Ist es ein benutzerdefiniertes Event?
private boolean isCustom;
// Optionale Event-Region (null = gesamte Welt)
private EventRegion region;
// ─── Konstruktor für builtin Events ────────────────────────────────────
public EventDefinition(EventType type) {
this.id = type.name().toLowerCase();
this.type = type;
this.category = type.getCategory();
this.displayName = type.getDisplayName();
this.description = "Ein " + type.getDisplayName() + " Event.";
this.durationSeconds = 300;
this.minPlayers = 2;
this.maxPlayers = 50;
this.startCommands = new ArrayList<>();
this.endCommands = new ArrayList<>();
this.rewards = new ArrayList<>();
this.announcement = ColorUtil.color("&6✦ &e" + displayName + " &6startet jetzt!");
this.inRotation = true;
this.weight = 1;
this.customSettings = new HashMap<>();
this.isCustom = false;
}
// ─── Konstruktor für Custom Events ─────────────────────────────────────
public EventDefinition(String id) {
this.id = id;
this.type = EventType.CUSTOM;
this.category = EventCategory.CUSTOM;
this.displayName = id;
this.description = "Benutzerdefiniertes Event.";
this.durationSeconds = 300;
this.minPlayers = 1;
this.maxPlayers = 50;
this.startCommands = new ArrayList<>();
this.endCommands = new ArrayList<>();
this.rewards = new ArrayList<>();
this.announcement = ColorUtil.color("&6✦ &e" + id + " &6startet jetzt!");
this.inRotation = true;
this.weight = 1;
this.customSettings = new HashMap<>();
this.isCustom = true;
}
// ─── Laden aus ConfigurationSection ────────────────────────────────────
public static EventDefinition fromConfig(String id, ConfigurationSection sec) {
EventDefinition def = new EventDefinition(id);
def.displayName = sec.getString("display-name", id);
def.description = sec.getString("description", "Kein Beschreibungstext.");
def.durationSeconds = sec.getInt("duration-seconds", 300);
def.minPlayers = sec.getInt("min-players", 1);
def.maxPlayers = sec.getInt("max-players", 50);
def.startCommands = sec.getStringList("start-commands");
def.endCommands = sec.getStringList("end-commands");
def.rewards = sec.getStringList("rewards");
def.announcement = ColorUtil.color(sec.getString("announcement",
"&6✦ &e" + def.displayName + " &6startet jetzt!"));
def.inRotation = sec.getBoolean("in-rotation", true);
def.weight = sec.getInt("weight", 1);
String catStr = sec.getString("category", "CUSTOM");
try { def.category = EventCategory.valueOf(catStr); }
catch (Exception e) { def.category = EventCategory.CUSTOM; }
ConfigurationSection cs = sec.getConfigurationSection("settings");
if (cs != null) {
for (String key : cs.getKeys(false)) {
def.customSettings.put(key, cs.get(key));
}
}
// Region laden
if (sec.contains("region.world")) {
try {
String w = sec.getString("region.world");
int minX = sec.getInt("region.min-x");
int minY = sec.getInt("region.min-y");
int minZ = sec.getInt("region.min-z");
int maxX = sec.getInt("region.max-x");
int maxY = sec.getInt("region.max-y");
int maxZ = sec.getInt("region.max-z");
def.region = new EventRegion(w, minX, minY, minZ, maxX, maxY, maxZ);
} catch (Exception ignored) {}
}
return def;
}
// ─── Speichern in ConfigurationSection ─────────────────────────────────
public void saveToConfig(ConfigurationSection sec) {
sec.set("display-name", displayName);
sec.set("description", description);
sec.set("duration-seconds", durationSeconds);
sec.set("min-players", minPlayers);
sec.set("max-players", maxPlayers);
sec.set("start-commands", startCommands);
sec.set("end-commands", endCommands);
sec.set("rewards", rewards);
sec.set("announcement", announcement);
sec.set("in-rotation", inRotation);
sec.set("weight", weight);
sec.set("category", category.name());
if (region != null) {
sec.set("region.world", region.getWorldName());
sec.set("region.min-x", region.getMinX());
sec.set("region.min-y", region.getMinY());
sec.set("region.min-z", region.getMinZ());
sec.set("region.max-x", region.getMaxX());
sec.set("region.max-y", region.getMaxY());
sec.set("region.max-z", region.getMaxZ());
}
if (!customSettings.isEmpty()) {
for (Map.Entry<String, Object> entry : customSettings.entrySet()) {
sec.set("settings." + entry.getKey(), entry.getValue());
}
}
}
// ─── Getter/Setter ──────────────────────────────────────────────────────
public String getId() { return id; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String n) { this.displayName = n; }
public String getDescription() { return description; }
public void setDescription(String d) { this.description = d; }
public EventType getType() { return type; }
public EventCategory getCategory() { return category; }
public void setCategory(EventCategory c) { this.category = c; }
public int getDurationSeconds() { return durationSeconds; }
public void setDurationSeconds(int s) { this.durationSeconds = s; }
public int getMinPlayers() { return minPlayers; }
public void setMinPlayers(int n) { this.minPlayers = n; }
public int getMaxPlayers() { return maxPlayers; }
public void setMaxPlayers(int n) { this.maxPlayers = n; }
public List<String> getStartCommands() { return startCommands; }
public void setStartCommands(List<String> l) { this.startCommands = l; }
public List<String> getEndCommands() { return endCommands; }
public void setEndCommands(List<String> l) { this.endCommands = l; }
public List<String> getRewards() { return rewards; }
public void setRewards(List<String> l) { this.rewards = l; }
public String getAnnouncement() { return announcement; }
public void setAnnouncement(String a) { this.announcement = ColorUtil.color(a); }
public boolean isInRotation() { return inRotation; }
public void setInRotation(boolean b) { this.inRotation = b; }
public int getWeight() { return weight; }
public void setWeight(int w) { this.weight = w; }
public Map<String, Object> getCustomSettings() { return customSettings; }
public boolean isCustom() { return isCustom; }
public EventRegion getRegion() { return region; }
public void setRegion(EventRegion r) { this.region = r; }
public boolean hasRegion() { return region != null; }
public Object getSetting(String key) { return customSettings.get(key); }
public void setSetting(String key, Object val) { customSettings.put(key, val); }
}
// Wird unten in der Klasse ergänzt — separate Patch-Datei

View File

@@ -0,0 +1,101 @@
package dev.viper.eventengine.model;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
/**
* Achsenparalleler Quader in einer Welt.
* Wird pro EventDefinition gespeichert.
*/
public class EventRegion {
private final String worldName;
private final int minX, minY, minZ;
private final int maxX, maxY, maxZ;
public EventRegion(Location pos1, Location pos2) {
if (!pos1.getWorld().equals(pos2.getWorld()))
throw new IllegalArgumentException("Beide Positionen müssen in der gleichen Welt sein!");
this.worldName = pos1.getWorld().getName();
this.minX = Math.min(pos1.getBlockX(), pos2.getBlockX());
this.minY = Math.min(pos1.getBlockY(), pos2.getBlockY());
this.minZ = Math.min(pos1.getBlockZ(), pos2.getBlockZ());
this.maxX = Math.max(pos1.getBlockX(), pos2.getBlockX());
this.maxY = Math.max(pos1.getBlockY(), pos2.getBlockY());
this.maxZ = Math.max(pos1.getBlockZ(), pos2.getBlockZ());
}
/** Konstruktor aus gespeicherten Werten (Config-Load) */
public EventRegion(String worldName, int minX, int minY, int minZ,
int maxX, int maxY, int maxZ) {
this.worldName = worldName;
this.minX = minX; this.minY = minY; this.minZ = minZ;
this.maxX = maxX; this.maxY = maxY; this.maxZ = maxZ;
}
// ─── Prüfungen ─────────────────────────────────────────────────────────
public boolean contains(Location loc) {
if (loc == null || loc.getWorld() == null) return false;
if (!loc.getWorld().getName().equals(worldName)) return false;
int x = loc.getBlockX(), y = loc.getBlockY(), z = loc.getBlockZ();
return x >= minX && x <= maxX
&& y >= minY && y <= maxY
&& z >= minZ && z <= maxZ;
}
/** Erweiterte Prüfung mit horizontalem Puffer (für Boundary-Events) */
public boolean containsWithBuffer(Location loc, int buffer) {
if (loc == null || loc.getWorld() == null) return false;
if (!loc.getWorld().getName().equals(worldName)) return false;
int x = loc.getBlockX(), y = loc.getBlockY(), z = loc.getBlockZ();
return x >= minX - buffer && x <= maxX + buffer
&& y >= minY - buffer && y <= maxY + buffer
&& z >= minZ - buffer && z <= maxZ + buffer;
}
// ─── Hilfsmethoden ─────────────────────────────────────────────────────
/** Mittelpunkt der Region auf Bodenhöhe (minY) */
public Location getCenter() {
World world = Bukkit.getWorld(worldName);
if (world == null) return null;
return new Location(world,
(minX + maxX) / 2.0 + 0.5,
minY,
(minZ + maxZ) / 2.0 + 0.5);
}
/** Zufällige sichere Position innerhalb der Region */
public Location randomLocation(java.util.Random rng) {
World world = Bukkit.getWorld(worldName);
if (world == null) return null;
int x = minX + rng.nextInt(Math.max(1, maxX - minX));
int z = minZ + rng.nextInt(Math.max(1, maxZ - minZ));
// Y auf Oberfläche oder minY+1
int y = world.getHighestBlockYAt(x, z);
y = Math.max(y, minY + 1);
return new Location(world, x + 0.5, y, z + 0.5);
}
public World getWorld() { return Bukkit.getWorld(worldName); }
public String getWorldName() { return worldName; }
public int getMinX() { return minX; }
public int getMinY() { return minY; }
public int getMinZ() { return minZ; }
public int getMaxX() { return maxX; }
public int getMaxY() { return maxY; }
public int getMaxZ() { return maxZ; }
/** Größe in Blöcken */
public int getSizeX() { return maxX - minX + 1; }
public int getSizeY() { return maxY - minY + 1; }
public int getSizeZ() { return maxZ - minZ + 1; }
@Override
public String toString() {
return worldName + " [" + minX + "," + minY + "," + minZ
+ "] → [" + maxX + "," + maxY + "," + maxZ + "]";
}
}

View File

@@ -0,0 +1,156 @@
package dev.viper.eventengine.model;
public enum EventType {
// ═══════════════════════════════════════════════════════════
// COMBAT EVENTS (20)
// ═══════════════════════════════════════════════════════════
PVP_DEATHMATCH("PvP Deathmatch", EventCategory.COMBAT),
PVP_TEAM_BATTLE("Team Battle", EventCategory.COMBAT),
PVP_FREE_FOR_ALL("Free for All", EventCategory.COMBAT),
PVP_LAST_MAN_STANDING("Last Man Standing", EventCategory.COMBAT),
PVP_ONE_VS_ONE("1v1 Turnier", EventCategory.COMBAT),
PVP_BOW_ONLY("Nur Bogen", EventCategory.COMBAT),
PVP_SWORD_ONLY("Nur Schwert", EventCategory.COMBAT),
PVP_FIST_FIGHT("Faustkampf", EventCategory.COMBAT),
PVP_KIT_PVP("Kit PvP", EventCategory.COMBAT),
PVP_CAPTURE_THE_FLAG("Capture the Flag", EventCategory.COMBAT),
PVP_KING_OF_THE_HILL("King of the Hill", EventCategory.COMBAT),
PVP_HUNGER_GAMES("Hunger Games", EventCategory.COMBAT),
PVP_BEDWARS_LITE("BedWars Lite", EventCategory.COMBAT),
PVP_SKYWARS_LITE("SkyWars Lite", EventCategory.COMBAT),
PVP_UHC("Ultra Hardcore", EventCategory.COMBAT),
PVP_SPLEEF("Spleef", EventCategory.COMBAT),
PVP_SUMO("Sumo", EventCategory.COMBAT),
PVP_SNOWBALL_FIGHT("Schneeballschlacht", EventCategory.COMBAT),
PVP_ELYTRA_PVP("Elytra PvP", EventCategory.COMBAT),
PVP_ARENA_SURVIVAL("Arena Survival", EventCategory.COMBAT),
// ═══════════════════════════════════════════════════════════
// SURVIVAL EVENTS (15)
// ═══════════════════════════════════════════════════════════
SURVIVAL_MOB_WAVE("Mob-Wellen", EventCategory.SURVIVAL),
SURVIVAL_ZOMBIE_SIEGE("Zombie-Belagerung", EventCategory.SURVIVAL),
SURVIVAL_BOSS_RUSH("Boss Rush", EventCategory.SURVIVAL),
SURVIVAL_WITHER_STORM("Wither Sturm", EventCategory.SURVIVAL),
SURVIVAL_DRAGON_FIGHT("Drachen-Event", EventCategory.SURVIVAL),
SURVIVAL_HARDCORE_ROUND("Hardcore-Runde", EventCategory.SURVIVAL),
SURVIVAL_ISLAND("Insel-Überleben", EventCategory.SURVIVAL),
SURVIVAL_NETHER_RUN("Nether-Sprint", EventCategory.SURVIVAL),
SURVIVAL_ENDURANCE("Ausdauer-Test", EventCategory.SURVIVAL),
SURVIVAL_RAIDS_PLUS("Raid+", EventCategory.SURVIVAL),
SURVIVAL_MONSTER_HUNT("Monster-Jagd", EventCategory.SURVIVAL),
SURVIVAL_LAVA_RISING("Steigendes Lava", EventCategory.SURVIVAL),
SURVIVAL_GRAVITY_SHIFT("Schwerkraft-Chaos", EventCategory.SURVIVAL),
SURVIVAL_RANDOM_SPAWN("Random Spawn", EventCategory.SURVIVAL),
SURVIVAL_MANHUNT("Manhunt", EventCategory.SURVIVAL),
// ═══════════════════════════════════════════════════════════
// BUILDING EVENTS (10)
// ═══════════════════════════════════════════════════════════
BUILD_BATTLE("Build Battle", EventCategory.BUILDING),
BUILD_SPEED_BUILD("Speed Build", EventCategory.BUILDING),
BUILD_THEME_CHALLENGE("Themen-Challenge", EventCategory.BUILDING),
BUILD_PIXEL_ART("Pixel Art Contest", EventCategory.BUILDING),
BUILD_TALLEST_TOWER("Höchster Turm", EventCategory.BUILDING),
BUILD_BRIDGE("Brücke bauen", EventCategory.BUILDING),
BUILD_REDSTONE("Redstone Challenge", EventCategory.BUILDING),
BUILD_UNDERGROUND("Unterirdisch bauen", EventCategory.BUILDING),
BUILD_SKYBLOCK_STYLE("Skyblock Style", EventCategory.BUILDING),
BUILD_BLINDBUILD("Blind bauen", EventCategory.BUILDING),
// ═══════════════════════════════════════════════════════════
// RACING EVENTS (10)
// ═══════════════════════════════════════════════════════════
RACE_PARKOUR("Parkour Race", EventCategory.RACING),
RACE_ELYTRA("Elytra-Rennen", EventCategory.RACING),
RACE_BOAT("Boot-Rennen", EventCategory.RACING),
RACE_HORSE("Pferde-Rennen", EventCategory.RACING),
RACE_PIG("Schweine-Rennen", EventCategory.RACING),
RACE_MINECART("Lore-Rennen", EventCategory.RACING),
RACE_SWIMMING("Schwimm-Rennen", EventCategory.RACING),
RACE_OBSTACLE("Hindernislauf", EventCategory.RACING),
RACE_MAZE("Labyrinth", EventCategory.RACING),
RACE_ICEBOAT("Eisboot-Rennen", EventCategory.RACING),
// ═══════════════════════════════════════════════════════════
// COLLECTION EVENTS (10)
// ═══════════════════════════════════════════════════════════
COLLECT_SCAVENGER_HUNT("Schatzsuche", EventCategory.COLLECTION),
COLLECT_MINING_COMP("Mining-Wettbewerb", EventCategory.COLLECTION),
COLLECT_FISHING_COMP("Angel-Wettbewerb", EventCategory.COLLECTION),
COLLECT_FARMING_COMP("Farm-Wettbewerb", EventCategory.COLLECTION),
COLLECT_MOB_DROPS("Mob-Drops sammeln", EventCategory.COLLECTION),
COLLECT_TREASURE_HUNT("Schatz finden", EventCategory.COLLECTION),
COLLECT_EASTER_EGG("Eier suchen", EventCategory.COLLECTION),
COLLECT_SPEED_MINE("Speed Mining", EventCategory.COLLECTION),
COLLECT_WOODCUTTING("Holzfäll-Comp", EventCategory.COLLECTION),
COLLECT_ENCHANT_RACE("Verzauberungsrennen", EventCategory.COLLECTION),
// ═══════════════════════════════════════════════════════════
// FUN EVENTS (15)
// ═══════════════════════════════════════════════════════════
FUN_RANDOM_EFFECTS("Zufalls-Effekte", EventCategory.FUN),
FUN_TINY_PLAYERS("Mini-Spieler", EventCategory.FUN),
FUN_GIANT_PLAYERS("Riesen-Spieler", EventCategory.FUN),
FUN_INVISIBLE_PLAYERS("Unsichtbarkeit", EventCategory.FUN),
FUN_CHAOS_MODE("Chaos-Modus", EventCategory.FUN),
FUN_LIGHTNING_STORM("Blitz-Sturm", EventCategory.FUN),
FUN_TNT_RAIN("TNT-Regen", EventCategory.FUN),
FUN_ITEM_RAIN("Item-Regen", EventCategory.FUN),
FUN_DROP_PARTY("Drop-Party", EventCategory.FUN),
FUN_FIREWORK_SHOW("Feuerwerk-Show", EventCategory.FUN),
FUN_RANDOM_TELEPORT("Zufalls-TP", EventCategory.FUN),
FUN_SWAP_INVENTORIES("Inventar-Tausch", EventCategory.FUN),
FUN_REVERSE_GRAVITY("Umgekehrte Schwerkraft", EventCategory.FUN),
FUN_SPEED_BOOST("Geschwindigkeits-Boost", EventCategory.FUN),
FUN_BOUNCY_BLOCKS("Hüpfende Blöcke", EventCategory.FUN),
// ═══════════════════════════════════════════════════════════
// QUIZ & KNOWLEDGE EVENTS (5)
// ═══════════════════════════════════════════════════════════
QUIZ_MINECRAFT_TRIVIA("Minecraft-Quiz", EventCategory.QUIZ),
QUIZ_GENERAL_KNOWLEDGE("Allgemeinwissen-Quiz", EventCategory.QUIZ),
QUIZ_SPEED_QUIZ("Speed-Quiz", EventCategory.QUIZ),
QUIZ_CRAFTING_CHALLENGE("Crafting-Challenge", EventCategory.QUIZ),
QUIZ_MOB_QUIZ("Mob-Quiz", EventCategory.QUIZ),
// ═══════════════════════════════════════════════════════════
// ECONOMY EVENTS (5)
// ═══════════════════════════════════════════════════════════
ECONOMY_AUCTION("Auktion", EventCategory.ECONOMY),
ECONOMY_MARKET_RUSH("Markt-Rush", EventCategory.ECONOMY),
ECONOMY_LOTTERY("Lotterie", EventCategory.ECONOMY),
ECONOMY_TRADE_FRENZY("Handels-Frenzy", EventCategory.ECONOMY),
ECONOMY_BETTING("Wetten-Event", EventCategory.ECONOMY),
// ═══════════════════════════════════════════════════════════
// TEAM EVENTS (10)
// ═══════════════════════════════════════════════════════════
TEAM_RELAY_RACE("Staffellauf", EventCategory.TEAM),
TEAM_BUILD_BATTLE("Team Build Battle", EventCategory.TEAM),
TEAM_SURVIVAL("Team Survival", EventCategory.TEAM),
TEAM_TREASURE_HUNT("Team Schatzsuche", EventCategory.TEAM),
TEAM_QUIZ("Team-Quiz", EventCategory.TEAM),
TEAM_CAPTURE_POINTS("Punkte-Capture", EventCategory.TEAM),
TEAM_RESOURCE_RACE("Ressourcen-Rennen", EventCategory.TEAM),
TEAM_HIDE_AND_SEEK("Verstecken", EventCategory.TEAM),
TEAM_MURDER_MYSTERY("Murder Mystery", EventCategory.TEAM),
TEAM_COLOR_WAR("Farben-Krieg", EventCategory.TEAM),
// ═══════════════════════════════════════════════════════════
// CUSTOM (dynamisch erstellt)
// ═══════════════════════════════════════════════════════════
CUSTOM("Eigenes Event", EventCategory.CUSTOM);
private final String displayName;
private final EventCategory category;
EventType(String displayName, EventCategory category) {
this.displayName = displayName;
this.category = category;
}
public String getDisplayName() { return displayName; }
public EventCategory getCategory() { return category; }
}

View File

@@ -0,0 +1,56 @@
package dev.viper.eventengine.model;
import java.time.DayOfWeek;
import java.time.LocalTime;
import java.util.List;
/**
* Repräsentiert einen Zeitplan-Eintrag aus der config.yml.
*
* Beispiel-Config:
* schedule:
* - days: [MONDAY, FRIDAY]
* time: "18:00"
* event: "pvp_deathmatch"
* - days: [DAILY]
* time: "12:00"
* event: "RANDOM"
*/
public class ScheduleEntry {
public static final String RANDOM = "RANDOM";
private final List<DayOfWeek> days; // leer = täglich
private final LocalTime time;
private final String eventId; // EventDefinition-ID oder "RANDOM"
private final boolean everyDay;
public ScheduleEntry(List<DayOfWeek> days, LocalTime time, String eventId) {
this.days = days;
this.time = time;
this.eventId = eventId;
this.everyDay = days == null || days.isEmpty();
}
public boolean matchesNow(DayOfWeek day, LocalTime now) {
boolean dayMatch = everyDay || days.contains(day);
boolean timeMatch = now.getHour() == time.getHour()
&& now.getMinute() == time.getMinute();
return dayMatch && timeMatch;
}
public boolean isRandom() {
return RANDOM.equalsIgnoreCase(eventId);
}
public List<DayOfWeek> getDays() { return days; }
public LocalTime getTime() { return time; }
public String getEventId() { return eventId; }
public boolean isEveryDay() { return everyDay; }
@Override
public String toString() {
String dayStr = everyDay ? "Täglich" : days.toString();
return dayStr + " um " + time + "" + eventId;
}
}

View File

@@ -0,0 +1,140 @@
package dev.viper.eventengine.scheduler;
import dev.viper.eventengine.EventEngine;
import dev.viper.eventengine.model.EventDefinition;
import dev.viper.eventengine.model.ScheduleEntry;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Optional;
import java.util.logging.Logger;
/**
* Läuft jede Minute und prüft, ob ein geplantes Event feuern soll.
* Unterstützt:
* - Expliziten Zeitplan aus config.yml (schedule: [])
* - Intervall-Modus (use-interval: true, interval-minutes: 60)
*/
public class EventScheduler {
private final EventEngine plugin;
private final Logger log;
private BukkitTask minuteTask;
private BukkitTask intervalTask;
// Für Intervall-Modus: Zähler
private int minuteCounter = 0;
public EventScheduler(EventEngine plugin) {
this.plugin = plugin;
this.log = plugin.getLogger();
}
public void start() {
stop();
// Jede Minute: Zeitplan prüfen
minuteTask = new BukkitRunnable() {
@Override
public void run() {
tickSchedule();
}
}.runTaskTimer(plugin, 1200L, 1200L); // 1200 Ticks = 60 Sekunden
log.info("EventScheduler gestartet.");
// Intervall-Modus als Zusatz
if (plugin.getConfigManager().isUseInterval()) {
startIntervalMode();
}
}
private void startIntervalMode() {
int intervalMin = plugin.getConfigManager().getIntervalMinutes();
if (intervalMin <= 0) return;
long ticks = intervalMin * 60L * 20L;
intervalTask = new BukkitRunnable() {
@Override
public void run() {
if (plugin.getEventManager().isRunning()) return;
fireRandomOrDefault();
}
}.runTaskTimer(plugin, ticks, ticks);
log.info("Intervall-Modus: alle " + intervalMin + " Minuten.");
}
private void tickSchedule() {
LocalDateTime now = LocalDateTime.now();
DayOfWeek day = now.getDayOfWeek();
LocalTime time = now.toLocalTime();
List<ScheduleEntry> schedule = plugin.getConfigManager().getSchedule();
for (ScheduleEntry entry : schedule) {
if (!entry.matchesNow(day, time)) continue;
if (plugin.getEventManager().isRunning()) {
log.info("Zeitplan-Event übersprungen (läuft bereits): " + entry.getEventId());
continue;
}
// Ankündigung?
int announceBefore = plugin.getConfigManager().getAnnounceBefore();
if (announceBefore > 0) {
scheduleAnnouncement(entry, announceBefore);
}
fireScheduleEntry(entry);
}
}
private void scheduleAnnouncement(ScheduleEntry entry, int secondsBefore) {
String name = entry.isRandom() ? "ein zufälliges Event" : entry.getEventId();
long ticks = secondsBefore * 20L;
// Ankündigung JETZT senden (Event startet in X Sekunden)
// (Zeitplan feuert genau zur geplanten Minute)
plugin.getServer().broadcastMessage(
plugin.prefix() + "§e⏰ In §c" + secondsBefore + " Sekunden §estartet: §6" + name + "§e!");
}
private void fireScheduleEntry(ScheduleEntry entry) {
if (entry.isRandom()) {
fireRandomOrDefault();
return;
}
Optional<EventDefinition> defOpt = plugin.getEventRegistry().get(entry.getEventId());
if (defOpt.isPresent()) {
plugin.getEventManager().startEvent(defOpt.get(), null);
} else {
log.warning("Zeitplan-Event nicht gefunden: " + entry.getEventId() + " — feuere zufälliges.");
fireRandomOrDefault();
}
}
private void fireRandomOrDefault() {
if (plugin.getConfigManager().isRandomOnInterval()) {
Optional<EventDefinition> random = plugin.getEventRegistry().getWeightedRandom();
random.ifPresent(def -> plugin.getEventManager().startEvent(def, null));
} else {
String defaultId = plugin.getConfigManager().getDefaultEventId();
Optional<EventDefinition> def = plugin.getEventRegistry().get(defaultId);
def.ifPresent(d -> plugin.getEventManager().startEvent(d, null));
}
}
public void stop() {
if (minuteTask != null) { minuteTask.cancel(); minuteTask = null; }
if (intervalTask != null) { intervalTask.cancel(); intervalTask = null; }
}
public void restart() {
stop();
start();
}
}

View File

@@ -0,0 +1,75 @@
package dev.viper.eventengine.util;
import net.md_5.bungee.api.ChatColor;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Wandelt alle Farbformate um:
* &c → §c (Standard-Codes)
* &#FF5733 → Hex-Farbe (Paper / Spigot 1.16+)
* &x&F&F&5&7&3&3 → Bukkit-Hex-Format
* §c → bleibt §c (bereits konvertiert)
*/
public final class ColorUtil {
// &#RRGGBB oder #RRGGBB
private static final Pattern HEX_HASH = Pattern.compile("&#([0-9A-Fa-f]{6})|#([0-9A-Fa-f]{6})");
// &x&R&R&G&G&B&B (Bukkit-Hex-Format)
private static final Pattern HEX_BUKKIT = Pattern.compile("&x(&[0-9A-Fa-f]){6}");
private ColorUtil() {}
/**
* Konvertiert einen String mit beliebigen Farbcodes zu einem Minecraft-farbigen String.
*/
public static String color(String input) {
if (input == null) return "";
String s = input;
// 1. &#RRGGBB und #RRGGBB → §x§R§R§G§G§B§B
Matcher hexHash = HEX_HASH.matcher(s);
StringBuffer sb = new StringBuffer();
while (hexHash.find()) {
String hex = hexHash.group(1) != null ? hexHash.group(1) : hexHash.group(2);
hexHash.appendReplacement(sb, hexToBukkit(hex));
}
hexHash.appendTail(sb);
s = sb.toString();
// 2. &x&R&R&G&G&B&B → §x§R§R§G§G§B§B (falls jemand es schon im Bukkit-Format angibt)
Matcher hexBukkit = HEX_BUKKIT.matcher(s);
sb = new StringBuffer();
while (hexBukkit.find()) {
hexBukkit.appendReplacement(sb, hexBukkit.group().replace('&', '§'));
}
hexBukkit.appendTail(sb);
s = sb.toString();
// 3. &a&f, &0&9, &k&r → §-Codes
s = ChatColor.translateAlternateColorCodes('&', s);
return s;
}
/**
* Entfernt alle Farbcodes aus einem String (für Vergleiche, Logs etc.)
*/
public static String strip(String input) {
if (input == null) return "";
return ChatColor.stripColor(color(input));
}
/**
* Konvertiert einen 6-stelligen Hex-String (#RRGGBB ohne #) in das
* Minecraft §x§R§R§G§G§B§B Format.
*/
private static String hexToBukkit(String hex) {
StringBuilder result = new StringBuilder("§x");
for (char c : hex.toCharArray()) {
result.append('§').append(c);
}
return result.toString();
}
}

View File

@@ -0,0 +1,121 @@
# ═══════════════════════════════════════════════════════════════════
# EventEngine — Konfiguration
# Plugin von Viper | dev.viper.eventengine
# ═══════════════════════════════════════════════════════════════════
# ── Allgemeine Einstellungen ─────────────────────────────────────
settings:
# Prefix für alle Plugin-Nachrichten (& = Farb-Code)
prefix: "&8[&6EventEngine&8]&r "
# Logs Events in der Server-Konsole?
log-events: true
# Sekunden VOR dem Event-Start, wann die Ankündigung erfolgt
announce-before-seconds: 30
# Intervall-Modus: Startet automatisch alle X Minuten ein Event
# Nützlich wenn kein fester Zeitplan gewünscht ist
use-interval: false
interval-minutes: 60
# Welches Event beim Intervall? "RANDOM" = zufällig aus Rotation
default-event: "RANDOM"
# Zufälliges Event im Intervall-Modus?
random-on-interval: true
# ── Zeitplan ─────────────────────────────────────────────────────
# Jeder Eintrag hat:
# days: Wochentage (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY)
# Leer lassen oder "DAILY" für jeden Tag
# time: Uhrzeit im Format HH:MM (24h)
# event: Event-ID (aus /event list) oder "RANDOM"
#
# ─── Beispiel-Zeitplan ───────────────────────────────────────────
schedule:
# Täglich 12 Uhr: Zufälliges Event
- days: []
time: "12:00"
event: "RANDOM"
# Täglich 18 Uhr: PvP Deathmatch
- days: []
time: "18:00"
event: "pvp_deathmatch"
# Freitag & Samstag Abend: Hunger Games
- days: [FRIDAY, SATURDAY]
time: "20:00"
event: "pvp_hunger_games"
# Samstag Nachmittag: Build Battle
- days: [SATURDAY]
time: "15:00"
event: "build_battle"
# Sonntag Mittag: Drop Party
- days: [SUNDAY]
time: "14:00"
event: "fun_drop_party"
# Montag: Lotterie
- days: [MONDAY]
time: "19:00"
event: "economy_lottery"
# Mittwoch: Team Survival
- days: [WEDNESDAY]
time: "18:00"
event: "team_survival"
# ── Event-Overrides ───────────────────────────────────────────────
# Hier können einzelne eingebaute Events angepasst werden.
# OHNE diese Sektion gelten die Plugin-Defaults.
# Custom Events werden in custom_events.yml gespeichert.
#
# Beispiel:
# event-overrides:
# pvp_deathmatch:
# duration-seconds: 600
# min-players: 4
# rewards:
# - "eco give %player% 500"
# - "give %player% diamond 3"
# fun_drop_party:
# duration-seconds: 120
# announcement: "&6✦ &eDROP PARTY &7startet! Kommt alle auf den Spawn!"
event-overrides: {}
# ── Event-Regionen ────────────────────────────────────────────────
# Regionen können direkt hier oder ingame per Command gesetzt werden:
# /event region pos1 <event-id> → Erste Ecke (stehe an der Position)
# /event region pos2 <event-id> → Zweite Ecke → Region wird gespeichert
# /event region clear <event-id> → Region entfernen (gesamte Welt)
# /event region info <event-id> → Region anzeigen
#
# Für Custom Events wird die Region in custom_events.yml gespeichert.
# Für builtin Events hier in event-overrides eintragen:
#
# event-overrides:
# pvp_deathmatch:
# region:
# world: world
# min-x: -50
# min-y: 60
# min-z: -50
# max-x: 50
# max-y: 120
# max-z: 50
#
# ── Block-Schutz während Events ──────────────────────────────────
# TNT und Explosionen zerstören KEINE Blöcke solange ein Event läuft.
# Das gilt immer — unabhängig ob eine Region definiert ist oder nicht.
# Spieler (PvP-Schaden durch Explosionen) bleibt aktiv.
protection:
# Spieler können die Region während eines Events nicht verlassen
enforce-region-boundary: true
# TNT/Explosionen zerstören keine Blöcke während Events
no-explosion-block-damage: true
# Teilnehmer können nur innerhalb der Region Blöcke abbauen/setzen
restrict-block-interaction: true

View File

@@ -0,0 +1,33 @@
# ═══════════════════════════════════════════════════════════════════
# EventEngine — Custom Events
# Diese Datei wird automatisch verwaltet.
# Zum Erstellen: /event create <id>
# Zum Löschen: /event delete <id>
# ═══════════════════════════════════════════════════════════════════
#
# Du kannst Events auch manuell hier eintragen:
#
# events:
# mein_event:
# display-name: "Mein tolles Event"
# description: "Ein cooles Custom Event für unseren Server!"
# category: FUN # COMBAT, SURVIVAL, BUILDING, RACING, COLLECTION, FUN, QUIZ, ECONOMY, TEAM, CUSTOM
# duration-seconds: 300 # 0 = unbegrenzt
# min-players: 2
# max-players: 30
# announcement: "&6✦ &eMein Event &7startet! Seid dabei!"
# in-rotation: true # In der Zufalls-Rotation?
# weight: 2 # Gewichtung (höher = häufiger bei RANDOM)
# start-commands:
# - "broadcast Das Event startet!"
# - "title @a title {\"text\":\"EVENT START\",\"color\":\"gold\"}"
# end-commands:
# - "broadcast Das Event ist vorbei!"
# rewards: # Wird an JEDEN Teilnehmer ausgeführt (%player% = Spieler)
# - "eco give %player% 1000"
# - "give %player% golden_apple 5"
# settings: # Beliebige Custom-Einstellungen (für eigene Erweiterungen)
# pvp-enabled: false
# teleport-spawn: true
events: {}

View File

@@ -0,0 +1,24 @@
name: EventEngine
version: '${project.version}'
main: dev.viper.eventengine.EventEngine
api-version: '1.21'
description: 100+ Server Events mit Custom-Builder und Zeitplan
author: Viper
commands:
event:
description: Haupt-Befehl für EventEngine
usage: /event <start|stop|list|schedule|create|info|gui|reload>
aliases: [ee, events]
permission: eventengine.admin
permissions:
eventengine.admin:
description: Zugriff auf alle EventEngine-Befehle
default: op
eventengine.participate:
description: Darf an Events teilnehmen
default: true
eventengine.notify:
description: Erhält Event-Benachrichtigungen
default: true