Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f615dc867a | |||
| 673bae4d50 | |||
| 6ad9407cb4 | |||
| 9dad34719b | |||
| 323e316f0f | |||
| 0a16e1e049 | |||
| c371893407 | |||
| f2bf8f1858 | |||
| a0a33f1f56 | |||
| 164a160dbb | |||
| efdbc6fe9f | |||
| 7ac02b4ec4 | |||
| 93971650ce | |||
| 336e3f934c | |||
| 91e350ee62 | |||
| 8736e78adf | |||
| 329ec8e1da | |||
| ebf392b024 | |||
| 33d00e97c6 | |||
| 1fdcc11211 | |||
| e0ed7ecdf5 | |||
| 2ca97c88fc | |||
| fc502e3da8 | |||
| 5e3db1e78c | |||
| fc6fd9ebb5 | |||
| 84edbcc0e4 | |||
| 9ec883d6ad | |||
| 2b0c7c1a9e | |||
| df39093c69 | |||
| dfbf87dcd4 | |||
| 8953a19400 | |||
| 85065bcc73 | |||
| 2209b42766 | |||
| bf11bb0b70 | |||
| b98d33af40 | |||
| 0d6b21701f | |||
| b3240cdb22 | |||
| 89c1c4335b | |||
| 71f2da8e99 | |||
| a257b604ea | |||
| ef153d5d8f | |||
| bd883a4fa1 | |||
| ac7e04829e | |||
| 5cda58408a | |||
| 9767896cde | |||
| e015bbb356 | |||
| 1ac19014c1 |
+4
@@ -23,4 +23,8 @@ public class CraftAttackReportRepository extends ReportRepository {
|
||||
ReportUrl.class
|
||||
);
|
||||
}
|
||||
|
||||
public ReqResp<AllReports> queryAllReports() {
|
||||
return this.get("reports", AllReports.class);
|
||||
}
|
||||
}
|
||||
|
||||
+17
-6
@@ -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<Report> from_self,
|
||||
List<Report> 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<Report> reports) {
|
||||
public record Report(
|
||||
@NotNull UUID reporter,
|
||||
@Nullable UUID reported,
|
||||
@NotNull String reason,
|
||||
@Nullable Long created,
|
||||
@Nullable Status status,
|
||||
@NotNull String url
|
||||
) { }
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.UUID;
|
||||
|
||||
public class AdminMarker extends Appliance implements DisplayName.Colored {
|
||||
public final static String adminPermission = "admin";
|
||||
public final static String adminPermission = "adminmarker";
|
||||
|
||||
@Override
|
||||
public @Nullable TextColor getNameColor(Player player) {
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ public class HelpCommand extends ApplianceCommand<Help> {
|
||||
Component.text("Willkommen auf Craftattack!", NamedTextColor.GOLD)
|
||||
.appendNewline()
|
||||
.append(Component.text("Wenn du hilfe benötigst kannst du dich jederzeit an einen Admin wenden." +
|
||||
" Weitere Informationen zu Funktionen und Befehlen erhältst du zudem im Turm am Spawn.", NamedTextColor.GRAY))
|
||||
" Weitere Informationen zu Funktionen und Befehlen erhältst du zudem am Spawn.", NamedTextColor.GRAY))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+33
-1
@@ -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;
|
||||
@@ -16,6 +18,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;
|
||||
|
||||
@@ -132,7 +135,7 @@ public class Report extends Appliance {
|
||||
}
|
||||
|
||||
Function<List<ReportRepository.PlayerReports.Report>, List<ReportRepository.PlayerReports.Report>> 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<ReportRepository.PlayerReports.Report> reportsToOthers = filterClosed.apply(userReports.data().from_self()).reversed();
|
||||
@@ -178,6 +181,35 @@ public class Report extends Appliance {
|
||||
issuer.sendMessage(component.build());
|
||||
}
|
||||
|
||||
public void sendReportsInfo(Player player) {
|
||||
ReqResp<ReportRepository.AllReports> allReportsResponse = this.queryRepository(CraftAttackReportRepository.class).queryAllReports();
|
||||
|
||||
if(allReportsResponse.status() != 200) {
|
||||
Main.logger().warning("Failed to request Reports: " + allReportsResponse.status());
|
||||
return;
|
||||
}
|
||||
|
||||
List<ReportRepository.AllReports.Report> allOpenReports = allReportsResponse.data().reports().stream()
|
||||
.filter(report -> report.status() == null && report.created() != null)
|
||||
.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<Listener> listeners() {
|
||||
return List.of(
|
||||
new ReportCreatedListener(),
|
||||
new ReportJoinListener()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<ApplianceCommand<?>> commands() {
|
||||
|
||||
+2
-1
@@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -46,7 +47,7 @@ class ReportCommand extends ApplianceCommand.PlayerChecked<Report> {
|
||||
response = Stream.concat(
|
||||
Bukkit.getOnlinePlayers().stream().map(Player::getName),
|
||||
Arrays.stream(Bukkit.getOfflinePlayers()).map(OfflinePlayer::getName)
|
||||
).toList();
|
||||
).filter(Objects::nonNull).distinct().toList();
|
||||
}
|
||||
|
||||
if(args.length == 2) {
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
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;
|
||||
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<Report> {
|
||||
@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));
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
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;
|
||||
|
||||
public class ReportJoinListener extends ApplianceListener<Report> {
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
if(!event.getPlayer().hasPermission("admin")) return;
|
||||
Bukkit.getScheduler().runTaskAsynchronously(
|
||||
Main.instance(),
|
||||
() -> this.getAppliance().sendReportsInfo(event.getPlayer())
|
||||
);
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -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);
|
||||
|
||||
+4
-10
@@ -5,15 +5,11 @@ import eu.mhsl.craftattack.spawn.core.Main;
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Boat;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Appliance.Flags(enabled = false)
|
||||
public class AntiBoatFreecam extends Appliance {
|
||||
private static final float MAX_YAW_OFFSET = 106.0f;
|
||||
private final Map<Player, Float> violatedPlayers = new HashMap<>();
|
||||
|
||||
public AntiBoatFreecam() {
|
||||
Bukkit.getScheduler().runTaskTimerAsynchronously(
|
||||
@@ -27,14 +23,12 @@ public class AntiBoatFreecam extends Appliance {
|
||||
float yawDelta = wrapDegrees(playerYaw - boatYaw);
|
||||
if(Math.abs(yawDelta) <= MAX_YAW_OFFSET) return;
|
||||
|
||||
this.violatedPlayers.merge(player, 1f, Float::sum);
|
||||
float violationCount = this.violatedPlayers.get(player);
|
||||
if(violationCount != 1 && violationCount % 100 != 0) return;
|
||||
Main.instance().getAppliance(AcInform.class).notifyAdmins(
|
||||
Main.instance().getAppliance(AcInform.class).slowedNotifyAdmins(
|
||||
"internal",
|
||||
player.getName(),
|
||||
"illegalBoatLookYaw",
|
||||
violationCount
|
||||
yawDelta,
|
||||
3000
|
||||
);
|
||||
}),
|
||||
1L,
|
||||
|
||||
+16
@@ -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<Listener> listeners() {
|
||||
return List.of(
|
||||
new SignEditListener()
|
||||
);
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
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;
|
||||
|
||||
import java.text.Normalizer;
|
||||
import java.util.Set;
|
||||
|
||||
class SignEditListener extends ApplianceListener<AntiIllegalSignCharacters> {
|
||||
private static final Set<Integer> 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<Integer> 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 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 == '§';
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package eu.mhsl.craftattack.spawn.common.appliances.security.antiInventoryMove;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
|
||||
import net.kyori.adventure.util.Ticks;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
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;
|
||||
|
||||
private final Map<UUID, Long> invOpen = new ConcurrentHashMap<>();
|
||||
|
||||
public void setInvOpen(Player player, boolean open) {
|
||||
if(open)
|
||||
this.invOpen.put(player.getUniqueId(), System.currentTimeMillis());
|
||||
else
|
||||
this.invOpen.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
public boolean hasInventoryOpen(Player player) {
|
||||
if(!this.invOpen.containsKey(player.getUniqueId())) return false;
|
||||
return this.invOpen.get(player.getUniqueId()) < System.currentTimeMillis() - errorTimeMargin;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(
|
||||
new InventoryTrackerListener(),
|
||||
new InInventoryMoveListener()
|
||||
);
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package eu.mhsl.craftattack.spawn.common.appliances.security.antiInventoryMove;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.common.appliances.tooling.acInform.AcInform;
|
||||
import eu.mhsl.craftattack.spawn.core.Main;
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerInputEvent;
|
||||
|
||||
class InInventoryMoveListener extends ApplianceListener<AntiInventoryMove> {
|
||||
@EventHandler
|
||||
public void onInput(PlayerInputEvent event) {
|
||||
if(!this.getAppliance().hasInventoryOpen(event.getPlayer())) return;
|
||||
Main.instance().getAppliance(AcInform.class).slowedNotifyAdmins(
|
||||
"internal",
|
||||
event.getPlayer().getName(),
|
||||
"inInventoryMove",
|
||||
-1f,
|
||||
3000
|
||||
);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
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<AntiInventoryMove> {
|
||||
@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);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onClose(InventoryCloseEvent event) {
|
||||
if(!(event.getPlayer() instanceof Player player)) return;
|
||||
this.getAppliance().setInvOpen(player, false);
|
||||
}
|
||||
}
|
||||
+43
-4
@@ -11,14 +11,20 @@ import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class AcInform extends Appliance {
|
||||
private final Map<String, Map<String, Long>> violationSlowdowns = new ConcurrentHashMap<>();
|
||||
|
||||
public void processCommand(@NotNull String[] args) {
|
||||
String anticheatName = null;
|
||||
String playerName = null;
|
||||
String checkName = null;
|
||||
Float violationCount = null;
|
||||
int notifyEvery = 0;
|
||||
|
||||
for(int i = 0; i < args.length; i++) {
|
||||
if(!args[i].startsWith("--")) continue;
|
||||
@@ -36,13 +42,32 @@ public class AcInform extends Appliance {
|
||||
case "--playerName" -> playerName = value;
|
||||
case "--check" -> checkName = value;
|
||||
case "--violationCount" -> violationCount = value.isEmpty() ? null : Float.valueOf(value);
|
||||
case "--notifyEvery" -> notifyEvery = Integer.parseInt(value);
|
||||
}
|
||||
}
|
||||
|
||||
if(notifyEvery == 0) {
|
||||
this.notifyAdmins(anticheatName, playerName, checkName, violationCount);
|
||||
} else {
|
||||
this.slowedNotifyAdmins(anticheatName, playerName, checkName, violationCount, notifyEvery);
|
||||
}
|
||||
}
|
||||
|
||||
public void slowedNotifyAdmins(@Nullable String anticheatName, @Nullable String playerName, @Nullable String checkName, @Nullable Float violationCount, int notifyEvery) {
|
||||
this.violationSlowdowns.putIfAbsent(playerName, new HashMap<>());
|
||||
|
||||
var slowdowns = this.violationSlowdowns.get(playerName);
|
||||
if(slowdowns.containsKey(checkName)) {
|
||||
if(slowdowns.get(checkName) > System.currentTimeMillis() - notifyEvery) return;
|
||||
}
|
||||
|
||||
this.notifyAdmins(anticheatName, playerName, checkName, violationCount);
|
||||
}
|
||||
|
||||
public void notifyAdmins(@Nullable String anticheatName, @Nullable String playerName, @Nullable String checkName, @Nullable Float violationCount) {
|
||||
this.violationSlowdowns.putIfAbsent(playerName, new HashMap<>());
|
||||
this.violationSlowdowns.get(playerName).put(checkName, System.currentTimeMillis());
|
||||
|
||||
ComponentBuilder<TextComponent, TextComponent.Builder> component = Component.text();
|
||||
NamedTextColor textColor = NamedTextColor.GRAY;
|
||||
|
||||
@@ -85,28 +110,42 @@ public class AcInform extends Appliance {
|
||||
Component.newline()
|
||||
.append(Component.text("⊥ ", NamedTextColor.GRAY))
|
||||
.append(Component.text("[", NamedTextColor.GRAY))
|
||||
.append(Component.text("Report", NamedTextColor.GOLD))
|
||||
.append(Component.text("\uD83D\uDCD6", NamedTextColor.GOLD))
|
||||
.append(Component.text("]", NamedTextColor.GRAY))
|
||||
.clickEvent(ClickEvent.suggestCommand(String.format("/report %s anticheat %s flagged %s", playerName, anticheatName, checkName)))
|
||||
);
|
||||
|
||||
component.append(
|
||||
Component.text(" [", NamedTextColor.GRAY)
|
||||
.append(Component.text("Kick", NamedTextColor.GOLD))
|
||||
.append(Component.text("\u23F1", NamedTextColor.GOLD))
|
||||
.append(Component.text("]", NamedTextColor.GRAY))
|
||||
.clickEvent(ClickEvent.suggestCommand(String.format("/kick %s", playerName)))
|
||||
);
|
||||
|
||||
component.append(
|
||||
Component.text(" [", NamedTextColor.GRAY)
|
||||
.append(Component.text("Panic Ban", NamedTextColor.GOLD))
|
||||
.append(Component.text("\uD83E\uDDB6", NamedTextColor.GOLD))
|
||||
.append(Component.text("]", NamedTextColor.GRAY))
|
||||
.clickEvent(ClickEvent.suggestCommand(String.format("/kickunsuspected %s", playerName)))
|
||||
);
|
||||
|
||||
component.append(
|
||||
Component.text(" [", NamedTextColor.GRAY)
|
||||
.append(Component.text("\u2623", NamedTextColor.GOLD))
|
||||
.append(Component.text("]", NamedTextColor.GRAY))
|
||||
.clickEvent(ClickEvent.suggestCommand(String.format("/kickcrash %s", playerName)))
|
||||
);
|
||||
|
||||
component.append(
|
||||
Component.text(" [", NamedTextColor.GRAY)
|
||||
.append(Component.text("\uD83D\uDD12", NamedTextColor.GOLD))
|
||||
.append(Component.text("]", NamedTextColor.GRAY))
|
||||
.clickEvent(ClickEvent.suggestCommand(String.format("/panicban %s", playerName)))
|
||||
);
|
||||
|
||||
component.append(
|
||||
Component.text(" [", NamedTextColor.GRAY)
|
||||
.append(Component.text("Spectate/Teleport", NamedTextColor.GOLD))
|
||||
.append(Component.text("\uD83D\uDC41", NamedTextColor.GOLD))
|
||||
.append(Component.text("]", NamedTextColor.GRAY))
|
||||
.clickEvent(ClickEvent.suggestCommand(String.format("/grim spectate %s", playerName)))
|
||||
);
|
||||
|
||||
+33
-1
@@ -1,9 +1,14 @@
|
||||
package eu.mhsl.craftattack.spawn.common.appliances.tooling.kick;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.Main;
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
|
||||
import eu.mhsl.craftattack.spawn.core.util.entity.PlayerUtils;
|
||||
import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.util.Ticks;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -25,9 +30,36 @@ public class Kick extends Appliance {
|
||||
).applyKick(player);
|
||||
}
|
||||
|
||||
public void unsuspectedKick(@NotNull String playerName) {
|
||||
Player player = Bukkit.getPlayer(playerName);
|
||||
|
||||
if(player == null)
|
||||
throw new ApplianceCommand.Error("Player not found");
|
||||
|
||||
String material = Material.values()[(int)(Math.random() * Material.values().length)].name();
|
||||
player.kick(Component.text("java.lang.IllegalStateException: Failed to create model for minecraft:%s".formatted(material)));
|
||||
}
|
||||
|
||||
public void crashKick(@NotNull String playerName) {
|
||||
Player player = Bukkit.getPlayer(playerName);
|
||||
|
||||
if(player == null)
|
||||
throw new ApplianceCommand.Error("Player not found");
|
||||
|
||||
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> {
|
||||
PlayerUtils.sendCube(player, 100, Material.ENCHANTING_TABLE.createBlockData());
|
||||
PlayerUtils.sendCube(player, 5, Material.DIRT.createBlockData());
|
||||
});
|
||||
Bukkit.getScheduler().runTaskLater(Main.instance(), () -> player.kick(Component.empty()), Ticks.TICKS_PER_SECOND * 15);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<ApplianceCommand<?>> commands() {
|
||||
return List.of(new KickCommand());
|
||||
return List.of(
|
||||
new KickCommand(),
|
||||
new KickUnsuspectedCommand(),
|
||||
new KickCrashCommand()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package eu.mhsl.craftattack.spawn.common.appliances.tooling.kick;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class KickCrashCommand extends ApplianceCommand<Kick> {
|
||||
public KickCrashCommand() {
|
||||
super("kickCrash");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||
if(args.length < 1) throw new Error("Es muss ein Spielername angegeben werden!");
|
||||
this.getAppliance().crashKick(args[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
return super.tabCompleteReducer(
|
||||
Bukkit.getOnlinePlayers().stream().map(Player::getName).toList(),
|
||||
args
|
||||
);
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package eu.mhsl.craftattack.spawn.common.appliances.tooling.kick;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class KickUnsuspectedCommand extends ApplianceCommand<Kick> {
|
||||
public KickUnsuspectedCommand() {
|
||||
super("kickUnsuspected");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||
if(args.length < 1) throw new Error("Es muss ein Spielername angegeben werden!");
|
||||
this.getAppliance().unsuspectedKick(args[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
return super.tabCompleteReducer(
|
||||
Bukkit.getOnlinePlayers().stream().map(Player::getName).toList(),
|
||||
args
|
||||
);
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -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;
|
||||
}));
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
package eu.mhsl.craftattack.spawn.core.util.entity;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PlayerUtils {
|
||||
public static void resetStatistics(Player player) {
|
||||
for(Statistic statistic : Statistic.values()) {
|
||||
@@ -30,4 +36,30 @@ public class PlayerUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendCube(Player player, int cubeSize, BlockData fakeBlock) {
|
||||
Location loc = player.getLocation();
|
||||
World world = player.getWorld();
|
||||
|
||||
int half = cubeSize / 2;
|
||||
int cx = loc.getBlockX();
|
||||
int cy = loc.getBlockY();
|
||||
int cz = loc.getBlockZ();
|
||||
|
||||
int minY = world.getMinHeight();
|
||||
int maxY = world.getMaxHeight() - 1;
|
||||
|
||||
Map<Location, BlockData> changes = new HashMap<>();
|
||||
|
||||
for (int x = cx - half; x <= cx + half; x++) {
|
||||
for (int y = Math.max(cy - half, minY); y <= Math.min(cy + half, maxY); y++) {
|
||||
for (int z = cz - half; z <= cz + half; z++) {
|
||||
changes.put(new Location(world, x, y, z), fakeBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//noinspection UnstableApiUsage
|
||||
player.sendMultiBlockChange(changes);
|
||||
}
|
||||
}
|
||||
|
||||
+65
-23
@@ -5,23 +5,18 @@ import eu.mhsl.craftattack.spawn.core.Main;
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
|
||||
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.commands.BloodmoonCommand;
|
||||
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonEntityDamageListener;
|
||||
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonMonsterDeathListener;
|
||||
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonPlayerJoinListener;
|
||||
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonTimeListener;
|
||||
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.*;
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.util.Ticks;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
@@ -70,7 +65,6 @@ public class Bloodmoon extends Appliance {
|
||||
public final double mobHealthMultiplier = 2;
|
||||
|
||||
private final ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
private boolean isActive = false;
|
||||
private final BossBar bossBar = BossBar.bossBar(
|
||||
Component.text("Blutmond", NamedTextColor.DARK_RED),
|
||||
1f,
|
||||
@@ -79,6 +73,7 @@ public class Bloodmoon extends Appliance {
|
||||
Set.of(BossBar.Flag.CREATE_WORLD_FOG, BossBar.Flag.DARKEN_SCREEN)
|
||||
);
|
||||
private final boolean hordesEnabled = true;
|
||||
public final boolean bloodmoonSkippable = true;
|
||||
private final int hordeSpawnRateTicks = 40 * Ticks.TICKS_PER_SECOND;
|
||||
private final int hordeSpawnRateVariationTicks = 40 * Ticks.TICKS_PER_SECOND;
|
||||
private final int hordeMinPopulation = 3;
|
||||
@@ -90,10 +85,10 @@ public class Bloodmoon extends Appliance {
|
||||
EntityType.SPIDER
|
||||
);
|
||||
private final Map<Player, @Nullable BukkitTask> hordeSpawnTasks = new WeakHashMap<>();
|
||||
private long lastBloodmoonStartTick = 0;
|
||||
public final int ticksPerDay = 24000;
|
||||
public final int bloodmoonLength = this.ticksPerDay /2;
|
||||
public final int bloodmoonLength = this.ticksPerDay / 2;
|
||||
public final int preStartMessageTicks = Ticks.TICKS_PER_SECOND * 50;
|
||||
private boolean bossbarActive = false;
|
||||
private final int bloodmoonFreeDaysAtStart = 3;
|
||||
private final int bloodmoonStartTime = this.ticksPerDay /2;
|
||||
private final int bloodmoonDayInterval = 30;
|
||||
@@ -113,35 +108,71 @@ public class Bloodmoon extends Appliance {
|
||||
}
|
||||
|
||||
public boolean bloodmoonIsActive() {
|
||||
return this.isActive;
|
||||
long currentTick = Bukkit.getWorlds().getFirst().getFullTime();
|
||||
long day = currentTick / this.ticksPerDay;
|
||||
if(day % this.bloodmoonDayInterval != 0 || day - this.bloodmoonFreeDaysAtStart <= 0) return false;
|
||||
long time = currentTick % this.ticksPerDay;
|
||||
return time >= this.bloodmoonStartTime && time <= this.bloodmoonStartTime + this.bloodmoonLength;
|
||||
}
|
||||
|
||||
public void startBloodmoon(long startTick) {
|
||||
this.lastBloodmoonStartTick = startTick;
|
||||
this.isActive = true;
|
||||
public void startBloodmoon() {
|
||||
this.bossbarActive = true;
|
||||
Bukkit.getOnlinePlayers().forEach(this::addPlayerToBossBar);
|
||||
this.startHordeSpawning(this.getRandomHordeSpawnDelay());
|
||||
this.sendStartMessages();
|
||||
}
|
||||
|
||||
public void stopBloodmoon() {
|
||||
this.isActive = false;
|
||||
public void stopBloodmoonIfInactive() {
|
||||
Bukkit.getScheduler().runTaskLater(
|
||||
Main.instance(),
|
||||
() -> {
|
||||
if(!this.bossbarActive) return;
|
||||
if(this.bloodmoonIsActive()) return;
|
||||
this.bossbarActive = false;
|
||||
Bukkit.getOnlinePlayers().forEach(player -> player.hideBossBar(this.bossBar));
|
||||
this.stopHordeSpawning();
|
||||
this.sendStopMessages();
|
||||
},
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
// not working for entity effects and debuffs...
|
||||
public void forceStopBloodmoon() {
|
||||
this.bossbarActive = false;
|
||||
Bukkit.getOnlinePlayers().forEach(player -> player.hideBossBar(this.bossBar));
|
||||
this.stopHordeSpawning();
|
||||
this.sendStopMessages();
|
||||
}
|
||||
|
||||
public void updateBossBar() {
|
||||
long tick = Bukkit.getWorlds().getFirst().getFullTime();
|
||||
long sinceStart = tick - this.lastBloodmoonStartTick;
|
||||
long sinceStart = tick - this.lastBloodmoonStartTick();
|
||||
float progress = 1f - ((float) sinceStart / this.bloodmoonLength);
|
||||
if(progress < 0) progress = 1f;
|
||||
this.bossBar.progress(progress);
|
||||
}
|
||||
|
||||
private long lastBloodmoonStartTick() {
|
||||
long currentTick = Bukkit.getWorlds().getFirst().getFullTime();
|
||||
long day = currentTick / this.ticksPerDay;
|
||||
long time = currentTick % this.ticksPerDay;
|
||||
|
||||
boolean todayIsBloodmoon = (day % this.bloodmoonDayInterval == 0) && (day > this.bloodmoonFreeDaysAtStart);
|
||||
if (todayIsBloodmoon && time < this.bloodmoonStartTime) {
|
||||
day -= this.bloodmoonDayInterval;
|
||||
} else if (!todayIsBloodmoon) {
|
||||
day -= (day % this.bloodmoonDayInterval);
|
||||
}
|
||||
|
||||
if (day <= this.bloodmoonFreeDaysAtStart) return -1L;
|
||||
return day * this.ticksPerDay + this.bloodmoonStartTime;
|
||||
}
|
||||
|
||||
public boolean isStartTick(long tick) {
|
||||
long day = tick / this.ticksPerDay;
|
||||
if(day % this.bloodmoonDayInterval != 0 || day - this.bloodmoonFreeDaysAtStart <= 0) return false;
|
||||
long time = tick - (day * this.ticksPerDay);
|
||||
if(day % this.bloodmoonDayInterval != 0 || day <= this.bloodmoonFreeDaysAtStart) return false;
|
||||
long time = tick % this.ticksPerDay;
|
||||
return time == this.bloodmoonStartTime;
|
||||
}
|
||||
|
||||
@@ -153,7 +184,14 @@ public class Bloodmoon extends Appliance {
|
||||
Bukkit.getOnlinePlayers().forEach(player -> this.startHordeSpawning(delay, player));
|
||||
}
|
||||
|
||||
private void startHordeSpawning(int delay, Player player) {
|
||||
private void stopHordeSpawning() {
|
||||
this.hordeSpawnTasks.forEach((player, bukkitTask) -> {
|
||||
@Nullable BukkitTask task = this.hordeSpawnTasks.get(player);
|
||||
if(task != null) task.cancel();
|
||||
});
|
||||
}
|
||||
|
||||
public void startHordeSpawning(int delay, Player player) {
|
||||
@Nullable BukkitTask task = this.hordeSpawnTasks.get(player);
|
||||
if(task != null) task.cancel();
|
||||
BukkitTask newTask = Bukkit.getScheduler().runTaskLater(
|
||||
@@ -187,14 +225,17 @@ public class Bloodmoon extends Appliance {
|
||||
|
||||
public void spawnRandomHorde(Player player) {
|
||||
if(!this.hordesEnabled) return;
|
||||
if(!this.getBloodmoonSetting(player)) return;
|
||||
if(!player.getGameMode().equals(GameMode.SURVIVAL)) return;
|
||||
|
||||
EntityType hordeEntityType = this.hordeMobList.get(this.random.nextInt(this.hordeMobList.size()));
|
||||
if(player.getLocation().getWorld().getEnvironment().equals(World.Environment.THE_END)) hordeEntityType = EntityType.ENDERMITE;
|
||||
int hordeSize = this.random.nextInt(this.hordeMinPopulation, this.hordeMaxPopulation + 1);
|
||||
this.spawnHorde(player, hordeSize, hordeEntityType);
|
||||
}
|
||||
|
||||
public void sendWarningMessage(Player p) {
|
||||
if(!this.getBloodmoonSetting(p)) return;
|
||||
p.sendMessage(Component.text("Der Blutmond waltet in diesem Augenblick!", NamedTextColor.RED));
|
||||
}
|
||||
|
||||
@@ -215,7 +256,7 @@ public class Bloodmoon extends Appliance {
|
||||
Math.cos(spawnRadiant)*this.hordeSpawnDistance
|
||||
);
|
||||
mobSpawnLocation.setY(player.getWorld().getHighestBlockYAt(mobSpawnLocation) + 1);
|
||||
player.getWorld().spawnEntity(mobSpawnLocation, type);
|
||||
player.getWorld().spawnEntity(mobSpawnLocation, type, CreatureSpawnEvent.SpawnReason.NATURAL);
|
||||
player.getWorld().strikeLightningEffect(mobSpawnLocation);
|
||||
}
|
||||
}
|
||||
@@ -269,7 +310,8 @@ public class Bloodmoon extends Appliance {
|
||||
new BloodmoonMonsterDeathListener(),
|
||||
new BloodmoonPlayerJoinListener(),
|
||||
new BloodmoonEntityDamageListener(),
|
||||
new BloodmoonTimeListener()
|
||||
new BloodmoonTimeListener(),
|
||||
new BloodmoonTimeSkipListener()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+7
-2
@@ -2,6 +2,7 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.comm
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
|
||||
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -23,15 +24,19 @@ public class BloodmoonCommand extends ApplianceCommand<Bloodmoon> {
|
||||
|
||||
switch(args[0]) {
|
||||
case "start": {
|
||||
this.getAppliance().startBloodmoon(0L);
|
||||
this.getAppliance().startBloodmoon();
|
||||
sender.sendMessage("Started bloodmoon.");
|
||||
break;
|
||||
}
|
||||
case "stop": {
|
||||
this.getAppliance().stopBloodmoon();
|
||||
this.getAppliance().forceStopBloodmoon();
|
||||
sender.sendMessage("Stopped bloodmoon.");
|
||||
break;
|
||||
}
|
||||
case "time": {
|
||||
sender.sendMessage(String.valueOf(Bukkit.getWorlds().getFirst().getFullTime()));
|
||||
break;
|
||||
}
|
||||
default: throw new Error("No such option: '%s' !".formatted(args[0]));
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -2,6 +2,7 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.list
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
@@ -9,7 +10,9 @@ public class BloodmoonPlayerJoinListener extends ApplianceListener<Bloodmoon> {
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
if(!this.getAppliance().bloodmoonIsActive()) return;
|
||||
this.getAppliance().addPlayerToBossBar(event.getPlayer());
|
||||
this.getAppliance().sendWarningMessage(event.getPlayer());
|
||||
Player player = event.getPlayer();
|
||||
this.getAppliance().addPlayerToBossBar(player);
|
||||
this.getAppliance().startHordeSpawning(1500, player);
|
||||
this.getAppliance().sendWarningMessage(player);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -12,14 +12,14 @@ public class BloodmoonTimeListener extends ApplianceListener<Bloodmoon> {
|
||||
public void onServerTick(ServerTickStartEvent event) {
|
||||
long currentTime = Bukkit.getWorlds().getFirst().getFullTime();
|
||||
if(this.getAppliance().isStartTick(currentTime)) {
|
||||
this.getAppliance().startBloodmoon(currentTime);
|
||||
this.getAppliance().startBloodmoon();
|
||||
return;
|
||||
}
|
||||
if(this.getAppliance().isStartTick(currentTime - this.getAppliance().bloodmoonLength)) {
|
||||
this.getAppliance().stopBloodmoon();
|
||||
this.getAppliance().stopBloodmoonIfInactive();
|
||||
return;
|
||||
}
|
||||
if(currentTime % Ticks.TICKS_PER_SECOND == 0) this.getAppliance().updateBossBar();
|
||||
if(currentTime % Ticks.TICKS_PER_SECOND == 0 && this.getAppliance().bloodmoonIsActive()) this.getAppliance().updateBossBar();
|
||||
if(this.getAppliance().isStartTick(currentTime + this.getAppliance().ticksPerDay)) {
|
||||
this.getAppliance().sendAnnouncementMessages();
|
||||
return;
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerBedEnterEvent;
|
||||
import org.bukkit.event.world.TimeSkipEvent;
|
||||
|
||||
public class BloodmoonTimeSkipListener extends ApplianceListener<Bloodmoon> {
|
||||
@EventHandler
|
||||
public void onTimeSkip(TimeSkipEvent event) {
|
||||
if(this.getAppliance().bloodmoonSkippable || !event.getSkipReason().equals(TimeSkipEvent.SkipReason.NIGHT_SKIP)) {
|
||||
this.getAppliance().stopBloodmoonIfInactive();
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerSleep(PlayerBedEnterEvent event) {
|
||||
if(!this.getAppliance().bloodmoonIsActive()) return;
|
||||
if(this.getAppliance().bloodmoonSkippable) return;
|
||||
if(!event.getBedEnterResult().equals(PlayerBedEnterEvent.BedEnterResult.OK)) return;
|
||||
event.setUseBed(Event.Result.DENY);
|
||||
event.getPlayer().sendActionBar(Component.text("Du kannst während dem Blutmond nicht schlafen"));
|
||||
}
|
||||
}
|
||||
-1
@@ -39,7 +39,6 @@ public class CustomAdvancements extends Appliance {
|
||||
player.getAdvancementProgress(advancement).awardCriteria("criteria");
|
||||
} catch(Exception e) {
|
||||
Main.logger().info("Advancement " + advancementName + " not found! (is Custom Advancements data pack loaded?)");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.mobSilenceNametag;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FirstTestClass extends Appliance {
|
||||
|
||||
public String greetPlayer(Player player) {
|
||||
return "Hello, " + player.getName() + "! Test 2";
|
||||
}
|
||||
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new FirstTestListener());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.mobSilenceNametag;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import org.bukkit.event.EventHandler;
|
||||
|
||||
public class FirstTestListener extends ApplianceListener<FirstTestClass> {
|
||||
@EventHandler
|
||||
public void onPlayerJoin(org.bukkit.event.player.PlayerJoinEvent event) {
|
||||
String greeting = this.getAppliance().greetPlayer(event.getPlayer());
|
||||
event.getPlayer().sendMessage(greeting);
|
||||
}
|
||||
}
|
||||
+12
-11
@@ -51,14 +51,15 @@ 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." +
|
||||
" 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 die˝ser 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
|
||||
@@ -74,11 +75,11 @@ public class Outlawed extends Appliance implements DisplayName.Prefixed {
|
||||
|
||||
void switchLawStatus(Player player) throws OutlawChangeNotPermitted {
|
||||
if(this.getLawStatus(player).equals(Status.FORCED)) {
|
||||
throw new OutlawChangeNotPermitted("Dein Vogelfreistatus wurde als Strafe auferlegt und kann daher nicht verändert werden.");
|
||||
throw new OutlawChangeNotPermitted("Dein PVP-Status wurde als Strafe auferlegt und kann daher nicht verändert werden.");
|
||||
}
|
||||
|
||||
if(this.isTimeout(player)) {
|
||||
throw new OutlawChangeNotPermitted("Du kannst deinen Vogelfreistatus nicht so schnell wechseln. Bitte warte einige Stunden bevor du umschaltest!");
|
||||
throw new OutlawChangeNotPermitted("Du kannst deinen PVP-Status nicht so schnell wechseln. Bitte warte einige Stunden bevor du umschaltest!");
|
||||
}
|
||||
|
||||
this.setLawStatus(player, this.isOutlawed(player) ? Status.DISABLED : Status.VOLUNTARILY);
|
||||
@@ -126,13 +127,13 @@ public class Outlawed extends Appliance implements DisplayName.Prefixed {
|
||||
|
||||
public Component getStatusDescription(Status status) {
|
||||
return switch(status) {
|
||||
case DISABLED -> Component.text("Vogelfreistatus inaktiv: ", NamedTextColor.GREEN)
|
||||
case DISABLED -> Component.text("PVP-Modus inaktiv: ", NamedTextColor.GREEN)
|
||||
.append(Component.text("Es gelten die normalen Regeln!", NamedTextColor.GOLD));
|
||||
|
||||
case VOLUNTARILY, FORCED -> Component.text("Vogelfreistatus aktiv: ", NamedTextColor.RED)
|
||||
case VOLUNTARILY, FORCED -> Component.text("PVP-Modus aktiv: ", NamedTextColor.RED)
|
||||
.append(Component.text(
|
||||
"Du darfst von allen anderen vogelfreien Spielern angegriffen und getötet werden!" +
|
||||
"Wenn du getötet wirst, müssen andere Spieler deine Items nicht zurückerstatten!",
|
||||
"Du darfst von allen anderen PVP-Spielern angegriffen und getötet werden!\n" +
|
||||
"Wenn du getötet wirst, müssen andere Spieler deine Items *nicht* zurückerstatten!",
|
||||
NamedTextColor.GOLD
|
||||
));
|
||||
};
|
||||
@@ -143,7 +144,7 @@ public class Outlawed extends Appliance implements DisplayName.Prefixed {
|
||||
if(this.isOutlawed(player)) {
|
||||
return Component.text("[☠]", NamedTextColor.RED)
|
||||
.hoverEvent(HoverEvent.showText(Component.text(
|
||||
"Vogelfreie Spieler dürfen von anderen vogelfreien Spielern ohne Grund angegriffen werden!"
|
||||
"PVP-Modus Spieler dürfen von anderen vogelfreien Spielern ohne Grund angegriffen werden!"
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class OutlawedCommand extends ApplianceCommand.PlayerChecked<Outlawed> {
|
||||
public static final String commandName = "vogelfrei";
|
||||
public static final String commandName = "pvp";
|
||||
|
||||
public OutlawedCommand() {
|
||||
super(commandName);
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.portableCrafting;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings;
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
|
||||
class OnCraftingBlockUseListener extends ApplianceListener<PortableCrafting> {
|
||||
@EventHandler
|
||||
public void inInteract(PlayerInteractEvent event) {
|
||||
if(!event.getAction().equals(Action.RIGHT_CLICK_AIR)) return;
|
||||
if(!Settings.instance().getSetting(event.getPlayer(), Settings.Key.EnablePortableCrafting, Boolean.class)) return;
|
||||
|
||||
switch(event.getMaterial()) {
|
||||
case CRAFTING_TABLE -> this.getAppliance().openCraftingTable(event.getPlayer());
|
||||
case STONECUTTER -> this.getAppliance().openStonecutter(event.getPlayer());
|
||||
}
|
||||
}
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.portableCrafting;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
|
||||
class OnCraftingTableUseListener extends ApplianceListener<PortableCrafting> {
|
||||
@EventHandler
|
||||
public void inInteract(PlayerInteractEvent event) {
|
||||
if(!event.getAction().equals(Action.RIGHT_CLICK_AIR)) return;
|
||||
if(!event.getMaterial().equals(Material.CRAFTING_TABLE)) return;
|
||||
this.getAppliance().openFor(event.getPlayer());
|
||||
}
|
||||
}
|
||||
+6
-3
@@ -14,13 +14,16 @@ public class PortableCrafting extends Appliance {
|
||||
Settings.instance().declareSetting(PortableCraftingSetting.class);
|
||||
}
|
||||
|
||||
public void openFor(Player player) {
|
||||
if(!Settings.instance().getSetting(player, Settings.Key.EnablePortableCrafting, Boolean.class)) return;
|
||||
public void openCraftingTable(Player player) {
|
||||
player.openWorkbench(null, true);
|
||||
}
|
||||
|
||||
public void openStonecutter(Player player) {
|
||||
player.openStonecutter(null, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new OnCraftingTableUseListener());
|
||||
return List.of(new OnCraftingBlockUseListener());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ public class PortableCraftingSetting extends BoolSetting implements CategorizedS
|
||||
|
||||
@Override
|
||||
protected String description() {
|
||||
return "Erlaubt das öffnen einer Werkbank in der Hand, ohne sie plazieren zu müssen";
|
||||
return "Erlaubt das öffnen einer Werkbank oder einer Steinsäge in der Hand, ohne den Block plazieren zu müssen";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+58
-18
@@ -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.*;
|
||||
@@ -37,6 +39,11 @@ public class Event extends Appliance {
|
||||
DONE
|
||||
}
|
||||
|
||||
public enum EventType {
|
||||
BIG,
|
||||
SMALL
|
||||
}
|
||||
|
||||
Countdown advertiseCountdown = new Countdown(
|
||||
120,
|
||||
announcementData -> Component.text()
|
||||
@@ -50,6 +57,7 @@ public class Event extends Appliance {
|
||||
);
|
||||
public DisplayVillager.ConfigBound villager;
|
||||
private boolean isOpen = false;
|
||||
private EventType eventType;
|
||||
private AdvertisementStatus advertiseStatus = AdvertisementStatus.BEFORE;
|
||||
private UUID roomId;
|
||||
private final List<Reward> pendingRewards = new ArrayList<>();
|
||||
@@ -79,21 +87,31 @@ public class Event extends Appliance {
|
||||
if(this.isOpen) this.roomId = UUID.fromString(this.localConfig().getString("roomId", ""));
|
||||
}
|
||||
|
||||
public void openEvent() {
|
||||
public void openEvent(EventType type) {
|
||||
if(this.isOpen) throw new ApplianceCommand.Error("Es läuft derzeit bereits ein Event!");
|
||||
this.eventType = type;
|
||||
|
||||
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> {
|
||||
ReqResp<EventRepository.CreatedRoom> sessionResponse = this.queryRepository(EventRepository.class).createSession();
|
||||
if(type.equals(EventType.SMALL)) {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> {
|
||||
ReqResp<EventRepository.CreatedRoom> sessionResponse = this.queryRepository(EventRepository.class).createSession();
|
||||
|
||||
if(sessionResponse.status() != HttpStatus.OK)
|
||||
throw new ApplianceCommand.Error("Event-Server meldet Fehler: " + sessionResponse.status());
|
||||
if(sessionResponse.status() != HttpStatus.OK)
|
||||
throw new ApplianceCommand.Error("Event-Server meldet Fehler: " + sessionResponse.status());
|
||||
|
||||
this.isOpen = true;
|
||||
this.roomId = sessionResponse.data().uuid();
|
||||
});
|
||||
this.isOpen = true;
|
||||
this.roomId = sessionResponse.data().uuid();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.isOpen = true;
|
||||
}
|
||||
|
||||
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,21 +127,43 @@ 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));
|
||||
|
||||
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> {
|
||||
ReqResp<EventRepository.QueueRoom.Response> queueResponse = this.queryRepository(EventRepository.class)
|
||||
.queueRoom(new EventRepository.QueueRoom(p.getUniqueId(), this.roomId));
|
||||
if(this.eventType.equals(EventType.SMALL)) {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> {
|
||||
ReqResp<EventRepository.QueueRoom.Response> queueResponse = this.queryRepository(EventRepository.class)
|
||||
.queueRoom(new EventRepository.QueueRoom(p.getUniqueId(), this.roomId));
|
||||
|
||||
if(queueResponse.status() != HttpStatus.OK || queueResponse.data().error() != null) {
|
||||
p.sendMessage(Component.text("Fehler beim Betreten: " + queueResponse.data().error(), NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
if(queueResponse.status() != HttpStatus.OK || queueResponse.data().error() != null) {
|
||||
p.sendMessage(Component.text("Fehler beim Betreten: " + queueResponse.data().error(), NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
p.sendMessage(Component.text("Betrete...", NamedTextColor.GREEN));
|
||||
PluginMessage.connect(p, this.localConfig().getString("connect-server-name"));
|
||||
});
|
||||
p.sendMessage(Component.text("Betrete...", NamedTextColor.GREEN));
|
||||
PluginMessage.connect(p, this.localConfig().getString("connect-server-name"));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
PluginMessage.connect(p, "grand-event");
|
||||
}
|
||||
|
||||
public void endEvent() {
|
||||
|
||||
+15
-1
@@ -7,6 +7,10 @@ import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class EventOpenSessionCommand extends ApplianceCommand<Event> {
|
||||
public EventOpenSessionCommand() {
|
||||
@@ -15,7 +19,17 @@ public class EventOpenSessionCommand extends ApplianceCommand<Event> {
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||
this.getAppliance().openEvent();
|
||||
if(args.length == 0) {
|
||||
this.getAppliance().openEvent(Event.EventType.SMALL);
|
||||
} else {
|
||||
this.getAppliance().openEvent(Event.EventType.valueOf(args[0]));
|
||||
}
|
||||
sender.sendMessage(Component.text("Event-Server gestartet!", NamedTextColor.GREEN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
if(args.length == 1) return Arrays.stream(Event.EventType.values()).map(Enum::toString).toList();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -9,7 +9,6 @@ import eu.mhsl.craftattack.spawn.core.api.HttpStatus;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentBuilder;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -52,7 +51,7 @@ public class Feedback extends Appliance {
|
||||
|
||||
message
|
||||
.append(Component.text("Klicke hier und gib uns Feedback, damit wir dein Spielerlebnis verbessern können!", NamedTextColor.DARK_GREEN)
|
||||
.hoverEvent(HoverEvent.showText(ComponentUtil.clickLink(feedbackUrl))))
|
||||
.append(ComponentUtil.clickLink(feedbackUrl)))
|
||||
.appendNewline()
|
||||
.append(border);
|
||||
|
||||
|
||||
+1
@@ -17,6 +17,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Appliance.Flags(autoload = false, enabled = false)
|
||||
public class WorldMuseum extends Appliance {
|
||||
public DisplayVillager.ConfigBound villager;
|
||||
|
||||
|
||||
+15
-8
@@ -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<Location> 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)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -121,14 +122,20 @@ public class ProjectStart extends Appliance {
|
||||
|
||||
IteratorUtil.worlds(World::getWorldBorder, worldBorder -> worldBorder.setSize(worldBorder.getMaxSize()));
|
||||
IteratorUtil.worlds(world -> IteratorUtil.setGameRules(this.gameRulesAfterStart, false));
|
||||
IteratorUtil.worlds(world -> world.setFullTime(0));
|
||||
Bukkit.getWorlds().getFirst().setFullTime(0);
|
||||
|
||||
this.netherFireLocations.forEach(location -> Objects.requireNonNull(this.startWorld).getBlockAt(location).setType(Material.FIRE));
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
||||
player.setFoodLevel(20);
|
||||
player.setHealth(20);
|
||||
player.getInventory().clear();
|
||||
if(player.getInventory().contains(Material.RECOVERY_COMPASS)) {
|
||||
player.getInventory().clear();
|
||||
player.getInventory().addItem(new ItemStack(Material.RECOVERY_COMPASS));
|
||||
} else {
|
||||
player.getInventory().clear();
|
||||
}
|
||||
|
||||
player.setGameMode(GameMode.SURVIVAL);
|
||||
player.setExp(0);
|
||||
player.setLevel(0);
|
||||
|
||||
+4
-3
@@ -20,9 +20,10 @@ public class Strikes extends Appliance {
|
||||
|
||||
private final Map<Integer, Duration> strikePunishmentMap = Map.of(
|
||||
1, Duration.ofHours(1),
|
||||
2, Duration.ofHours(24),
|
||||
3, Duration.ofDays(3),
|
||||
4, Duration.ofDays(7)
|
||||
2, Duration.ofHours(3),
|
||||
3, Duration.ofDays(1),
|
||||
4, Duration.ofDays(2),
|
||||
5, Duration.ofDays(3)
|
||||
);
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ public class Whitelist extends Appliance {
|
||||
? Floodgate.getBedrockPlayer(player).getUsername()
|
||||
: player.getName();
|
||||
|
||||
if(!user.username().trim().equalsIgnoreCase(purePlayerName))
|
||||
if(!user.username().trim().equalsIgnoreCase(purePlayerName) && !Floodgate.isBedrock(player)) // TODO: Bedrock Namen mit leerzeichen funktionieren nicht, daher die ausnahme bei der NUtzernamenprüfung
|
||||
throw new DisconnectInfo.Throwable(
|
||||
"Nutzername geändert",
|
||||
String.format("Der Name '%s' stimmt nicht mit '%s' überein.", user.username(), player.getName()),
|
||||
|
||||
+1
-1
@@ -12,6 +12,6 @@ class InfectionSpawnListener extends ApplianceListener<ArmadilloInfectionReducer
|
||||
public void onSpawn(CreatureSpawnEvent event) {
|
||||
if(!event.getSpawnReason().equals(CreatureSpawnEvent.SpawnReason.POTION_EFFECT)) return;
|
||||
if(!event.getEntity().getType().equals(EntityType.SILVERFISH)) return;
|
||||
if(ThreadLocalRandom.current().nextDouble() > 0.7) event.setCancelled(true);
|
||||
if(ThreadLocalRandom.current().nextDouble() > 0.8) event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -1,10 +1,12 @@
|
||||
package eu.mhsl.craftattack.spawn.craftattack.appliances.tweaks.silverfishExpReducer;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
|
||||
@Appliance.Flags(enabled = false)
|
||||
class SilverfishDeathListener extends ApplianceListener<SilverfishExpReducer> {
|
||||
@EventHandler
|
||||
public void onDeath(EntityDeathEvent event) {
|
||||
|
||||
+70
-12
@@ -1,32 +1,52 @@
|
||||
package eu.mhsl.craftattack.spawn.event.appliances.deathrun;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.Main;
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners.DeathrunPlayerDamageListener;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners.DeathrunPlayerJoinListener;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners.DeathrunPlayerMoveListener;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners.DeathrunPortalListener;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.eventController.Event;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scorable;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreboardBuilder;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import net.kyori.adventure.util.Ticks;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Appliance.Flags(autoload = false)
|
||||
public class Deathrun extends Appliance implements Event, Scorable {
|
||||
private final EventScoreboardBuilder scoreboardBuilder = new EventScoreboardBuilder(this, 3, 2, 3);
|
||||
private final EventScoreboardBuilder scoreboardBuilder = new EventScoreboardBuilder(this, 3, 2, 0);
|
||||
private final double borderDistance = 100;
|
||||
private final int borderVisibilityDistance = 8;
|
||||
private long durationSeconds;
|
||||
private boolean isBeforeStart = true;
|
||||
private boolean pvpDisabled = true;
|
||||
private final World world = Bukkit.getWorlds().getFirst();
|
||||
private BukkitTask pvpTask;
|
||||
public ArrayList<UUID> previouslyJoinedPlayers = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
World world = Bukkit.getWorlds().getFirst();
|
||||
world.getWorldBorder().setCenter(world.getSpawnLocation());
|
||||
world.getWorldBorder().setSize(20);
|
||||
this.world.getWorldBorder().setCenter(this.world.getSpawnLocation());
|
||||
this.world.getWorldBorder().setSize(20);
|
||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
||||
player.teleport(this.world.getSpawnLocation());
|
||||
this.previouslyJoinedPlayers.add(player.getUniqueId());
|
||||
});
|
||||
this.pvpDisabled = true;
|
||||
}
|
||||
|
||||
public double getBorderDistance() {
|
||||
@@ -37,7 +57,7 @@ public class Deathrun extends Appliance implements Event, Scorable {
|
||||
return this.borderVisibilityDistance;
|
||||
}
|
||||
|
||||
public void spawnParticleWall(Player p, double xMin, double xMax, double yMin, double yMax, double zMin, double zMax) {
|
||||
public void spawnParticles(Player p, double xMin, double xMax, double yMin, double yMax, double zMin, double zMax) {
|
||||
Particle particle = Particle.WAX_ON;
|
||||
|
||||
for (double y = yMin; y <= yMax; y += 0.5) {
|
||||
@@ -51,18 +71,51 @@ public class Deathrun extends Appliance implements Event, Scorable {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
World world = Bukkit.getWorlds().getFirst();
|
||||
world.getWorldBorder().setSize(world.getWorldBorder().getMaxSize());
|
||||
this.world.getWorldBorder().setSize(this.world.getWorldBorder().getMaxSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(long durationSeconds) {
|
||||
this.isBeforeStart = false;
|
||||
this.durationSeconds = durationSeconds;
|
||||
Title title = Title.title(Component.text("Start"), Component.text("Laufe Richtung Osten! (positiv x)"));
|
||||
Bukkit.getOnlinePlayers().forEach(player -> player.showTitle(title));
|
||||
Title title = Title.title(Component.text("Start", NamedTextColor.GOLD), Component.text("Laufe Richtung Osten! (positiv x)", NamedTextColor.YELLOW));
|
||||
// TODO: Soll PvP überhaupt aktiviert werden? Soll Respawn erlaubt sein?
|
||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
||||
player.showTitle(title);
|
||||
player.sendMessage(Component.text("Start! Laufe Richtung Osten (positiv x)!", NamedTextColor.YELLOW));
|
||||
});
|
||||
Bukkit.getScheduler().runTaskLater(
|
||||
Main.instance(),
|
||||
() -> Bukkit.getOnlinePlayers().forEach(player ->
|
||||
player.sendMessage(Component.text("PvP wird in 10 Minuten aktiviert!", NamedTextColor.GOLD))
|
||||
),
|
||||
Ticks.TICKS_PER_SECOND * 5
|
||||
);
|
||||
|
||||
World world = Bukkit.getWorlds().getFirst();
|
||||
world.getWorldBorder().setSize(world.getWorldBorder().getMaxSize());
|
||||
this.world.getWorldBorder().setSize(this.world.getWorldBorder().getMaxSize());
|
||||
this.pvpTask = Bukkit.getScheduler().runTaskLater(
|
||||
Main.instance(),
|
||||
() -> {
|
||||
this.pvpDisabled = false;
|
||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
||||
player.sendMessage(Component.text("PvP ist jetzt aktiviert!", NamedTextColor.GOLD));
|
||||
player.playSound(Sound.sound(org.bukkit.Sound.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.MASTER, 500f, 2f));
|
||||
});
|
||||
},
|
||||
Ticks.TICKS_PER_SECOND * 60 * 10
|
||||
);
|
||||
}
|
||||
|
||||
public boolean isBeforeStart() {
|
||||
return this.isBeforeStart;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return this.world;
|
||||
}
|
||||
|
||||
public boolean isPvpDisabled() {
|
||||
return this.pvpDisabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,6 +127,8 @@ public class Deathrun extends Appliance implements Event, Scorable {
|
||||
public void stop() {
|
||||
this.getScoreboardBuilder().stopAutomaticUpdates();
|
||||
Title title = Title.title(Component.text("Ende!"), Component.empty());
|
||||
if(this.pvpTask != null) this.pvpTask.cancel();
|
||||
this.pvpDisabled = true;
|
||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
||||
player.showTitle(title);
|
||||
player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard());
|
||||
@@ -98,7 +153,10 @@ public class Deathrun extends Appliance implements Event, Scorable {
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(
|
||||
new DeathrunPlayerMoveListener()
|
||||
new DeathrunPlayerMoveListener(),
|
||||
new DeathrunPlayerDamageListener(),
|
||||
new DeathrunPlayerJoinListener(),
|
||||
new DeathrunPortalListener()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.deathrun.Deathrun;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
|
||||
public class DeathrunPlayerDamageListener extends ApplianceListener<Deathrun> {
|
||||
@EventHandler
|
||||
public void onPlayerDamagePlayer(EntityDamageByEntityEvent event) {
|
||||
if(!this.getAppliance().isPvpDisabled()) return;
|
||||
if(!(event.getDamager() instanceof Player)) return;
|
||||
if(!(event.getEntity() instanceof Player)) return;
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerDamage(EntityDamageEvent event) {
|
||||
if(!this.getAppliance().isBeforeStart()) return;
|
||||
if(!(event.getEntity() instanceof Player)) return;
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.deathrun.Deathrun;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
public class DeathrunPlayerJoinListener extends ApplianceListener<Deathrun> {
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if(
|
||||
this.getAppliance().isBeforeStart() ||
|
||||
!this.getAppliance().previouslyJoinedPlayers.contains(player.getUniqueId())
|
||||
) {
|
||||
player.teleport(this.getAppliance().getWorld().getSpawnLocation());
|
||||
player.setGameMode(GameMode.ADVENTURE);
|
||||
this.getAppliance().previouslyJoinedPlayers.add(player.getUniqueId());
|
||||
}
|
||||
|
||||
if(!this.getAppliance().isBeforeStart() && player.getGameMode().equals(GameMode.ADVENTURE)) {
|
||||
player.setGameMode(GameMode.SURVIVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-4
@@ -1,10 +1,12 @@
|
||||
package eu.mhsl.craftattack.spawn.event.appliances.deathrun;
|
||||
package eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.deathrun.Deathrun;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
|
||||
public class DeathrunPlayerMoveListener extends ApplianceListener<Deathrun> {
|
||||
@EventHandler
|
||||
@@ -14,22 +16,34 @@ public class DeathrunPlayerMoveListener extends ApplianceListener<Deathrun> {
|
||||
double minZ = spawnLocation.z() - this.getAppliance().getBorderDistance();
|
||||
double maxZ = spawnLocation.z() + this.getAppliance().getBorderDistance();
|
||||
if(event.getTo().x() < minX + this.getAppliance().getBorderVisibilityDistance()) {
|
||||
this.getAppliance().spawnParticleWall(event.getPlayer(), minX-0.2, minX-0.2, event.getTo().y()-0.5, event.getTo().y()+2.5, event.getTo().z()-1.5, event.getTo().z()+1.5);
|
||||
this.getAppliance().spawnParticles(event.getPlayer(), minX-0.2, minX-0.2, event.getTo().y()-0.5, event.getTo().y()+2.5, event.getTo().z()-1.5, event.getTo().z()+1.5);
|
||||
if(event.getTo().x() < minX) {
|
||||
event.setTo(event.getTo().clone().set(minX, event.getTo().y(), event.getTo().z()));
|
||||
}
|
||||
}
|
||||
if(event.getTo().z() < minZ + this.getAppliance().getBorderVisibilityDistance()) {
|
||||
this.getAppliance().spawnParticleWall(event.getPlayer(), event.getTo().x()-1.5, event.getTo().x()+1.5, event.getTo().y()-0.5, event.getTo().y()+2.5, minZ-0.2, minZ-0.2);
|
||||
this.getAppliance().spawnParticles(event.getPlayer(), event.getTo().x()-1.5, event.getTo().x()+1.5, event.getTo().y()-0.5, event.getTo().y()+2.5, minZ-0.2, minZ-0.2);
|
||||
if(event.getTo().z() < minZ) {
|
||||
event.setTo(event.getTo().clone().set(event.getTo().x(), event.getTo().y(), minZ));
|
||||
}
|
||||
}
|
||||
if(event.getTo().z() > maxZ - this.getAppliance().getBorderVisibilityDistance()) {
|
||||
this.getAppliance().spawnParticleWall(event.getPlayer(), event.getTo().x()-1.5, event.getTo().x()+1.5, event.getTo().y()-0.5, event.getTo().y()+2.5, maxZ+0.2, maxZ+0.2);
|
||||
this.getAppliance().spawnParticles(event.getPlayer(), event.getTo().x()-1.5, event.getTo().x()+1.5, event.getTo().y()-0.5, event.getTo().y()+2.5, maxZ+0.2, maxZ+0.2);
|
||||
if(event.getTo().z() > maxZ) {
|
||||
event.setTo(event.getTo().clone().set(event.getTo().x(), event.getTo().y(), maxZ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerTeleport(PlayerTeleportEvent event) throws Exception {
|
||||
Location spawnLocation = Bukkit.getWorlds().getFirst().getSpawnLocation();
|
||||
double minX = spawnLocation.x() - this.getAppliance().getBorderDistance();
|
||||
double minZ = spawnLocation.z() - this.getAppliance().getBorderDistance();
|
||||
double maxZ = spawnLocation.z() + this.getAppliance().getBorderDistance();
|
||||
if(event.getTo().x() < minX || event.getTo().z() < minZ || event.getTo().z() > maxZ) {
|
||||
event.setCancelled(true);
|
||||
throw new Exception("Player %s teleported outside the border.".formatted(event.getPlayer()));
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.deathrun.Deathrun;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerPortalEvent;
|
||||
|
||||
public class DeathrunPortalListener extends ApplianceListener<Deathrun> {
|
||||
@EventHandler
|
||||
public void onPlayerPortal(PlayerPortalEvent event) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
+113
-8
@@ -3,20 +3,53 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController;
|
||||
import eu.mhsl.craftattack.spawn.core.Main;
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.eventController.commands.EventCommand;
|
||||
import eu.mhsl.craftattack.spawn.core.util.IteratorUtil;
|
||||
import eu.mhsl.craftattack.spawn.core.util.entity.PlayerUtils;
|
||||
import eu.mhsl.craftattack.spawn.core.util.server.PluginMessage;
|
||||
import eu.mhsl.craftattack.spawn.core.util.text.ComponentUtil;
|
||||
import eu.mhsl.craftattack.spawn.core.util.text.Countdown;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.eventController.commands.BigEventCommand;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.eventController.commands.JoinCraftattackCommand;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.util.Ticks;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
|
||||
public class EventController extends Appliance {
|
||||
private List<Appliance> eventAppliances = null;
|
||||
private Event selectedEvent = null;
|
||||
private long timerStart;
|
||||
private int timerTaskId = -1;
|
||||
private long durationMinutes;
|
||||
private final Countdown countdown = new Countdown(
|
||||
10,
|
||||
this::format,
|
||||
this::announce,
|
||||
this::startEvent
|
||||
);
|
||||
|
||||
private final Map<GameRule<Boolean>, Boolean> gameRulesAfterStart = Map.ofEntries(
|
||||
entry(GameRule.DO_DAYLIGHT_CYCLE, true),
|
||||
entry(GameRule.DO_INSOMNIA, true),
|
||||
entry(GameRule.DISABLE_RAIDS, false),
|
||||
entry(GameRule.DO_FIRE_TICK, true),
|
||||
entry(GameRule.DO_ENTITY_DROPS, true),
|
||||
entry(GameRule.DO_PATROL_SPAWNING, true),
|
||||
entry(GameRule.DO_TRADER_SPAWNING, true),
|
||||
entry(GameRule.DO_WEATHER_CYCLE, true),
|
||||
entry(GameRule.FALL_DAMAGE, true),
|
||||
entry(GameRule.FIRE_DAMAGE, true)
|
||||
);
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
@@ -36,6 +69,8 @@ public class EventController extends Appliance {
|
||||
Appliance newAppliance = Main.instance().restartAppliance(appliance.getClass());
|
||||
if(!(newAppliance instanceof Event newEvent)) throw new IllegalArgumentException("Appliance has to implement Event.");
|
||||
this.selectedEvent = newEvent;
|
||||
Bukkit.getOnlinePlayers().forEach(player -> player.setGameMode(GameMode.ADVENTURE));
|
||||
IteratorUtil.worlds(world -> IteratorUtil.setGameRules(this.gameRulesAfterStart, true));
|
||||
}
|
||||
|
||||
public void unloadEvent() {
|
||||
@@ -47,12 +82,62 @@ public class EventController extends Appliance {
|
||||
this.selectedEvent = null;
|
||||
}
|
||||
|
||||
public boolean hasLoadedEvent() {
|
||||
return this.selectedEvent != null;
|
||||
}
|
||||
|
||||
public void scheduleStart(long durationMinutes) {
|
||||
if(!this.hasLoadedEvent()) throw new ApplianceCommand.Error("There is no event selected!");
|
||||
this.durationMinutes = durationMinutes;
|
||||
this.countdown.start();
|
||||
}
|
||||
|
||||
public void cancelStart() {
|
||||
if(this.countdown.isRunning()) this.countdown.cancel();
|
||||
}
|
||||
|
||||
private Component format(Countdown.AnnouncementData data) {
|
||||
return Component.text()
|
||||
.append(ComponentUtil.createRainbowText(this.selectedEvent.getClass().getSimpleName(), 10))
|
||||
.append(Component.text(" startet in ", NamedTextColor.GOLD))
|
||||
.append(Component.text(data.count(), NamedTextColor.AQUA))
|
||||
.append(Component.text(" " + data.unit() + "!", NamedTextColor.GOLD))
|
||||
.build();
|
||||
}
|
||||
|
||||
private void announce(Component message) {
|
||||
IteratorUtil.onlinePlayers(player -> {
|
||||
player.sendMessage(message);
|
||||
player.playSound(Sound.sound(org.bukkit.Sound.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.MASTER, 500f, 1f));
|
||||
});
|
||||
}
|
||||
|
||||
private void startEvent() {
|
||||
this.startEvent(this.durationMinutes);
|
||||
}
|
||||
|
||||
public void startEvent(long durationMinutes) {
|
||||
if(this.selectedEvent == null) throw new ApplianceCommand.Error("There is no event selected!");
|
||||
IteratorUtil.worlds(world -> IteratorUtil.setGameRules(this.gameRulesAfterStart, false));
|
||||
IteratorUtil.worlds(world -> world.setFullTime(0));
|
||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
||||
player.setFoodLevel(20);
|
||||
player.setHealth(20);
|
||||
player.getInventory().clear();
|
||||
player.setGameMode(GameMode.SURVIVAL);
|
||||
player.setExp(0);
|
||||
player.setLevel(0);
|
||||
|
||||
player.playSound(Sound.sound(org.bukkit.Sound.ITEM_GOAT_HORN_SOUND_6, Sound.Source.MASTER, 500f, 1f));
|
||||
|
||||
player.sendMessage(Component.text("Viel Spaß bei %s!".formatted(this.selectedEvent.getClass().getSimpleName()), NamedTextColor.GREEN));
|
||||
|
||||
player.setStatistic(Statistic.TIME_SINCE_REST, 0);
|
||||
PlayerUtils.resetStatistics(player);
|
||||
});
|
||||
this.selectedEvent.start(durationMinutes * 60);
|
||||
if(this.selectedEvent instanceof Scorable scorable && scorable.automaticUpdates()) scorable.getScoreboardBuilder().startAutomaticUpdates();
|
||||
// TODO: possibility for other dimensions
|
||||
this.timerStart = Bukkit.getWorlds().getFirst().getFullTime();
|
||||
this.timerTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(
|
||||
Main.instance(),
|
||||
this::updateTimer,
|
||||
@@ -66,6 +151,20 @@ public class EventController extends Appliance {
|
||||
this.selectedEvent.stop();
|
||||
if(this.timerTaskId != -1) Bukkit.getScheduler().cancelTask(this.timerTaskId);
|
||||
this.timerTaskId = -1;
|
||||
if(this.selectedEvent instanceof Scorable scorable) {
|
||||
String scores = String.join("\n", scorable.getScoreboardBuilder().getScores());
|
||||
Bukkit.getOnlinePlayers().forEach(player -> player.sendMessage(scores));
|
||||
Main.instance().getLogger().info(scores);
|
||||
}
|
||||
|
||||
Bukkit.getScheduler().runTaskLater(
|
||||
Main.instance(),
|
||||
() -> {
|
||||
Bukkit.getOnlinePlayers().forEach(player -> PluginMessage.connect(player, "craftattack"));
|
||||
this.unloadEvent();
|
||||
},
|
||||
Ticks.TICKS_PER_SECOND * 7
|
||||
);
|
||||
}
|
||||
|
||||
public String getSelectedEvent() {
|
||||
@@ -74,12 +173,10 @@ public class EventController extends Appliance {
|
||||
}
|
||||
|
||||
private void updateTimer() {
|
||||
long ticksLeft = this.timerStart - (Bukkit.getWorlds().getFirst().getFullTime() - this.selectedEvent.getDurationSeconds() * Ticks.TICKS_PER_SECOND);
|
||||
long ticksLeft = -(Bukkit.getWorlds().getFirst().getFullTime() - this.selectedEvent.getDurationSeconds() * Ticks.TICKS_PER_SECOND);
|
||||
if(ticksLeft <= 0) {
|
||||
if(this.timerTaskId != -1) Bukkit.getScheduler().cancelTask(this.timerTaskId);
|
||||
this.timerTaskId = -1;
|
||||
this.selectedEvent.stop();
|
||||
Bukkit.getOnlinePlayers().forEach(player -> player.sendActionBar(Component.text("Fertig!")));
|
||||
this.stopEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -92,10 +189,18 @@ public class EventController extends Appliance {
|
||||
return String.format("%02d:%02d:%02d", seconds / 3600, (seconds / 60) % 60, seconds % 60);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(
|
||||
new EventPlayerLoginListener()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
||||
return List.of(
|
||||
new EventCommand()
|
||||
new BigEventCommand(),
|
||||
new JoinCraftattackCommand()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package eu.mhsl.craftattack.spawn.event.appliances.eventController;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
public class EventPlayerLoginListener extends ApplianceListener<EventController> {
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
if(event.getPlayer().isOp()) return;
|
||||
if(this.getAppliance().hasLoadedEvent()) return;
|
||||
event.getPlayer().kick(Component.text("Es ist kein Event geladen."));
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -10,8 +10,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EventCommand extends ApplianceCommand<EventController> {
|
||||
public EventCommand() {
|
||||
public class BigEventCommand extends ApplianceCommand<EventController> {
|
||||
public BigEventCommand() {
|
||||
super("event");
|
||||
}
|
||||
|
||||
@@ -35,12 +35,12 @@ public class EventCommand extends ApplianceCommand<EventController> {
|
||||
}
|
||||
case "start": {
|
||||
if(args.length == 1) {
|
||||
this.getAppliance().startEvent(60 * 2);
|
||||
this.getAppliance().scheduleStart(60 * 2);
|
||||
break;
|
||||
}
|
||||
if(args.length == 2) {
|
||||
try {
|
||||
this.getAppliance().startEvent(Long.parseLong(args[1]));
|
||||
this.getAppliance().scheduleStart(Long.parseLong(args[1]));
|
||||
} catch(NumberFormatException e) {
|
||||
throw new Error("Last argument has to be a long.");
|
||||
}
|
||||
@@ -48,6 +48,7 @@ public class EventCommand extends ApplianceCommand<EventController> {
|
||||
break;
|
||||
}
|
||||
case "stop": {
|
||||
this.getAppliance().cancelStart();
|
||||
this.getAppliance().stopEvent();
|
||||
break;
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package eu.mhsl.craftattack.spawn.event.appliances.eventController.commands;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
|
||||
import eu.mhsl.craftattack.spawn.core.util.server.PluginMessage;
|
||||
import eu.mhsl.craftattack.spawn.event.appliances.eventController.EventController;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class JoinCraftattackCommand extends ApplianceCommand.PlayerChecked<EventController> {
|
||||
public JoinCraftattackCommand() {
|
||||
super("craftattack");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
PluginMessage.connect(this.getPlayer(), "craftattack");
|
||||
}
|
||||
}
|
||||
+48
-10
@@ -8,6 +8,7 @@ import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.util.Ticks;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scoreboard.DisplaySlot;
|
||||
import org.bukkit.scoreboard.Objective;
|
||||
@@ -52,9 +53,6 @@ public class EventScoreboardBuilder {
|
||||
objective.numberFormat(NumberFormat.blank());
|
||||
|
||||
UUID uuid = p.getUniqueId();
|
||||
scoreList.removeIf(e -> e.playerUuid().equals(uuid));
|
||||
scoreList.add(new EventScoreEntry(uuid, p.getName(), this.scorable.getScore(p)));
|
||||
|
||||
scoreList.sort(this.scoreComparator);
|
||||
|
||||
int size = scoreList.size();
|
||||
@@ -92,18 +90,37 @@ public class EventScoreboardBuilder {
|
||||
|
||||
int[] display = indices.distinct().sorted().toArray();
|
||||
|
||||
for (int i = 0; i < display.length; i++) {
|
||||
int idx = display[i];
|
||||
List<String> lines = new ArrayList<>();
|
||||
int prevIdx = -1;
|
||||
int sepNo = 0;
|
||||
|
||||
for (int idx : display) {
|
||||
if (prevIdx != -1 && idx > prevIdx + 1) {
|
||||
lines.add(this.separatorLine(sepNo++));
|
||||
}
|
||||
|
||||
EventScoreEntry entry = scoreList.get(idx);
|
||||
if(!entry.playerUuid().equals(p.getUniqueId())) {
|
||||
lines.add(this.formattedLine(idx, entry.name(), entry.score()));
|
||||
} else {
|
||||
lines.add(ChatColor.YELLOW + this.formattedLine(idx, entry.name(), entry.score()) + ChatColor.RESET);
|
||||
}
|
||||
|
||||
String line = this.formattedLine(idx, entry.name(), entry.score());
|
||||
prevIdx = idx;
|
||||
}
|
||||
|
||||
objective.getScore(line).setScore(display.length - i);
|
||||
int score = lines.size();
|
||||
for (String line : lines) {
|
||||
objective.getScore(line).setScore(score--);
|
||||
}
|
||||
|
||||
return scoreboard;
|
||||
}
|
||||
|
||||
private String separatorLine(int n) {
|
||||
return ChatColor.GRAY + "..." + ChatColor.RESET + " ".repeat(n);
|
||||
}
|
||||
|
||||
|
||||
public void startAutomaticUpdates() {
|
||||
this.scoreboardUpdateTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(
|
||||
@@ -120,8 +137,19 @@ public class EventScoreboardBuilder {
|
||||
}
|
||||
|
||||
private void updateScore(Player p) {
|
||||
this.playerScores.removeIf(entry -> entry.playerUuid().equals(p.getUniqueId()));
|
||||
this.playerScores.add(new EventScoreEntry(p.getUniqueId(), p.getName(), this.scorable.getScore(p)));
|
||||
EventScoreEntry previousEntry = this.playerScores.stream()
|
||||
.filter(entry -> entry.playerUuid().equals(p.getUniqueId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if(previousEntry == null) {
|
||||
this.playerScores.add(new EventScoreEntry(p.getUniqueId(), p.getName(), this.scorable.getScore(p)));
|
||||
return;
|
||||
}
|
||||
int currentScore = this.scorable.getScore(p);
|
||||
if(previousEntry.score() < currentScore) {
|
||||
this.playerScores.removeIf(entry -> entry.playerUuid().equals(p.getUniqueId()));
|
||||
this.playerScores.add(new EventScoreEntry(p.getUniqueId(), p.getName(), currentScore));
|
||||
}
|
||||
}
|
||||
|
||||
public void updateScoreboards() {
|
||||
@@ -134,7 +162,17 @@ public class EventScoreboardBuilder {
|
||||
|
||||
private String formattedLine(int place, String name, int score) {
|
||||
name = this.trimName(name);
|
||||
return "%s. %s: %s".formatted(place+1, name, score);
|
||||
return "%s. %s : %s".formatted(place+1, name, score);
|
||||
}
|
||||
|
||||
public List<String> getScores() {
|
||||
List<EventScoreEntry> scoreList = new ArrayList<>(this.playerScores);
|
||||
scoreList.sort(this.scoreComparator);
|
||||
ArrayList<String> result = new ArrayList<>();
|
||||
for(int i = 0; i < scoreList.size(); i++) {
|
||||
result.add(this.formattedLine(i, scoreList.get(i).name(), scoreList.get(i).score()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String trimName(String name) {
|
||||
|
||||
Reference in New Issue
Block a user