package tc.oc.pgm.flag.state; import java.util.Collections; import java.util.Objects; import net.md_5.bungee.api.ChatColor; import org.bukkit.Location; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerMoveEvent; import java.time.Duration; import java.time.Instant; import tc.oc.commons.bukkit.event.CoarsePlayerMoveEvent; import tc.oc.commons.core.scheduler.Task; import tc.oc.commons.core.util.TimeUtils; import tc.oc.pgm.events.PlayerLeavePartyEvent; import tc.oc.pgm.match.MatchPlayer; import tc.oc.pgm.match.MatchScope; import tc.oc.pgm.match.ParticipantState; import tc.oc.pgm.match.Party; import tc.oc.pgm.spawns.events.ParticipantDespawnEvent; import tc.oc.pgm.teams.Team; import tc.oc.pgm.events.BlockTransformEvent; import tc.oc.pgm.goals.events.GoalEvent; import tc.oc.pgm.flag.Flag; import tc.oc.pgm.flag.Post; import tc.oc.pgm.flag.event.FlagCaptureEvent; import tc.oc.pgm.flag.event.FlagStateChangeEvent; import tc.oc.pgm.teams.TeamMatchModule; import javax.annotation.Nullable; /** * Base class for all {@link Flag} states */ public abstract class BaseState implements Runnable, State { protected final Flag flag; protected final Post post; protected final Instant enterTime; protected @Nullable Long remainingTicks; private Task task; protected BaseState(Flag flag, Post post) { this.flag = flag; this.post = post; this.enterTime = Instant.now(); } @Override public String toString() { return this.getClass().getSimpleName(); } /** * Called just after the flag's state has been changed to this object. * * This method is NOT allowed to transition this flag into any other state, and doing so * will throw an exception. Care must be taken that any events fired cannot cause another * transition for this flag. Transitioning other flags is OK. * * If this state wants to immediately transition, it should return zero from {@link #getDuration}, * which will cause {@link #finishCountdown} to be called after this method returns. */ public void enterState() { this.task = this.flag.getMatch().getScheduler(MatchScope.LOADED).createRepeatingTask(1, 1, this); } public void leaveState() { if(this.task != null) { this.task.cancel(); this.task = null; } } @Override public Iterable<Location> getProximityLocations(ParticipantState player) { return Collections.emptySet(); } @Override public boolean isCurrent() { return this.flag.isCurrent(this); } protected @Nullable Duration getDuration() { return null; } public void startCountdown() { Duration duration = getDuration(); if(duration != null) { if(Duration.ZERO.equals(duration)) { this.finishCountdown(); } else if(!TimeUtils.isInfPositive(duration)) { this.remainingTicks = duration.toMillis() / 50; } } } protected boolean isCountingDown() { return this.flag.getMatch().isRunning() && this.remainingTicks != null && this.remainingTicks > 0; } protected long getRemainingSeconds() { return this.remainingTicks == null ? -1 : (this.remainingTicks + 19) / 20; } @Override public void run() { this.tickLoaded(); if(this.flag.getMatch().isRunning()) this.tickRunning(); } public void tickLoaded() { } public void tickRunning() { if(this.isCountingDown()) { long before = this.getRemainingSeconds(); if(--this.remainingTicks == 0) { this.finishCountdown(); } long after = this.getRemainingSeconds(); if(before != after) { this.tickSeconds(after); } } } protected void tickSeconds(long seconds) { } protected void finishCountdown() { } @Override public boolean isCarrying(MatchPlayer player) { return false; } @Override public boolean isCarrying(ParticipantState player) { MatchPlayer matchPlayer = player.getMatchPlayer(); return matchPlayer != null && isCarrying(matchPlayer); } @Override public boolean isCarrying(Party party) { return false; } @Override public Post getPost() { return this.post; } @Override public boolean isAtPost(Post post) { return Objects.equals(post, this.post); } @Override public @Nullable Team getController() { if(this.post.getOwner() != null) { return this.flag.getMatch().needMatchModule(TeamMatchModule.class).team(this.post.getOwner()); } else { return null; } } public ChatColor getStatusColor(Party viewer) { return this.flag.getChatColor(); } public ChatColor getLabelColor(Party viewer) { if(this.flag.hasMultipleControllers()) { Team controller = this.getController(); return controller != null ? controller.getColor() : ChatColor.WHITE; } else { return ChatColor.WHITE; } } public String getStatusText(Party viewer) { if(this.isCountingDown()) { return String.valueOf(this.getRemainingSeconds()); } else { return this.getStatusSymbol(viewer); } } public abstract String getStatusSymbol(Party viewer); public void onEvent(GoalEvent event) { } public void onEvent(FlagStateChangeEvent event) { } public void onEvent(FlagCaptureEvent event) { } public void onEvent(PlayerMoveEvent event) { } public void onEvent(CoarsePlayerMoveEvent event) { } public void onEvent(BlockTransformEvent event) { } public void onEvent(PlayerDropItemEvent event) { } public void onEvent(ParticipantDespawnEvent event) { } public void onEvent(PlayerLeavePartyEvent event) { } public void onEvent(InventoryClickEvent event) { } public void onEvent(EntityDamageEvent event) { } }