Upload via GUI (14 Dateien)
This commit is contained in:
@@ -21,7 +21,7 @@ import java.util.UUID;
|
||||
|
||||
final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private static final List<String> SUBS = List.of("top", "skip", "gift", "queue", "watch", "temp", "reload");
|
||||
private static final List<String> SUBS = List.of("top", "skip", "gift", "queue", "watch", "temp", "pvp", "reload");
|
||||
|
||||
private final LandsChunkInfo plugin;
|
||||
|
||||
@@ -58,11 +58,52 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
case "queue" -> queue(p, args);
|
||||
case "watch" -> watch(p, args);
|
||||
case "temp" -> temp(p, args);
|
||||
case "pvp" -> pvp(p, args);
|
||||
default -> info(p, args);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void pvp(Player p, String[] args) {
|
||||
if (!allowed(p, "admin")) {
|
||||
return;
|
||||
}
|
||||
String action = args.length < 2 ? "" : args[1].toLowerCase(Locale.ROOT);
|
||||
switch (action) {
|
||||
case "pos1" -> {
|
||||
plugin.pvp.setPos1(p);
|
||||
plugin.send(p, "&aPunkt 1 gesetzt.");
|
||||
}
|
||||
case "pos2" -> {
|
||||
plugin.pvp.setPos2(p);
|
||||
plugin.send(p, "&aPunkt 2 gesetzt.");
|
||||
}
|
||||
case "create" -> {
|
||||
if (args.length < 3) {
|
||||
plugin.send(p, "&cNutzung: /chunkinfo pvp create <Name>");
|
||||
return;
|
||||
}
|
||||
String err = plugin.pvp.create(p, args[2]);
|
||||
plugin.send(p, err == null ? "&aPvP-Region &e" + args[2] + " &aerstellt." : "&c" + err);
|
||||
}
|
||||
case "delete" -> {
|
||||
if (args.length < 3) {
|
||||
plugin.send(p, "&cNutzung: /chunkinfo pvp delete <Name>");
|
||||
return;
|
||||
}
|
||||
plugin.send(p, plugin.pvp.delete(args[2]) ? "&aRegion geloescht." : "&cRegion nicht gefunden.");
|
||||
}
|
||||
case "list" -> {
|
||||
if (plugin.pvp.all().isEmpty()) {
|
||||
plugin.send(p, "&7Keine PvP-Regionen vorhanden.");
|
||||
}
|
||||
plugin.pvp.all().values().forEach(r -> p.sendMessage(plugin.line("&8- &e" + r.name() + " &7(" + r.world()
|
||||
+ ": " + r.minX() + "," + r.minZ() + " bis " + r.maxX() + "," + r.maxZ() + ")")));
|
||||
}
|
||||
default -> plugin.send(p, "&7/chunkinfo pvp pos1 | pos2 | create <Name> | delete <Name> | list");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean allowed(Player p, String perm) {
|
||||
if (p.hasPermission("landschunkinfo." + perm)) {
|
||||
return true;
|
||||
@@ -467,6 +508,13 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
switch (args[0].toLowerCase(Locale.ROOT)) {
|
||||
case "queue", "watch" -> out.addAll(args.length == 2 ? List.of("list", "clear") : List.of());
|
||||
case "temp" -> out.addAll(List.of("list", "cancel", "1", "7", "14", "30"));
|
||||
case "pvp" -> {
|
||||
if (args.length == 2) {
|
||||
out.addAll(List.of("pos1", "pos2", "create", "delete", "list"));
|
||||
} else if (args[1].equalsIgnoreCase("delete")) {
|
||||
out.addAll(plugin.pvp.names());
|
||||
}
|
||||
}
|
||||
case "skip", "gift" -> {
|
||||
out.add("confirm");
|
||||
plugin.landsOf(p.getUniqueId()).forEach(l -> out.add(l.getName()));
|
||||
|
||||
@@ -49,6 +49,7 @@ public final class LandsChunkInfo extends JavaPlugin implements Listener {
|
||||
LandsIntegration lands;
|
||||
LockStore store;
|
||||
VaultHook vault;
|
||||
PvpRegions pvp;
|
||||
|
||||
private long cooldownMillis;
|
||||
private long lastTick = System.currentTimeMillis();
|
||||
@@ -72,6 +73,8 @@ public final class LandsChunkInfo extends JavaPlugin implements Listener {
|
||||
new ChunkExpansion(this).register();
|
||||
}
|
||||
|
||||
pvp = new PvpRegions(getDataFolder(), getLogger());
|
||||
Bukkit.getPluginManager().registerEvents(pvp, this);
|
||||
Bukkit.getPluginManager().registerEvents(this, this);
|
||||
InfoCommand command = new InfoCommand(this);
|
||||
var cmd = getCommand("chunkinfo");
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
package de.landschunkinfo;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* PvP-Regionen: In diesen Bereichen darf gekaempft werden, auch wenn Lands den Angriff
|
||||
* (z. B. wegen gemeinsamem Land in der Wildnis) blockiert. Gespeichert in pvp-regions.yml.
|
||||
* Die Regionen sind Rechtecke ueber die gesamte Hoehe.
|
||||
*/
|
||||
final class PvpRegions implements Listener {
|
||||
|
||||
record Region(String name, String world, int minX, int minZ, int maxX, int maxZ) {
|
||||
boolean contains(Location l) {
|
||||
return l.getWorld() != null && l.getWorld().getName().equals(world)
|
||||
&& l.getBlockX() >= minX && l.getBlockX() <= maxX
|
||||
&& l.getBlockZ() >= minZ && l.getBlockZ() <= maxZ;
|
||||
}
|
||||
}
|
||||
|
||||
private final File file;
|
||||
private final Logger log;
|
||||
private final Map<String, Region> regions = new LinkedHashMap<>();
|
||||
private final Map<UUID, Location> pos1 = new ConcurrentHashMap<>();
|
||||
private final Map<UUID, Location> pos2 = new ConcurrentHashMap<>();
|
||||
|
||||
PvpRegions(File dataFolder, Logger log) {
|
||||
this.file = new File(dataFolder, "pvp-regions.yml");
|
||||
this.log = log;
|
||||
load();
|
||||
}
|
||||
|
||||
private void load() {
|
||||
regions.clear();
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
YamlConfiguration y = YamlConfiguration.loadConfiguration(file);
|
||||
ConfigurationSection sec = y.getConfigurationSection("regions");
|
||||
if (sec == null) {
|
||||
return;
|
||||
}
|
||||
for (String name : sec.getKeys(false)) {
|
||||
ConfigurationSection r = sec.getConfigurationSection(name);
|
||||
if (r == null) {
|
||||
continue;
|
||||
}
|
||||
regions.put(name.toLowerCase(), new Region(name, r.getString("world", ""),
|
||||
r.getInt("min-x"), r.getInt("min-z"), r.getInt("max-x"), r.getInt("max-z")));
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void save() {
|
||||
YamlConfiguration y = new YamlConfiguration();
|
||||
for (Region r : regions.values()) {
|
||||
String base = "regions." + r.name() + ".";
|
||||
y.set(base + "world", r.world());
|
||||
y.set(base + "min-x", r.minX());
|
||||
y.set(base + "min-z", r.minZ());
|
||||
y.set(base + "max-x", r.maxX());
|
||||
y.set(base + "max-z", r.maxZ());
|
||||
}
|
||||
try {
|
||||
y.save(file);
|
||||
} catch (IOException e) {
|
||||
log.warning("pvp-regions.yml konnte nicht gespeichert werden: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ Verwaltung
|
||||
|
||||
void setPos1(Player p) {
|
||||
pos1.put(p.getUniqueId(), p.getLocation());
|
||||
}
|
||||
|
||||
void setPos2(Player p) {
|
||||
pos2.put(p.getUniqueId(), p.getLocation());
|
||||
}
|
||||
|
||||
/** @return null bei Erfolg, sonst Fehlertext */
|
||||
String create(Player p, String name) {
|
||||
Location a = pos1.get(p.getUniqueId());
|
||||
Location b = pos2.get(p.getUniqueId());
|
||||
if (a == null || b == null) {
|
||||
return "Setze zuerst &e/chunkinfo pvp pos1 &7und &e/chunkinfo pvp pos2&7.";
|
||||
}
|
||||
if (a.getWorld() == null || !a.getWorld().equals(b.getWorld())) {
|
||||
return "Beide Punkte muessen in derselben Welt liegen.";
|
||||
}
|
||||
regions.put(name.toLowerCase(), new Region(name, a.getWorld().getName(),
|
||||
Math.min(a.getBlockX(), b.getBlockX()), Math.min(a.getBlockZ(), b.getBlockZ()),
|
||||
Math.max(a.getBlockX(), b.getBlockX()), Math.max(a.getBlockZ(), b.getBlockZ())));
|
||||
save();
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean delete(String name) {
|
||||
boolean removed = regions.remove(name.toLowerCase()) != null;
|
||||
if (removed) {
|
||||
save();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
Map<String, Region> all() {
|
||||
return Collections.unmodifiableMap(regions);
|
||||
}
|
||||
|
||||
Set<String> names() {
|
||||
return regions.values().stream().map(Region::name).collect(java.util.stream.Collectors.toSet());
|
||||
}
|
||||
|
||||
boolean inRegion(Location l) {
|
||||
for (Region r : regions.values()) {
|
||||
if (r.contains(l)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------- Event
|
||||
|
||||
/**
|
||||
* Laeuft nach Lands (HIGHEST): Wenn Angreifer und Opfer beide in einer PvP-Region stehen,
|
||||
* wird ein von Lands abgebrochener Schaden wieder freigegeben.
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onDamage(EntityDamageByEntityEvent e) {
|
||||
if (!e.isCancelled() || regions.isEmpty() || !(e.getEntity() instanceof Player victim)) {
|
||||
return;
|
||||
}
|
||||
Entity damager = e.getDamager();
|
||||
if (damager instanceof Projectile proj && proj.getShooter() instanceof Entity shooter) {
|
||||
damager = shooter;
|
||||
}
|
||||
if (!(damager instanceof Player attacker) || attacker.equals(victim)) {
|
||||
return;
|
||||
}
|
||||
if (inRegion(attacker.getLocation()) && inRegion(victim.getLocation())) {
|
||||
e.setCancelled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user