Upload via GUI (14 Dateien)
This commit is contained in:
@@ -80,7 +80,7 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
}
|
||||
case "create" -> {
|
||||
if (args.length < 3) {
|
||||
plugin.send(p, "&cNutzung: /chunkinfo pvp create <Name>");
|
||||
plugin.send(p, "&cNutzung: /chunks pvp create <Name>");
|
||||
return;
|
||||
}
|
||||
String err = plugin.pvp.create(p, args[2]);
|
||||
@@ -88,7 +88,7 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
}
|
||||
case "delete" -> {
|
||||
if (args.length < 3) {
|
||||
plugin.send(p, "&cNutzung: /chunkinfo pvp delete <Name>");
|
||||
plugin.send(p, "&cNutzung: /chunks pvp delete <Name>");
|
||||
return;
|
||||
}
|
||||
plugin.send(p, plugin.pvp.delete(args[2]) ? "&aRegion geloescht." : "&cRegion nicht gefunden.");
|
||||
@@ -100,7 +100,7 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
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");
|
||||
default -> plugin.send(p, "&7/chunks pvp pos1 | pos2 | create <Name> | delete <Name> | list");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
for (Land land : shown) {
|
||||
describe(p, land);
|
||||
}
|
||||
p.sendMessage(plugin.line("&8Mehr: &7/chunkinfo top | skip | gift | queue | watch | temp"));
|
||||
p.sendMessage(plugin.line("&8Mehr: &7/chunks top | skip | gift | queue | watch | temp"));
|
||||
}
|
||||
|
||||
private void describe(Player p, Land land) {
|
||||
@@ -187,7 +187,7 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
p.sendMessage(plugin.line(sb + (locked.size() > 5 ? " ..." : "")));
|
||||
}
|
||||
if (plugin.getConfig().getBoolean("skip.enabled", true)) {
|
||||
p.sendMessage(plugin.line("&7Sofort freischalten: &e/chunkinfo skip &7(Preis: &e"
|
||||
p.sendMessage(plugin.line("&7Sofort freischalten: &e/chunks skip &7(Preis: &e"
|
||||
+ price(first - now) + "&7)"));
|
||||
}
|
||||
}
|
||||
@@ -253,7 +253,7 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
return Math.max(min, remainingMs / 3_600_000.0 * perHour);
|
||||
}
|
||||
|
||||
/** /chunkinfo skip [Land] [confirm] bzw. /chunkinfo gift <Land> [confirm] */
|
||||
/** /chunks skip [Land] [confirm] bzw. /chunks gift <Land> [confirm] */
|
||||
private void skip(Player p, String[] args, boolean gift) {
|
||||
if (!allowed(p, gift ? "gift" : "skip")) {
|
||||
return;
|
||||
@@ -270,7 +270,7 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
if (name != null) {
|
||||
land = findLand(name);
|
||||
} else if (gift) {
|
||||
plugin.send(p, "&cNutzung: /chunkinfo gift <Land> [confirm]");
|
||||
plugin.send(p, "&cNutzung: /chunks gift <Land> [confirm]");
|
||||
return;
|
||||
} else {
|
||||
land = plugin.landsOf(p.getUniqueId()).stream()
|
||||
@@ -304,7 +304,7 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
if (!confirm) {
|
||||
plugin.send(p, "&7Slot in &e" + land.getName() + " &7(noch &e" + TimeUtil.format(remaining)
|
||||
+ "&7) freischalten fuer &e" + money(price) + (fromLand ? " &7aus der Landkasse" : "")
|
||||
+ "&7. Bestaetigen: &e/chunkinfo " + (gift ? "gift " : "skip ") + land.getName() + " confirm");
|
||||
+ "&7. Bestaetigen: &e/chunks " + (gift ? "gift " : "skip ") + land.getName() + " confirm");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -361,12 +361,12 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
int cx = p.getLocation().getBlockX() >> 4;
|
||||
int cz = p.getLocation().getBlockZ() >> 4;
|
||||
if (plugin.lands.getLandByUnloadedChunk(w, cx, cz) != null) {
|
||||
plugin.send(p, "&cDieser Chunk ist schon geclaimt. Mit &e/chunkinfo watch &ckannst du ihn beobachten.");
|
||||
plugin.send(p, "&cDieser Chunk ist schon geclaimt. Mit &e/chunks watch &ckannst du ihn beobachten.");
|
||||
return;
|
||||
}
|
||||
List<Entry> mine = plugin.store.entries(Kind.QUEUE).stream().filter(e -> e.player().equals(p.getUniqueId())).toList();
|
||||
if (mine.size() >= plugin.getConfig().getInt("queue.max", 3)) {
|
||||
plugin.send(p, "&cDeine Warteschlange ist voll (&e/chunkinfo queue clear&c).");
|
||||
plugin.send(p, "&cDeine Warteschlange ist voll (&e/chunks queue clear&c).");
|
||||
return;
|
||||
}
|
||||
if (mine.stream().anyMatch(e -> e.at(w.getName(), cx, cz))) {
|
||||
@@ -400,12 +400,12 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
int cz = p.getLocation().getBlockZ() >> 4;
|
||||
Land holder = plugin.lands.getLandByUnloadedChunk(w, cx, cz);
|
||||
if (holder == null) {
|
||||
plugin.send(p, "&cDieser Chunk ist frei - du kannst ihn direkt claimen oder mit &e/chunkinfo queue &avormerken.");
|
||||
plugin.send(p, "&cDieser Chunk ist frei - du kannst ihn direkt claimen oder mit &e/chunks queue &avormerken.");
|
||||
return;
|
||||
}
|
||||
List<Entry> mine = plugin.store.entries(Kind.WATCH).stream().filter(e -> e.player().equals(p.getUniqueId())).toList();
|
||||
if (mine.size() >= plugin.getConfig().getInt("watch.max", 5)) {
|
||||
plugin.send(p, "&cDeine Watchlist ist voll (&e/chunkinfo watch clear&c).");
|
||||
plugin.send(p, "&cDeine Watchlist ist voll (&e/chunks watch clear&c).");
|
||||
return;
|
||||
}
|
||||
if (mine.stream().anyMatch(e -> e.at(w.getName(), cx, cz))) {
|
||||
@@ -469,7 +469,7 @@ final class InfoCommand implements CommandExecutor, TabCompleter {
|
||||
try {
|
||||
days = Integer.parseInt(arg);
|
||||
} catch (NumberFormatException ex) {
|
||||
plugin.send(p, "&cNutzung: /chunkinfo temp <Tage> | cancel | list");
|
||||
plugin.send(p, "&cNutzung: /chunks temp <Tage> | cancel | list");
|
||||
return;
|
||||
}
|
||||
int maxDays = plugin.getConfig().getInt("temp-claims.max-days", 30);
|
||||
|
||||
@@ -67,17 +67,17 @@ public final class LandsChunkInfo extends JavaPlugin implements Listener {
|
||||
vault = VaultHook.create();
|
||||
}
|
||||
if (vault == null) {
|
||||
getLogger().info("Vault/Economy nicht gefunden: Bezahlung nur aus der Landkasse moeglich, /chunkinfo gift ist deaktiviert.");
|
||||
getLogger().info("Vault/Economy nicht gefunden: Bezahlung nur aus der Landkasse moeglich, /chunks gift ist deaktiviert.");
|
||||
}
|
||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
||||
new ChunkExpansion(this).register();
|
||||
}
|
||||
|
||||
pvp = new PvpRegions(getDataFolder(), getLogger());
|
||||
pvp = new PvpRegions(this, getDataFolder(), getLogger());
|
||||
Bukkit.getPluginManager().registerEvents(pvp, this);
|
||||
Bukkit.getPluginManager().registerEvents(this, this);
|
||||
InfoCommand command = new InfoCommand(this);
|
||||
var cmd = getCommand("chunkinfo");
|
||||
var cmd = getCommand("chunks");
|
||||
if (cmd != null) {
|
||||
cmd.setExecutor(command);
|
||||
cmd.setTabCompleter(command);
|
||||
@@ -87,6 +87,9 @@ public final class LandsChunkInfo extends JavaPlugin implements Listener {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (pvp != null) {
|
||||
pvp.shutdown();
|
||||
}
|
||||
if (store != null) {
|
||||
store.save();
|
||||
}
|
||||
@@ -374,7 +377,7 @@ public final class LandsChunkInfo extends JavaPlugin implements Listener {
|
||||
if (lands.getLandByUnloadedChunk(w, e.x(), e.z()) == null) {
|
||||
store.remove(Kind.WATCH, e);
|
||||
send(p, "&aDer beobachtete Chunk &e" + e.x() + ", " + e.z() + " &a(" + e.world()
|
||||
+ ") ist jetzt frei! Mit &e/chunkinfo queue &akannst du ihn dir sichern.");
|
||||
+ ") ist jetzt frei! Mit &e/chunks queue &akannst du ihn dir sichern.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,15 @@ import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.event.player.PlayerVelocityEvent;
|
||||
import org.bukkit.event.entity.EntityKnockbackByEntityEvent;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -36,13 +45,20 @@ final class PvpRegions implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String BYPASS = "lands.bypass.attack_player";
|
||||
|
||||
/** Spieler, die gerade in einer PvP-Region getroffen wurden (fuer den Rueckstoss). */
|
||||
private final Map<UUID, Long> recentHit = new ConcurrentHashMap<>();
|
||||
private final JavaPlugin plugin;
|
||||
private final Map<UUID, PermissionAttachment> bypass = new ConcurrentHashMap<>();
|
||||
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) {
|
||||
PvpRegions(JavaPlugin plugin, File dataFolder, Logger log) {
|
||||
this.plugin = plugin;
|
||||
this.file = new File(dataFolder, "pvp-regions.yml");
|
||||
this.log = log;
|
||||
load();
|
||||
@@ -100,7 +116,7 @@ final class PvpRegions implements Listener {
|
||||
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.";
|
||||
return "Setze zuerst &e/chunks pvp pos1 &7und &e/chunks pvp pos2&7.";
|
||||
}
|
||||
if (a.getWorld() == null || !a.getWorld().equals(b.getWorld())) {
|
||||
return "Beide Punkte muessen in derselben Welt liegen.";
|
||||
@@ -109,6 +125,7 @@ final class PvpRegions implements Listener {
|
||||
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();
|
||||
refreshAll();
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -116,6 +133,7 @@ final class PvpRegions implements Listener {
|
||||
boolean removed = regions.remove(name.toLowerCase()) != null;
|
||||
if (removed) {
|
||||
save();
|
||||
refreshAll();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
@@ -137,6 +155,77 @@ final class PvpRegions implements Listener {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------- Lands-Bypass in Regionen
|
||||
|
||||
/** Gibt dem Spieler in einer PvP-Region das Lands-Recht zum Angreifen, sonst entzieht es es. */
|
||||
void refresh(Player p) {
|
||||
refreshAt(p, p.isOnline() && inRegion(p.getLocation()));
|
||||
}
|
||||
|
||||
void refreshAll() {
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
refresh(p);
|
||||
}
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
PermissionAttachment att = bypass.remove(p.getUniqueId());
|
||||
if (att != null) {
|
||||
try {
|
||||
p.removeAttachment(att);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// schon entfernt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onMove(PlayerMoveEvent e) {
|
||||
if (e.getTo() == null || regions.isEmpty() && bypass.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (e.getFrom().getBlockX() != e.getTo().getBlockX() || e.getFrom().getBlockZ() != e.getTo().getBlockZ()) {
|
||||
boolean inside = inRegion(e.getTo());
|
||||
if (inside != bypass.containsKey(e.getPlayer().getUniqueId())) {
|
||||
refreshAt(e.getPlayer(), inside);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onTeleport(PlayerTeleportEvent e) {
|
||||
refreshAt(e.getPlayer(), inRegion(e.getTo()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
refresh(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent e) {
|
||||
bypass.remove(e.getPlayer().getUniqueId());
|
||||
recentHit.remove(e.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
private void refreshAt(Player p, boolean inside) {
|
||||
PermissionAttachment att = bypass.get(p.getUniqueId());
|
||||
if (inside && att == null) {
|
||||
PermissionAttachment a = p.addAttachment(plugin);
|
||||
a.setPermission(BYPASS, true);
|
||||
bypass.put(p.getUniqueId(), a);
|
||||
} else if (!inside && att != null) {
|
||||
bypass.remove(p.getUniqueId());
|
||||
try {
|
||||
p.removeAttachment(att);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// schon entfernt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------- Event
|
||||
|
||||
/**
|
||||
@@ -145,7 +234,7 @@ final class PvpRegions implements Listener {
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onDamage(EntityDamageByEntityEvent e) {
|
||||
if (!e.isCancelled() || regions.isEmpty() || !(e.getEntity() instanceof Player victim)) {
|
||||
if (regions.isEmpty() || !(e.getEntity() instanceof Player victim)) {
|
||||
return;
|
||||
}
|
||||
Entity damager = e.getDamager();
|
||||
@@ -156,7 +245,30 @@ final class PvpRegions implements Listener {
|
||||
return;
|
||||
}
|
||||
if (inRegion(attacker.getLocation()) && inRegion(victim.getLocation())) {
|
||||
recentHit.put(victim.getUniqueId(), System.currentTimeMillis());
|
||||
if (e.isCancelled()) {
|
||||
e.setCancelled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Rueckstoss in der PvP-Region freigeben, falls Lands ihn fuer Land-Mitglieder unterdrueckt. */
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onKnockback(EntityKnockbackByEntityEvent e) {
|
||||
if (e.isCancelled() && e.getEntity() instanceof Player victim && isRecent(victim)) {
|
||||
e.setCancelled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onVelocity(PlayerVelocityEvent e) {
|
||||
if (e.isCancelled() && isRecent(e.getPlayer())) {
|
||||
e.setCancelled(false);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRecent(Player victim) {
|
||||
Long t = recentHit.get(victim.getUniqueId());
|
||||
return t != null && System.currentTimeMillis() - t < 500 && inRegion(victim.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user