diff --git a/common/build.gradle b/common/build.gradle index 578064a..f9f7a33 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -4,4 +4,5 @@ dependencies { compileOnly 'io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT' compileOnly 'org.geysermc.floodgate:api:2.2.2-SNAPSHOT' implementation 'org.apache.httpcomponents:httpclient:4.5.14' + implementation 'com.sparkjava:spark-core:2.9.4' } diff --git a/core/src/main/java/eu/mhsl/craftattack/spawn/core/util/text/Countdown.java b/core/src/main/java/eu/mhsl/craftattack/spawn/core/util/text/Countdown.java index bb5c7b0..7ba6540 100644 --- a/core/src/main/java/eu/mhsl/craftattack/spawn/core/util/text/Countdown.java +++ b/core/src/main/java/eu/mhsl/craftattack/spawn/core/util/text/Countdown.java @@ -34,12 +34,12 @@ public class Countdown { this.onDone = onDone; this.defaultAnnouncements = count -> { - if(this.current > 60 && this.current % 60 == 0) { - return new AnnouncementData(this.current / 60, "Minuten"); + if(count > 60 && count % 60 == 0) { + return new AnnouncementData(count / 60, "Minuten"); } - if(this.current <= 60 && (this.current <= 10 || this.current % 10 == 0)) { - return new AnnouncementData(this.current, "Sekunden"); + if(count <= 60 && (count <= 10 || count % 10 == 0)) { + return new AnnouncementData(count, "Sekunden"); } return null; @@ -87,7 +87,7 @@ public class Countdown { if(this.isDone()) { this.onDone.run(); - this.cancel(); + this.cancelIfRunning(); } } diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/Task.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/Task.java new file mode 100644 index 0000000..2c6bfa8 --- /dev/null +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/Task.java @@ -0,0 +1,6 @@ +package eu.mhsl.craftattack.spawn.varo.appliances.internal.teamTasks; + +public interface Task { + void stopTask(); + boolean isRunning(); +} diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/TeamTasks.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/TeamTasks.java index 37f66f5..6364b05 100644 --- a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/TeamTasks.java +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/TeamTasks.java @@ -4,7 +4,6 @@ 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.varo.appliances.metaGameplay.teams.VaroTeam; -import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; import java.util.HashMap; @@ -20,25 +19,25 @@ public class TeamTasks extends Appliance { TIME_KICK } - private final Map> tasks = new HashMap<>(); + private final Map> tasks = new HashMap<>(); - private Map getTeamTasks(VaroTeam team) { + private Map getTeamTasks(VaroTeam team) { return this.tasks.computeIfAbsent(team, varoTeam -> new HashMap<>()); } - public Map getRunningTeamTasks(VaroTeam team) { + public Map getRunningTeamTasks(VaroTeam team) { return this.getTeamTasks(team).entrySet().stream() - .filter(entry -> !entry.getValue().isCancelled()) + .filter(entry -> entry.getValue().isRunning()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } public void cancelTeamTasks(VaroTeam team) { Main.logger().info(String.format("All TeamTasks for Team %s were cancelled: %s", team.name, this.getRunningTeamTasks(team))); - this.getTeamTasks(team).forEach((type, bukkitTask) -> bukkitTask.cancel()); + this.getTeamTasks(team).forEach((type, bukkitTask) -> bukkitTask.stopTask()); } - public void addTask(VaroTeam team, Type type, BukkitTask runnable) { - if(this.getTeamTasks(team).containsKey(type) && !this.getTeamTasks(team).get(type).isCancelled()) { + public void addTask(VaroTeam team, Type type, Task runnable) { + if(this.getTeamTasks(team).containsKey(type) && this.getTeamTasks(team).get(type).isRunning()) { throw new IllegalStateException(String.format("Task %s for Team %s was already running!", type.name(), team.name)); } diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/TeamTasksCommand.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/TeamTasksCommand.java index fc39f21..fd16e83 100644 --- a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/TeamTasksCommand.java +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/TeamTasksCommand.java @@ -28,7 +28,7 @@ public class TeamTasksCommand extends ApplianceCommand { sender.sendMessage( tasks.entrySet() .stream() - .map(entry -> String.format("%s: %d", entry.getKey().name(), entry.getValue().getTaskId())) + .map(entry -> String.format("%s: %s", entry.getKey().name(), entry.getValue().getClass().getSimpleName())) .collect(Collectors.joining("\n")) ); } diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/tasks/BukkitTeamTask.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/tasks/BukkitTeamTask.java new file mode 100644 index 0000000..0d366ff --- /dev/null +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/tasks/BukkitTeamTask.java @@ -0,0 +1,16 @@ +package eu.mhsl.craftattack.spawn.varo.appliances.internal.teamTasks.tasks; + +import eu.mhsl.craftattack.spawn.varo.appliances.internal.teamTasks.Task; +import org.bukkit.scheduler.BukkitTask; + +public abstract class BukkitTeamTask implements Task, BukkitTask { + @Override + public void stopTask() { + this.cancel(); + } + + @Override + public boolean isRunning() { + return !this.isCancelled(); + } +} diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/tasks/CountdownTeamTask.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/tasks/CountdownTeamTask.java new file mode 100644 index 0000000..16ba024 --- /dev/null +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/internal/teamTasks/tasks/CountdownTeamTask.java @@ -0,0 +1,24 @@ +package eu.mhsl.craftattack.spawn.varo.appliances.internal.teamTasks.tasks; + +import eu.mhsl.craftattack.spawn.core.util.text.Countdown; +import eu.mhsl.craftattack.spawn.varo.appliances.internal.teamTasks.Task; +import net.kyori.adventure.text.Component; + +import java.util.function.Consumer; +import java.util.function.Function; + +public class CountdownTeamTask extends Countdown implements Task { + public CountdownTeamTask(int countdownFrom, Function announcementBuilder, Consumer announcementConsumer, Runnable onDone) { + super(countdownFrom, announcementBuilder, announcementConsumer, onDone); + } + + @Override + public void stopTask() { + super.cancelIfRunning(); + } + + @Override + public boolean isRunning() { + return !super.isDone(); + } +} diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/ConnectivityChangeListener.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/ConnectivityChangeListener.java index a359cf1..d9c7aea 100644 --- a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/ConnectivityChangeListener.java +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/ConnectivityChangeListener.java @@ -8,17 +8,21 @@ import org.bukkit.event.player.AsyncPlayerPreLoginEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; +import java.util.Objects; + class ConnectivityChangeListener extends ApplianceListener { @EventHandler public void onLogin(AsyncPlayerPreLoginEvent event) { boolean result = this.getAppliance().canLogin(event.getUniqueId()); - event.kickMessage(new DisconnectInfo( - "Kein Teilnehmer", - "Du bist nicht als Teilnehmer registriert oder bist ausgeschieden!", - "Sollte dies ein Fehler sein, kontaktiere bitte einen Admin.", - event.getUniqueId() - ).getComponent()); - if(!result) event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); + if(!result) { + event.kickMessage(new DisconnectInfo( + "Kein Teilnehmer", + "Du bist nicht als Teilnehmer registriert oder bist ausgeschieden!", + "Sollte dies ein Fehler sein, kontaktiere bitte einen Admin.", + event.getUniqueId() + ).getComponent()); + event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); + } } @EventHandler @@ -37,6 +41,7 @@ class ConnectivityChangeListener extends ApplianceListener { } VaroTeam team = Main.instance().getAppliance(Teams.class).getTeamFromPlayer(event.getPlayer().getUniqueId()); + Objects.requireNonNull(team, "Team not found for player " + event.getPlayer().getUniqueId()); Main.logger().info(String.format("Team %s got a Strike, because they %s left early!", team.name, event.getPlayer().getName())); // TODO: strike team this.getAppliance().enforceTeamLeave(event.getPlayer()); diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/Teams.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/Teams.java index 4735c4e..56ab8e5 100644 --- a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/Teams.java +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/Teams.java @@ -3,10 +3,12 @@ package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams; 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.text.Countdown; import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo; import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.displayName.DisplayName; import eu.mhsl.craftattack.spawn.varo.api.repositories.TeamRepository; import eu.mhsl.craftattack.spawn.varo.appliances.internal.teamTasks.TeamTasks; +import eu.mhsl.craftattack.spawn.varo.appliances.internal.teamTasks.tasks.CountdownTeamTask; import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.joinProtection.JoinProtection; import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.playTimer.PlayTimer; import net.kyori.adventure.text.Component; @@ -17,7 +19,6 @@ import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.event.Listener; -import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -56,7 +57,7 @@ public class Teams extends Appliance implements DisplayName.Prefixed { updatedTeam.color() ); this.teams.add(newTeam); - Main.logger().info("Added missing team to Teams registry: " + newTeam); + Main.logger().info("Added missing team to Teams registry: " + newTeam.name); } } } @@ -70,10 +71,20 @@ public class Teams extends Appliance implements DisplayName.Prefixed { public boolean canLogin(UUID playerId) { OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerId); - if(offlinePlayer.isOp()) return true; + if(offlinePlayer.isOp()) { + Main.logger().info(String.format("Allowing player %s to login, because he ist OP!", playerId)); + return true; + } - return this.teams.stream() - .anyMatch(varoTeam -> varoTeam.hasMember(playerId) && !Objects.requireNonNull(varoTeam.getMemberById(playerId)).isDead); + Optional team = this.teams.stream() + .filter(varoTeam -> varoTeam.hasMember(playerId) && !Objects.requireNonNull(varoTeam.getMemberById(playerId)).isDead) + .findAny(); + + team.ifPresentOrElse( + found -> Main.logger().info(String.format("Player %s is in Team %s!", playerId, found.name)), + () -> Main.logger().info(String.format("No valid Team found for %s (or he is in a Team but dead)!", playerId)) + ); + return team.isPresent(); } public @Nullable VaroTeam getTeamFromPlayer(UUID playerId) { @@ -143,12 +154,30 @@ public class Teams extends Appliance implements DisplayName.Prefixed { .ifPresentOrElse( member -> team.kickTeam(teamNotCompleteInfo), () -> { - BukkitTask kickTask = Bukkit.getScheduler().runTaskLater( - Main.instance(), - team::timeOverKick, - Ticks.TICKS_PER_SECOND * 60 * PlayTimer.PLAYTIME_MINUTES + Main.logger().info(String.format("Starting Time countdown for Team %s with %d", team.name, PlayTimer.PLAYTIME_MINUTES)); + CountdownTeamTask countdown = new CountdownTeamTask( + 60 * PlayTimer.PLAYTIME_MINUTES, + announcementData -> Component.text( + String.format("Es verbleiben noch %d %s Spielzeit!", announcementData.count(), announcementData.unit()), + NamedTextColor.RED + ), + component -> team.getOnlinePlayers().forEach(player -> player.sendMessage(component)), + team::timeOverKick ); - this.queryAppliance(TeamTasks.class).addTask(team, TeamTasks.Type.TIME_KICK, kickTask); + countdown.setDefaultAnnouncements(count -> { + if(count > 300) return null; + if(count > 60 && count % 60 == 0) { + return new Countdown.AnnouncementData(count / 60, "Minuten"); + } + + if(count <= 30 && (count <= 10 || count % 10 == 0)) { + return new Countdown.AnnouncementData(count, "Sekunden"); + } + + return null; + }); + countdown.start(); + this.queryAppliance(TeamTasks.class).addTask(team, TeamTasks.Type.TIME_KICK, countdown); } ), Ticks.TICKS_PER_SECOND * (JoinProtection.resistanceDuration / 2)