From ac7e04829e4f203fc4acb92fe4a8bd06215f650f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Sat, 20 Dec 2025 17:46:02 +0100 Subject: [PATCH 01/12] introduced `ReportCreatedListener`, updated `ReportCreatedEvent` to use UUIDs for reporter and reported, and improved admin notifications for new reports --- .../metaGameplay/report/Report.java | 8 ++++++ .../report/ReportCreatedListener.java | 26 +++++++++++++++++++ .../antiInventoryMove/AntiInventoryMove.java | 1 + .../api/server/hooks/impl/WebsiteHook.java | 4 ++- .../spawn/core/event/ReportCreatedEvent.java | 4 ++- 5 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/ReportCreatedListener.java diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java index 543abe0..5a2098b 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java @@ -16,6 +16,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; +import org.bukkit.event.Listener; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -178,6 +179,13 @@ public class Report extends Appliance { issuer.sendMessage(component.build()); } + @Override + protected @NotNull List listeners() { + return List.of( + new ReportCreatedListener() + ); + } + @Override @NotNull protected List> commands() { diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/ReportCreatedListener.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/ReportCreatedListener.java new file mode 100644 index 0000000..8a6c988 --- /dev/null +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/ReportCreatedListener.java @@ -0,0 +1,26 @@ +package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import eu.mhsl.craftattack.spawn.core.event.ReportCreatedEvent; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.event.EventHandler; + +public class ReportCreatedListener extends ApplianceListener { + @EventHandler + public void onReport(ReportCreatedEvent event) { + OfflinePlayer reporter = Bukkit.getOfflinePlayer(event.getReport().reporter()); + OfflinePlayer reported = Bukkit.getOfflinePlayer(event.getReport().reported()); + + Component message = Component.text( + "\uD83D\uDD14 Neuer Report von %s gegen %s: %s".formatted(reporter.getName(), reported.getName(), event.getReport().reason()), + NamedTextColor.YELLOW + ); + + Bukkit.getOnlinePlayers().stream() + .filter(player -> player.hasPermission("admin")) + .forEach(player -> player.sendMessage(message)); + } +} diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiInventoryMove/AntiInventoryMove.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiInventoryMove/AntiInventoryMove.java index 2b7a21d..ee99f6a 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiInventoryMove/AntiInventoryMove.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiInventoryMove/AntiInventoryMove.java @@ -11,6 +11,7 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +@Appliance.Flags(enabled = false) public class AntiInventoryMove extends Appliance { private static final long errorTimeMargin = Ticks.SINGLE_TICK_DURATION_MS * 2; diff --git a/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/server/hooks/impl/WebsiteHook.java b/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/server/hooks/impl/WebsiteHook.java index 73e7552..c75d02b 100644 --- a/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/server/hooks/impl/WebsiteHook.java +++ b/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/server/hooks/impl/WebsiteHook.java @@ -28,14 +28,16 @@ public class WebsiteHook extends HttpHook { return HttpServer.nothing; })); - record CreatedReport(String reporter, String reported, String reason) {} + record CreatedReport(UUID reporter, UUID reported, String reason) {} this.addAction("report", new JsonAction<>(CreatedReport.class, createdReport -> { + Main.logger().info(String.format("New Report from Hook: (%s) Reporter: %s Reported: %s", createdReport.reason, createdReport.reporter, createdReport.reported)); SpawnEvent.call(new ReportCreatedEvent(new ReportCreatedEvent.CreatedReport(createdReport.reporter, createdReport.reported, createdReport.reason))); return HttpServer.nothing; })); record CreatedStrike(UUID uuid) {} this.addAction("strike", new JsonAction<>(CreatedStrike.class, createdStrike -> { + Main.logger().info(String.format("New Strike from Hook! (User %s)", createdStrike.uuid)); SpawnEvent.call(new StrikeCreatedEvent(new StrikeCreatedEvent.CreatedStrike(createdStrike.uuid))); return HttpServer.nothing; })); diff --git a/core/src/main/java/eu/mhsl/craftattack/spawn/core/event/ReportCreatedEvent.java b/core/src/main/java/eu/mhsl/craftattack/spawn/core/event/ReportCreatedEvent.java index 777c02c..6b41367 100644 --- a/core/src/main/java/eu/mhsl/craftattack/spawn/core/event/ReportCreatedEvent.java +++ b/core/src/main/java/eu/mhsl/craftattack/spawn/core/event/ReportCreatedEvent.java @@ -4,6 +4,8 @@ import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; +import java.util.UUID; + public class ReportCreatedEvent extends Event { private static final HandlerList HANDLERS = new HandlerList(); @Override @@ -15,7 +17,7 @@ public class ReportCreatedEvent extends Event { return HANDLERS; } - public record CreatedReport(String reporter, String reported, String reason) {} + public record CreatedReport(UUID reporter, UUID reported, String reason) {} private final CreatedReport report; public ReportCreatedEvent(CreatedReport report) { From a257b604ea9a5f1f03205dccc24b25a38ce0f1d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Sun, 21 Dec 2025 09:32:40 +0100 Subject: [PATCH 02/12] updated `InventoryTrackerListener` to monitor `InventoryOpenEvent` with high priority and prevent processing of cancelled events --- .../security/antiInventoryMove/InventoryTrackerListener.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiInventoryMove/InventoryTrackerListener.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiInventoryMove/InventoryTrackerListener.java index 0c5c89f..7e064d4 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiInventoryMove/InventoryTrackerListener.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiInventoryMove/InventoryTrackerListener.java @@ -3,13 +3,15 @@ package eu.mhsl.craftattack.spawn.common.appliances.security.antiInventoryMove; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryOpenEvent; class InventoryTrackerListener extends ApplianceListener { - @EventHandler + @EventHandler(priority = EventPriority.MONITOR) public void onOpen(InventoryOpenEvent event) { if(!(event.getPlayer() instanceof Player player)) return; + if(event.isCancelled()) return; this.getAppliance().setInvOpen(player, true); } From 71f2da8e99742e4be33aa3255f7c34987d70e4ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Mon, 22 Dec 2025 18:44:22 +0100 Subject: [PATCH 03/12] introduced `AntiIllegalSignCharacters` appliance to prevent usage of illegal characters in sign edits --- .../AntiIllegalSignCharacters.java | 16 +++++++++++++ .../SignEditListener.java | 23 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/AntiIllegalSignCharacters.java create mode 100644 common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/SignEditListener.java diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/AntiIllegalSignCharacters.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/AntiIllegalSignCharacters.java new file mode 100644 index 0000000..9a94b66 --- /dev/null +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/AntiIllegalSignCharacters.java @@ -0,0 +1,16 @@ +package eu.mhsl.craftattack.spawn.common.appliances.security.antiIllegalSignCharacters; + +import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import org.bukkit.event.Listener; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class AntiIllegalSignCharacters extends Appliance { + @Override + protected @NotNull List listeners() { + return List.of( + new SignEditListener() + ); + } +} diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/SignEditListener.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/SignEditListener.java new file mode 100644 index 0000000..9ad38c9 --- /dev/null +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/SignEditListener.java @@ -0,0 +1,23 @@ +package eu.mhsl.craftattack.spawn.common.appliances.security.antiIllegalSignCharacters; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.event.EventHandler; +import org.bukkit.event.block.SignChangeEvent; + +class SignEditListener extends ApplianceListener { + @EventHandler + public void onSignEdit(SignChangeEvent event) { + for (int i = 0; i < 4; i++) { + Component line = event.line(i); + if(line == null) continue; + String lineStr = PlainTextComponentSerializer.plainText().serialize(line); + + if (!lineStr.matches("^[ -~]*$")) { + String cleaned = lineStr.replaceAll("[^ -~]", ""); + event.line(i, Component.text(cleaned)); + } + } + } +} From 89c1c4335bb1b2f6f5ba1adc20584f6841148be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Mon, 22 Dec 2025 21:41:34 +0100 Subject: [PATCH 04/12] refined `SignEditListener` to filter illegal characters more robustly by normalizing input and introducing specific character whitelists --- .../SignEditListener.java | 69 +++++++++++++++++-- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/SignEditListener.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/SignEditListener.java index 9ad38c9..4a7cd94 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/SignEditListener.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/SignEditListener.java @@ -6,18 +6,73 @@ import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.event.EventHandler; import org.bukkit.event.block.SignChangeEvent; +import java.text.Normalizer; +import java.util.Set; + class SignEditListener extends ApplianceListener { + private static final Set ALLOWED_CHARS = Set.of( + (int)' ', (int)'.', (int)',', (int)';', (int)':', (int)'!', (int)'?', + (int)'"', (int)'\'', + (int)'(', (int)')', (int)'[', (int)']', (int)'{', (int)'}', + (int)'-', (int)'_', (int)'+', (int)'=', (int)'/', (int)'\\', + (int)'@', (int)'#', (int)'$', (int)'%', (int)'&', (int)'*', + (int)'<', (int)'>', (int)'|', + (int)'~', (int)'`', (int)'^' + ); + + private static final Set ALLOWED_EXTRA = Set.of( + (int)'Ä', (int)'Ö', (int)'Ü', (int)'ä', (int)'ö', (int)'ü', (int)'ß', + (int)'€', (int)'°', (int)'µ' + ); + + @EventHandler public void onSignEdit(SignChangeEvent event) { for (int i = 0; i < 4; i++) { Component line = event.line(i); - if(line == null) continue; - String lineStr = PlainTextComponentSerializer.plainText().serialize(line); - - if (!lineStr.matches("^[ -~]*$")) { - String cleaned = lineStr.replaceAll("[^ -~]", ""); - event.line(i, Component.text(cleaned)); - } + if (line == null) continue; + String plainString = PlainTextComponentSerializer.plainText().serialize(line); + plainString = Normalizer.normalize(plainString, Normalizer.Form.NFC); + String cleaned = filterAllowed(plainString); + event.line(i, Component.text(cleaned)); } } + + private static String filterAllowed(String s) { + StringBuilder out = new StringBuilder(s.length()); + + for (int off = 0; off < s.length(); ) { + int cp = s.codePointAt(off); + off += Character.charCount(cp); + + if (isForbidden(cp)) continue; + + if (Character.isLetterOrDigit(cp)) { + out.appendCodePoint(cp); + continue; + } + + if (ALLOWED_CHARS.contains(cp) || ALLOWED_EXTRA.contains(cp)) { + out.appendCodePoint(cp); + } + } + return out.toString(); + } + + private static boolean isForbidden(int cp) { + // Surrogates / invalid + if (cp >= 0xD800 && cp <= 0xDFFF) return true; + + // Private Use Area (Mod/Pack-Icons/Placeholder) + if (cp >= 0xE000 && cp <= 0xF8FF) return true; + + // Zero-width and control characters + if (cp == 0x200B || cp == 0x200C || cp == 0x200D || cp == 0xFEFF) return true; + + // BiDi-Steuerzeichen + if (cp >= 0x202A && cp <= 0x202E) return true; + if (cp >= 0x2066 && cp <= 0x2069) return true; + + return cp == '§'; + } } From b3240cdb22ce706bb83ba2e62ee7a2da8061fad7 Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 23 Dec 2025 15:50:23 +0100 Subject: [PATCH 05/12] fixed maximum of 8 settings per category --- .../metaGameplay/settings/Settings.java | 16 ++++++++-------- .../gameplay/bloodmoon/BloodmoonSetting.java | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/settings/Settings.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/settings/Settings.java index dfec693..2a6a0fc 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/settings/Settings.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/settings/Settings.java @@ -128,12 +128,12 @@ public class Settings extends Appliance { if(categorizedSettings.isEmpty()) return; for(int i = 0; i < categorizedSettings.size(); i++) { - int slot = row.get() * 9 + i % 9; - inventory.setItem(slot, categorizedSettings.get(i).buildItem()); - - if(i % 9 == 8) { + if(i % 9 == 0 && i != 0) { row.incrementAndGet(); } + + int slot = row.get() * 9 + i % 9; + inventory.setItem(slot, categorizedSettings.get(i).buildItem()); } row.incrementAndGet(); }); @@ -143,12 +143,12 @@ public class Settings extends Appliance { .toList(); for(int i = 0; i < uncategorizedSettings.size(); i++) { - int slot = row.get() * 9 + i % 9; - inventory.setItem(slot, uncategorizedSettings.get(i).buildItem()); - - if(i % 9 == 8) { + if(i % 9 == 0 && i != 0) { row.incrementAndGet(); } + + int slot = row.get() * 9 + i % 9; + inventory.setItem(slot, uncategorizedSettings.get(i).buildItem()); } player.openInventory(inventory); diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java index 3782205..9fefebc 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java @@ -19,7 +19,7 @@ public class BloodmoonSetting extends BoolSetting implements CategorizedSetting @Override public SettingCategory category() { - return SettingCategory.Misc; // TODO: mehr als 8 bug fixen + return SettingCategory.Gameplay; } @Override From b98d33af4049cd60c758d4bc4fa08b7742cd312f Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 23 Dec 2025 18:56:30 +0100 Subject: [PATCH 06/12] added report reminder on admin join --- .../CraftAttackReportRepository.java | 4 +++ .../api/repositories/ReportRepository.java | 23 +++++++++++---- .../metaGameplay/report/Report.java | 28 +++++++++++++++++-- .../ReportCreatedListener.java | 3 +- .../report/listeners/ReportJoinListener.java | 14 ++++++++++ 5 files changed, 63 insertions(+), 9 deletions(-) rename common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/{ => listeners}/ReportCreatedListener.java (91%) create mode 100644 common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/listeners/ReportJoinListener.java diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/api/repositories/CraftAttackReportRepository.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/api/repositories/CraftAttackReportRepository.java index 232f4c7..43811f6 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/api/repositories/CraftAttackReportRepository.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/api/repositories/CraftAttackReportRepository.java @@ -23,4 +23,8 @@ public class CraftAttackReportRepository extends ReportRepository { ReportUrl.class ); } + + public ReqResp queryAllReports() { + return this.get("reports", AllReports.class); + } } diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/api/repositories/ReportRepository.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/api/repositories/ReportRepository.java index 0e3fec5..0007fd9 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/api/repositories/ReportRepository.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/api/repositories/ReportRepository.java @@ -21,6 +21,11 @@ public abstract class ReportRepository extends HttpRepository { public record ReportUrl(@NotNull String url) { } + public enum Status { + open, + closed, + } + public record PlayerReports( List from_self, List to_self @@ -31,11 +36,17 @@ public abstract class ReportRepository extends HttpRepository { @Nullable Long created, @Nullable Status status, @NotNull String url - ) { - public enum Status { - open, - closed, - } - } + ) { } + } + + public record AllReports(List reports) { + public record Report( + @NotNull UUID reporter, + @Nullable UUID reported, + @NotNull String reason, + @Nullable Long created, + @Nullable Status status, + @NotNull String url + ) { } } } diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java index 5a2098b..ff1e0e1 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java @@ -1,6 +1,8 @@ package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report; import eu.mhsl.craftattack.spawn.common.api.repositories.ReportRepository; +import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report.listeners.ReportCreatedListener; +import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report.listeners.ReportJoinListener; import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.api.client.ReqResp; import eu.mhsl.craftattack.spawn.common.api.repositories.CraftAttackReportRepository; @@ -133,7 +135,7 @@ public class Report extends Appliance { } Function, List> filterClosed = reports -> reports.stream() - .filter(report -> Objects.equals(report.status(), ReportRepository.PlayerReports.Report.Status.closed)) + .filter(report -> Objects.equals(report.status(), ReportRepository.Status.closed)) .toList(); List reportsToOthers = filterClosed.apply(userReports.data().from_self()).reversed(); @@ -179,10 +181,32 @@ public class Report extends Appliance { issuer.sendMessage(component.build()); } + public void sendReportsInfo(Player player) { + ReqResp allReportsResponse = this.queryRepository(CraftAttackReportRepository.class).queryAllReports(); + + if(allReportsResponse.status() != 200) { + Main.logger().warning("Failed to request Reports: " + allReportsResponse.status()); + return; + } + + List allOpenReports = allReportsResponse.data().reports().stream() + .filter(report -> report.status() == ReportRepository.Status.open) + .toList(); + + if(allOpenReports.isEmpty()) return; + + player.sendMessage( + Component.text("Hey, es gibt noch ", NamedTextColor.GOLD) + .append(Component.text(allOpenReports.size(), NamedTextColor.RED)) + .append(Component.text(" unbearbeitete Reports!", NamedTextColor.GOLD)) + ); + } + @Override protected @NotNull List listeners() { return List.of( - new ReportCreatedListener() + new ReportCreatedListener(), + new ReportJoinListener() ); } diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/ReportCreatedListener.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/listeners/ReportCreatedListener.java similarity index 91% rename from common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/ReportCreatedListener.java rename to common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/listeners/ReportCreatedListener.java index 8a6c988..9aba1b8 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/ReportCreatedListener.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/listeners/ReportCreatedListener.java @@ -1,5 +1,6 @@ -package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report; +package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report.listeners; +import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report.Report; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; import eu.mhsl.craftattack.spawn.core.event.ReportCreatedEvent; import net.kyori.adventure.text.Component; diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/listeners/ReportJoinListener.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/listeners/ReportJoinListener.java new file mode 100644 index 0000000..1cd9036 --- /dev/null +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/listeners/ReportJoinListener.java @@ -0,0 +1,14 @@ +package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report.listeners; + +import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report.Report; +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; + +public class ReportJoinListener extends ApplianceListener { + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + if(!event.getPlayer().hasPermission("admin")) return; + this.getAppliance().sendReportsInfo(event.getPlayer()); + } +} From bf11bb0b70dfb372c0f6a86dceb577cc7f42c427 Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 23 Dec 2025 19:05:53 +0100 Subject: [PATCH 07/12] fixed wrong reports info filtering --- .../spawn/common/appliances/metaGameplay/report/Report.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java index ff1e0e1..c4220c8 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java @@ -190,7 +190,7 @@ public class Report extends Appliance { } List allOpenReports = allReportsResponse.data().reports().stream() - .filter(report -> report.status() == ReportRepository.Status.open) + .filter(report -> report.status() == null) .toList(); if(allOpenReports.isEmpty()) return; From 2209b4276625b9061961281149a4b6421444e963 Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 23 Dec 2025 19:11:59 +0100 Subject: [PATCH 08/12] fixed wrong reports info filtering --- .../spawn/common/appliances/metaGameplay/report/Report.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java index c4220c8..f42e022 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/Report.java @@ -190,7 +190,7 @@ public class Report extends Appliance { } List allOpenReports = allReportsResponse.data().reports().stream() - .filter(report -> report.status() == null) + .filter(report -> report.status() == null && report.created() != null) .toList(); if(allOpenReports.isEmpty()) return; From 85065bcc7327ad09a20666ce3a7eea830b27515c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Tue, 23 Dec 2025 19:14:53 +0100 Subject: [PATCH 09/12] made `SignEditListener` formatting consistent and optimized `ReportJoinListener` to handle admin notifications asynchronously --- .../metaGameplay/report/listeners/ReportJoinListener.java | 7 ++++++- .../antiIllegalSignCharacters/SignEditListener.java | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/listeners/ReportJoinListener.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/listeners/ReportJoinListener.java index 1cd9036..adc56c3 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/listeners/ReportJoinListener.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/report/listeners/ReportJoinListener.java @@ -1,7 +1,9 @@ package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report.listeners; import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report.Report; +import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.player.PlayerJoinEvent; @@ -9,6 +11,9 @@ public class ReportJoinListener extends ApplianceListener { @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { if(!event.getPlayer().hasPermission("admin")) return; - this.getAppliance().sendReportsInfo(event.getPlayer()); + Bukkit.getScheduler().runTaskAsynchronously( + Main.instance(), + () -> this.getAppliance().sendReportsInfo(event.getPlayer()) + ); } } diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/SignEditListener.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/SignEditListener.java index 4a7cd94..ce24819 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/SignEditListener.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/security/antiIllegalSignCharacters/SignEditListener.java @@ -25,7 +25,6 @@ class SignEditListener extends ApplianceListener { (int)'€', (int)'°', (int)'µ' ); - @EventHandler public void onSignEdit(SignChangeEvent event) { for (int i = 0; i < 4; i++) { From 8953a19400f415dc1899a863fe40bbd8d16ad791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Tue, 23 Dec 2025 19:52:17 +0100 Subject: [PATCH 10/12] added Bedrock player warning in `joinEvent` method to handle potential compatibility issues --- .../appliances/metaGameplay/event/Event.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/metaGameplay/event/Event.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/metaGameplay/event/Event.java index 4c37244..01853fd 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/metaGameplay/event/Event.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/metaGameplay/event/Event.java @@ -2,6 +2,7 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.event; import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.api.client.ReqResp; +import eu.mhsl.craftattack.spawn.core.util.server.Floodgate; import eu.mhsl.craftattack.spawn.craftattack.api.repositories.EventRepository; import eu.mhsl.craftattack.spawn.core.api.server.HttpServer; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; @@ -26,6 +27,7 @@ import org.bukkit.entity.Villager; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.geysermc.cumulus.form.SimpleForm; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -94,6 +96,10 @@ public class Event extends Appliance { } public void joinEvent(Player p) { + this.joinEvent(p, false); + } + + public void joinEvent(Player p, boolean ignoreBedrock) { if(!this.isOpen) { p.sendMessage(Component.text("Zurzeit ist kein Event geöffnet.", NamedTextColor.RED)); return; @@ -109,6 +115,23 @@ public class Event extends Appliance { return; } + if(!ignoreBedrock && Floodgate.isBedrock(p)) { + Floodgate.getBedrockPlayer(p).sendForm( + SimpleForm.builder() + .title("Achtung!") + .content("Je nach deiner Minecraft-Bedrock-Version kann dein Minecraft in den Events abstürzen. " + + "Ggf. ist also für dich ein Mitspielen auf der Bedrock-Edition nicht möglich.") + .button("Ok, lass es uns versuchen") + .button("Abbrechen") + .validResultHandler(simpleFormResponse -> { + if(simpleFormResponse.clickedButtonId() != 0) return; + this.joinEvent(p, true); + }) + .build() + ); + return; + } + Main.instance().getLogger().info("Verbinde mit eventserver: " + p.getName()); p.sendMessage(Component.text("Authentifiziere...", NamedTextColor.GREEN)); From dfbf87dcd4ce9b0cd2f71ac04abebcbd9d3ab9c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Tue, 23 Dec 2025 21:07:32 +0100 Subject: [PATCH 11/12] updated `ProjectStart` to adjust coordinates, music, and glass material; refined player inventory handling logic; renamed `vogelfrei` to `PVP` in `Outlawed` messages for clarity --- .../gameplay/outlawed/Outlawed.java | 8 +++---- .../tooling/projectStart/ProjectStart.java | 21 ++++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/outlawed/Outlawed.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/outlawed/Outlawed.java index 3eddd09..3c369d1 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/outlawed/Outlawed.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/outlawed/Outlawed.java @@ -51,14 +51,14 @@ public class Outlawed extends Appliance implements DisplayName.Prefixed { void askForConfirmation(Player player) { Component confirmationMessage = switch(this.getLawStatus(player)) { - case DISABLED -> Component.text("Wenn du Vogelfrei aktivierst, darfst du von allen anderen vogelfreien Spielern grundlos angegriffen werden."); - case VOLUNTARILY -> Component.text("Wenn du Vogelfrei deaktivierst, darfst du nicht mehr grundlos von anderen Spielern angegriffen werden."); - case FORCED -> Component.text("Du darfst zurzeit deinen Vogelfreistatus nicht ändern, da dieser als Strafe auferlegt wurde!"); + case DISABLED -> Component.text("Wenn du den PVP-Modus aktivierst, darfst du von allen anderen PVP-Spielern grundlos angegriffen werden."); + case VOLUNTARILY -> Component.text("Wenn du den PVP-Modus deaktivierst, darfst du nicht mehr grundlos von anderen Spielern angegriffen werden."); + case FORCED -> Component.text("Du darfst zurzeit deinen PVP-Modus nicht ändern, da dieser als Strafe auferlegt wurde!"); }; String command = String.format("/%s confirm", OutlawedCommand.commandName); Component changeText = Component.text( String.format( - "Zum ändern deines Vogelfrei status klicke auf diese Nachricht oder tippe '%s'", + "Zum ändern deines PVP-Status klicke auf diese Nachricht oder tippe '%s'", command ), NamedTextColor.GOLD diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/tooling/projectStart/ProjectStart.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/tooling/projectStart/ProjectStart.java index df6832a..df5c904 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/tooling/projectStart/ProjectStart.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/tooling/projectStart/ProjectStart.java @@ -22,6 +22,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.*; import org.bukkit.entity.Player; import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -29,14 +30,14 @@ import java.util.Map; import java.util.Objects; import static java.util.Map.entry; -import static org.bukkit.Sound.MUSIC_DISC_PRECIPICE; +import static org.bukkit.Sound.MUSIC_DISC_LAVA_CHICKEN; public class ProjectStart extends Appliance { - private final int startMusicAt = 293; + private final int startMusicAt = 130; private final World startWorld = Bukkit.getWorld("world"); - private final Location glassLocation = new Location(this.startWorld, 0, 64, -300); + private final Location glassLocation = new Location(this.startWorld, -363, 126, 613); private final List netherFireLocations = List.of( - new Location(this.startWorld, 14, 71, -310) + new Location(this.startWorld, -352, 131, 627) ); private final Countdown countdown = new Countdown( @@ -47,7 +48,7 @@ public class ProjectStart extends Appliance { ); private final BlockCycle blockCycle = new BlockCycle( this.glassLocation, - Material.RED_STAINED_GLASS, + Material.WHITE_STAINED_GLASS, List.of( Material.RED_STAINED_GLASS, Material.YELLOW_STAINED_GLASS, @@ -77,7 +78,7 @@ public class ProjectStart extends Appliance { counter -> counter == this.startMusicAt, counter -> this.glassLocation .getWorld() - .playSound(this.glassLocation, MUSIC_DISC_PRECIPICE, SoundCategory.RECORDS, 500f, 1f) + .playSound(this.glassLocation, MUSIC_DISC_LAVA_CHICKEN, SoundCategory.RECORDS, 500f, 1f) ) ); } @@ -128,7 +129,13 @@ public class ProjectStart extends Appliance { Bukkit.getOnlinePlayers().forEach(player -> { player.setFoodLevel(20); player.setHealth(20); - player.getInventory().clear(); + if(player.getInventory().contains(Material.RECOVERY_COMPASS)) { + player.getInventory().clear(); + player.give(new ItemStack(Material.RECOVERY_COMPASS)); + } else { + player.getInventory().clear(); + } + player.setGameMode(GameMode.SURVIVAL); player.setExp(0); player.setLevel(0); From df39093c6984d2c8a4fa052931ab5926c039e17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Tue, 23 Dec 2025 21:32:35 +0100 Subject: [PATCH 12/12] enhanced `Outlawed` PVP activation message to include cooldown duration; fixed minor typo in forced status message --- .../craftattack/appliances/gameplay/outlawed/Outlawed.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/outlawed/Outlawed.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/outlawed/Outlawed.java index 3c369d1..08c31a2 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/outlawed/Outlawed.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/outlawed/Outlawed.java @@ -51,9 +51,10 @@ public class Outlawed extends Appliance implements DisplayName.Prefixed { void askForConfirmation(Player player) { Component confirmationMessage = switch(this.getLawStatus(player)) { - case DISABLED -> Component.text("Wenn du den PVP-Modus aktivierst, darfst du von allen anderen PVP-Spielern grundlos angegriffen werden."); + case DISABLED -> Component.text("Wenn du den PVP-Modus aktivierst, darfst du von allen anderen PVP-Spielern grundlos angegriffen werden." + + " Du kannst den PVP-Modus erst wieder nach " + this.timeoutInMs / 1000 / 60 / 60 + " Stunden deaktivieren!"); case VOLUNTARILY -> Component.text("Wenn du den PVP-Modus deaktivierst, darfst du nicht mehr grundlos von anderen Spielern angegriffen werden."); - case FORCED -> Component.text("Du darfst zurzeit deinen PVP-Modus nicht ändern, da dieser als Strafe auferlegt wurde!"); + case FORCED -> Component.text("Du darfst zurzeit deinen PVP-Modus nicht ändern, da die˝ser als Strafe auferlegt wurde!"); }; String command = String.format("/%s confirm", OutlawedCommand.commandName); Component changeText = Component.text(