Upload folder via GUI - src
This commit is contained in:
214
src/main/java/de/sudoplugin/SudoCommand.java
Normal file
214
src/main/java/de/sudoplugin/SudoCommand.java
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
package de.sudoplugin;
|
||||||
|
|
||||||
|
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.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class SudoCommand implements CommandExecutor, TabCompleter {
|
||||||
|
|
||||||
|
private final SudoPlugin plugin;
|
||||||
|
private final Map<String, String> commandMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
// Cooldown: UUID des Ausführers -> Zeitpunkt letzter Nutzung (ms)
|
||||||
|
private final Map<UUID, Map<UUID, Long>> cooldownPerTarget = new HashMap<>();
|
||||||
|
private final Map<UUID, Long> cooldownGlobal = new HashMap<>();
|
||||||
|
|
||||||
|
public SudoCommand(SudoPlugin plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
loadCommands();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadCommands() {
|
||||||
|
commandMap.clear();
|
||||||
|
File file = new File(plugin.getDataFolder(), "commands.yml");
|
||||||
|
if (!file.exists()) {
|
||||||
|
plugin.getLogger().warning("commands.yml nicht gefunden!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file);
|
||||||
|
for (Map<?, ?> entry : cfg.getMapList("commands")) {
|
||||||
|
String name = (String) entry.get("name");
|
||||||
|
String args = entry.containsKey("args") ? (String) entry.get("args") : "";
|
||||||
|
if (name != null && !name.isBlank())
|
||||||
|
commandMap.put(name.toLowerCase(), args == null ? "" : args.toLowerCase());
|
||||||
|
}
|
||||||
|
plugin.getLogger().info(commandMap.size() + " Befehle aus commands.yml geladen.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
|
||||||
|
// /sudo reload
|
||||||
|
if (args.length == 1 && args[0].equalsIgnoreCase("reload")) {
|
||||||
|
if (!sender.hasPermission("sudoplugin.use")) {
|
||||||
|
sender.sendMessage(plugin.msg("no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
plugin.reloadConfig();
|
||||||
|
plugin.openLogFile();
|
||||||
|
loadCommands();
|
||||||
|
sender.sendMessage(plugin.msg("reload-success"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 2) {
|
||||||
|
sender.sendMessage(plugin.msg("usage"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Konsolen-Check
|
||||||
|
boolean isConsole = !(sender instanceof Player);
|
||||||
|
if (isConsole && !plugin.getConfig().getBoolean("security.allow-console", true)) {
|
||||||
|
sender.sendMessage(plugin.msg("no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isConsole && !sender.hasPermission("sudoplugin.use")) {
|
||||||
|
sender.sendMessage(plugin.msg("no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player target = Bukkit.getPlayer(args[0]);
|
||||||
|
if (target == null) {
|
||||||
|
sender.sendMessage(plugin.msg("player-not-found", "{player}", args[0]));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Self-sudo Check
|
||||||
|
if (!isConsole && !plugin.getConfig().getBoolean("security.allow-self-sudo", false)) {
|
||||||
|
if (((Player) sender).getUniqueId().equals(target.getUniqueId())) {
|
||||||
|
sender.sendMessage(plugin.msg("self-sudo-denied"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OP-Check
|
||||||
|
if (!isConsole && !plugin.getConfig().getBoolean("security.allow-sudo-on-op", false)) {
|
||||||
|
if (target.isOp() && !sender.isOp()) {
|
||||||
|
sender.sendMessage(plugin.msg("op-sudo-denied"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blocked-Commands Check
|
||||||
|
List<String> blocked = plugin.getConfig().getStringList("security.blocked-commands");
|
||||||
|
if (blocked.stream().anyMatch(b -> b.equalsIgnoreCase(args[1]))) {
|
||||||
|
sender.sendMessage(plugin.msg("command-blocked"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cooldown Check
|
||||||
|
if (!isConsole) {
|
||||||
|
Player senderPlayer = (Player) sender;
|
||||||
|
String bypassPerm = plugin.getConfig().getString("cooldown.bypass-permission", "sudoplugin.cooldown.bypass");
|
||||||
|
int cooldownSecs = plugin.getConfig().getInt("cooldown.seconds", 0);
|
||||||
|
boolean perTarget = plugin.getConfig().getBoolean("cooldown.per-target", false);
|
||||||
|
|
||||||
|
if (cooldownSecs > 0 && !senderPlayer.hasPermission(bypassPerm)) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
long last = 0;
|
||||||
|
|
||||||
|
if (perTarget) {
|
||||||
|
last = cooldownPerTarget
|
||||||
|
.computeIfAbsent(senderPlayer.getUniqueId(), k -> new HashMap<>())
|
||||||
|
.getOrDefault(target.getUniqueId(), 0L);
|
||||||
|
} else {
|
||||||
|
last = cooldownGlobal.getOrDefault(senderPlayer.getUniqueId(), 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
long diff = (now - last) / 1000;
|
||||||
|
if (diff < cooldownSecs) {
|
||||||
|
long remaining = cooldownSecs - diff;
|
||||||
|
sender.sendMessage(plugin.msg("cooldown-active", "{seconds}", String.valueOf(remaining)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cooldown setzen
|
||||||
|
if (perTarget) {
|
||||||
|
cooldownPerTarget.computeIfAbsent(senderPlayer.getUniqueId(), k -> new HashMap<>())
|
||||||
|
.put(target.getUniqueId(), now);
|
||||||
|
} else {
|
||||||
|
cooldownGlobal.put(senderPlayer.getUniqueId(), now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Befehl zusammenbauen & ausführen
|
||||||
|
StringBuilder fullCommand = new StringBuilder(args[1]);
|
||||||
|
for (int i = 2; i < args.length; i++) fullCommand.append(" ").append(args[i]);
|
||||||
|
String commandToRun = fullCommand.toString();
|
||||||
|
|
||||||
|
target.performCommand(commandToRun);
|
||||||
|
|
||||||
|
// Sender benachrichtigen
|
||||||
|
if (plugin.getConfig().getBoolean("notifications.notify-sender", true)) {
|
||||||
|
sender.sendMessage(plugin.msg("success", "{cmd}", commandToRun, "{player}", target.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zielspieler benachrichtigen
|
||||||
|
if (plugin.getConfig().getBoolean("notifications.notify-target", false)) {
|
||||||
|
String notifyMsg = SudoPlugin.colorize(
|
||||||
|
plugin.getConfig().getString("notifications.notify-message", "&eEin Admin hat einen Befehl als du ausgeführt."));
|
||||||
|
target.sendMessage(notifyMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Konsolen-Log
|
||||||
|
String logEntry = sender.getName() + " -> /" + commandToRun + " als " + target.getName();
|
||||||
|
if (plugin.getConfig().getBoolean("notifications.log-to-console", true)) {
|
||||||
|
plugin.getLogger().info(logEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Datei-Log
|
||||||
|
if (plugin.getConfig().getBoolean("notifications.log-to-file", false)) {
|
||||||
|
plugin.writeLog(logEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||||
|
boolean isConsole = !(sender instanceof Player);
|
||||||
|
if (!isConsole && !sender.hasPermission("sudoplugin.use")) return new ArrayList<>();
|
||||||
|
|
||||||
|
if (args.length == 1) {
|
||||||
|
return Bukkit.getOnlinePlayers().stream()
|
||||||
|
.map(Player::getName)
|
||||||
|
.filter(n -> n.toLowerCase().startsWith(args[0].toLowerCase()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length == 2) {
|
||||||
|
List<String> blocked = plugin.getConfig().getStringList("security.blocked-commands");
|
||||||
|
return commandMap.keySet().stream()
|
||||||
|
.filter(c -> c.startsWith(args[1].toLowerCase()))
|
||||||
|
.filter(c -> blocked.stream().noneMatch(b -> b.equalsIgnoreCase(c)))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length == 3) {
|
||||||
|
String argType = commandMap.getOrDefault(args[1].toLowerCase(), "");
|
||||||
|
if (argType.equals("player")) {
|
||||||
|
return Bukkit.getOnlinePlayers().stream()
|
||||||
|
.map(Player::getName)
|
||||||
|
.filter(n -> n.toLowerCase().startsWith(args[2].toLowerCase()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
if (argType.equals("gamemode")) {
|
||||||
|
return Arrays.asList("survival", "creative", "adventure", "spectator").stream()
|
||||||
|
.filter(m -> m.startsWith(args[2].toLowerCase()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
72
src/main/java/de/sudoplugin/SudoPlugin.java
Normal file
72
src/main/java/de/sudoplugin/SudoPlugin.java
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package de.sudoplugin;
|
||||||
|
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
public class SudoPlugin extends JavaPlugin {
|
||||||
|
|
||||||
|
private PrintWriter logWriter;
|
||||||
|
private static final DateTimeFormatter LOG_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
saveDefaultConfig();
|
||||||
|
if (!new File(getDataFolder(), "commands.yml").exists()) {
|
||||||
|
saveResource("commands.yml", false);
|
||||||
|
}
|
||||||
|
openLogFile();
|
||||||
|
|
||||||
|
SudoCommand sudoCommand = new SudoCommand(this);
|
||||||
|
getCommand("sudo").setExecutor(sudoCommand);
|
||||||
|
getCommand("sudo").setTabCompleter(sudoCommand);
|
||||||
|
getLogger().info("SudoPlugin aktiviert!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
if (logWriter != null) logWriter.close();
|
||||||
|
getLogger().info("SudoPlugin deaktiviert!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openLogFile() {
|
||||||
|
if (logWriter != null) { logWriter.close(); logWriter = null; }
|
||||||
|
if (!getConfig().getBoolean("notifications.log-to-file", false)) return;
|
||||||
|
try {
|
||||||
|
File logFile = new File(getDataFolder(), "sudo.log");
|
||||||
|
logWriter = new PrintWriter(new FileWriter(logFile, true), true);
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLogger().warning("Konnte sudo.log nicht öffnen: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeLog(String entry) {
|
||||||
|
if (logWriter == null) return;
|
||||||
|
logWriter.println("[" + LocalDateTime.now().format(LOG_FORMAT) + "] " + entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gibt eine formatierte Nachricht aus der config zurück. */
|
||||||
|
public String msg(String key) {
|
||||||
|
String prefix = colorize(getConfig().getString("messages.prefix", "&8[&cSudo&8] &r"));
|
||||||
|
String message = colorize(getConfig().getString("messages." + key, "&c[" + key + " fehlt in config.yml]"));
|
||||||
|
return prefix + message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Wie msg(), aber mit Platzhalter-Ersetzung. */
|
||||||
|
public String msg(String key, String... replacements) {
|
||||||
|
String m = msg(key);
|
||||||
|
for (int i = 0; i + 1 < replacements.length; i += 2) {
|
||||||
|
m = m.replace(replacements[i], replacements[i + 1]);
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String colorize(String s) {
|
||||||
|
return org.bukkit.ChatColor.translateAlternateColorCodes('&', s);
|
||||||
|
}
|
||||||
|
}
|
||||||
63
src/main/resources/commands.yml
Normal file
63
src/main/resources/commands.yml
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# SudoPlugin - Verfügbare Befehle für Tab-Completion
|
||||||
|
# Hier kannst du Befehle hinzufügen oder entfernen.
|
||||||
|
#
|
||||||
|
# Format:
|
||||||
|
# - name: Befehlsname (ohne /)
|
||||||
|
# args: "player" # optionaler Typ für arg3-Completion
|
||||||
|
# # Mögliche Werte: player, gamemode, leer lassen wenn nichts
|
||||||
|
#
|
||||||
|
# Beispiel eigener Befehl:
|
||||||
|
# - name: meinbefehl
|
||||||
|
# args: ""
|
||||||
|
|
||||||
|
commands:
|
||||||
|
- name: msg
|
||||||
|
args: player
|
||||||
|
- name: tell
|
||||||
|
args: player
|
||||||
|
- name: w
|
||||||
|
args: player
|
||||||
|
- name: whisper
|
||||||
|
args: player
|
||||||
|
- name: me
|
||||||
|
args: ""
|
||||||
|
- name: say
|
||||||
|
args: ""
|
||||||
|
- name: tp
|
||||||
|
args: player
|
||||||
|
- name: tpa
|
||||||
|
args: player
|
||||||
|
- name: tpaccept
|
||||||
|
args: ""
|
||||||
|
- name: tpdeny
|
||||||
|
args: ""
|
||||||
|
- name: gamemode
|
||||||
|
args: gamemode
|
||||||
|
- name: give
|
||||||
|
args: ""
|
||||||
|
- name: fly
|
||||||
|
args: ""
|
||||||
|
- name: speed
|
||||||
|
args: ""
|
||||||
|
- name: heal
|
||||||
|
args: ""
|
||||||
|
- name: feed
|
||||||
|
args: ""
|
||||||
|
- name: spawn
|
||||||
|
args: ""
|
||||||
|
- name: home
|
||||||
|
args: ""
|
||||||
|
- name: sethome
|
||||||
|
args: ""
|
||||||
|
- name: warp
|
||||||
|
args: ""
|
||||||
|
- name: kit
|
||||||
|
args: ""
|
||||||
|
- name: pay
|
||||||
|
args: player
|
||||||
|
- name: balance
|
||||||
|
args: ""
|
||||||
|
- name: seen
|
||||||
|
args: player
|
||||||
|
- name: ignore
|
||||||
|
args: player
|
||||||
69
src/main/resources/config.yml
Normal file
69
src/main/resources/config.yml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# -----------------------------------------------
|
||||||
|
# SudoPlugin - Konfiguration
|
||||||
|
# -----------------------------------------------
|
||||||
|
|
||||||
|
# Sprache der Plugin-Nachrichten
|
||||||
|
# Verfügbare Werte: de, en
|
||||||
|
language: de
|
||||||
|
|
||||||
|
# -----------------------------------------------
|
||||||
|
# BENACHRICHTIGUNGEN
|
||||||
|
# -----------------------------------------------
|
||||||
|
notifications:
|
||||||
|
# Soll der Zielspieler informiert werden wenn ein Befehl als er ausgeführt wird?
|
||||||
|
notify-target: false
|
||||||
|
notify-message: "&eEin Admin hat einen Befehl als du ausgeführt."
|
||||||
|
|
||||||
|
# Soll der ausführende Spieler eine Bestätigungsnachricht sehen?
|
||||||
|
notify-sender: true
|
||||||
|
|
||||||
|
# Soll in der Konsole geloggt werden?
|
||||||
|
log-to-console: true
|
||||||
|
|
||||||
|
# Soll ein Eintrag in eine Log-Datei geschrieben werden? (plugins/SudoPlugin/sudo.log)
|
||||||
|
log-to-file: false
|
||||||
|
|
||||||
|
# -----------------------------------------------
|
||||||
|
# BERECHTIGUNGEN & SICHERHEIT
|
||||||
|
# -----------------------------------------------
|
||||||
|
security:
|
||||||
|
# Kann ein Spieler /sudo auf sich selbst ausführen?
|
||||||
|
allow-self-sudo: false
|
||||||
|
|
||||||
|
# Können Spieler mit sudoplugin.use auch andere OPs mit sudo ansprechen?
|
||||||
|
allow-sudo-on-op: false
|
||||||
|
|
||||||
|
# Kann /sudo auch von der Konsole aus genutzt werden?
|
||||||
|
allow-console: true
|
||||||
|
|
||||||
|
# Bestimmte Befehle komplett sperren (werden nie ausgeführt, egal was in commands.yml steht)
|
||||||
|
# Beispiel: [op, deop, stop]
|
||||||
|
blocked-commands: []
|
||||||
|
|
||||||
|
# -----------------------------------------------
|
||||||
|
# COOLDOWN
|
||||||
|
# -----------------------------------------------
|
||||||
|
cooldown:
|
||||||
|
# Cooldown zwischen sudo-Befehlen in Sekunden (0 = deaktiviert)
|
||||||
|
seconds: 0
|
||||||
|
|
||||||
|
# Soll der Cooldown pro Zielspieler gelten (true) oder global pro Ausführer (false)?
|
||||||
|
per-target: false
|
||||||
|
|
||||||
|
# Spieler mit dieser Permission sind vom Cooldown ausgenommen
|
||||||
|
bypass-permission: sudoplugin.cooldown.bypass
|
||||||
|
|
||||||
|
# -----------------------------------------------
|
||||||
|
# NACHRICHTEN-FORMAT
|
||||||
|
# -----------------------------------------------
|
||||||
|
messages:
|
||||||
|
prefix: "&8[&cSudo&8] &r"
|
||||||
|
no-permission: "&cDu hast keine Berechtigung."
|
||||||
|
player-not-found: "&cSpieler '{player}' ist nicht online."
|
||||||
|
usage: "&cVerwendung: /sudo <spieler> <befehl> [argumente...]"
|
||||||
|
success: "&aBefehl &f/{cmd} &awurde als &f{player} &aausgeführt."
|
||||||
|
self-sudo-denied: "&cDu kannst /sudo nicht auf dich selbst anwenden."
|
||||||
|
op-sudo-denied: "&cDu kannst /sudo nicht auf einen OP anwenden."
|
||||||
|
command-blocked: "&cDieser Befehl ist in der Konfiguration gesperrt."
|
||||||
|
cooldown-active: "&cBitte warte noch &f{seconds}s &cbevor du /sudo erneut nutzt."
|
||||||
|
reload-success: "&aKonfiguration erfolgreich neu geladen."
|
||||||
17
src/main/resources/plugin.yml
Normal file
17
src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
name: SudoPlugin
|
||||||
|
version: 1.0.0
|
||||||
|
main: de.sudoplugin.SudoPlugin
|
||||||
|
api-version: 1.20
|
||||||
|
author: M_Viper
|
||||||
|
description: Lets admins run commands as other players
|
||||||
|
|
||||||
|
commands:
|
||||||
|
sudo:
|
||||||
|
description: Execute a command as another player
|
||||||
|
usage: /sudo <player> <command> [args...]
|
||||||
|
permission: sudoplugin.use
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
sudoplugin.use:
|
||||||
|
description: Allows use of the /sudo command
|
||||||
|
default: op
|
||||||
Reference in New Issue
Block a user