Implement start-delay-timer.

The StartDelayTimer wraps the AutoStartTimer and provides a means of
"locking" the lobby until a configurable time has passed. During this
time, it is possible for other players to join the lobby and ready up,
but the arena will not start until the StartDelayTimer has run out,
after which the AutoStartTimer is started (if applicable).

New per-arena setting: start-delay-timer: [seconds]
New announcement: arena-start-delay
This commit is contained in:
garbagemule 2014-02-25 04:36:35 +01:00
parent 5e83c4e7e9
commit 7d14b1b10a
5 changed files with 128 additions and 5 deletions

View File

@ -1,7 +1,7 @@
name: MobArena
author: garbagemule
main: com.garbagemule.MobArena.MobArena
version: 0.96.2.11
version: 0.96.2.12
softdepend: [Multiverse-Core,Towny,Heroes,MagicSpells,Vault]
commands:
ma:

View File

@ -30,6 +30,7 @@ lock-food-level: true
player-time-in-arena: world
auto-ignite-tnt: false
auto-start-timer: 0
start-delay-timer: 0
auto-ready: false
use-class-chests: false
display-waves-as-level: false

View File

@ -35,6 +35,7 @@ import com.garbagemule.MobArena.util.*;
import com.garbagemule.MobArena.util.inventory.InventoryManager;
import com.garbagemule.MobArena.util.inventory.InventoryUtils;
import com.garbagemule.MobArena.util.timer.AutoStartTimer;
import com.garbagemule.MobArena.util.timer.StartDelayTimer;
import com.garbagemule.MobArena.waves.*;
import com.garbagemule.MobArena.ScoreboardManager.NullScoreboardManager;
@ -92,6 +93,7 @@ public class ArenaImpl implements Arena
private List<ItemStack> entryFee;
private TimeStrategy timeStrategy;
private AutoStartTimer autoStartTimer;
private StartDelayTimer startDelayTimer;
private boolean isolatedChat;
// Scoreboards
@ -159,6 +161,7 @@ public class ArenaImpl implements Arena
this.allowAnimals = world.getAllowAnimals();
this.autoStartTimer = new AutoStartTimer(this);
this.startDelayTimer = new StartDelayTimer(this, autoStartTimer);
this.isolatedChat = settings.getBoolean("isolated-chat", false);
@ -384,7 +387,12 @@ public class ArenaImpl implements Arena
return false;
}
// Stop the auto-start-timer
// Check if start-delay is over
if (startDelayTimer.isRunning()) {
return false;
}
// Stop the auto-start-timer regardless
autoStartTimer.stop();
// Fire the event and check if it's been cancelled.
@ -545,6 +553,8 @@ public class ArenaImpl implements Arena
Messenger.tell(p, Msg.LEAVE_NOT_READY);
}
// Stop start-delay-timer and start arena
startDelayTimer.stop();
startArena();
}
@ -591,14 +601,18 @@ public class ArenaImpl implements Arena
arenaPlayerMap.put(p, new ArenaPlayer(p, this, plugin));
// Start the auto-start-timer
autoStartTimer.start();
// Start the start-delay-timer if applicable
if (!autoStartTimer.isRunning()) {
startDelayTimer.start();
}
// Notify player of joining
Messenger.tell(p, Msg.JOIN_PLAYER_JOINED);
// Notify player of time left
if (autoStartTimer.isRunning()) {
if (startDelayTimer.isRunning()) {
Messenger.tell(p, Msg.ARENA_START_DELAY, "" + startDelayTimer.getRemaining() / 20l);
} else if (autoStartTimer.isRunning()) {
Messenger.tell(p, Msg.ARENA_AUTO_START, "" + autoStartTimer.getRemaining() / 20l);
}

View File

@ -12,6 +12,7 @@ public enum Msg {
ARENA_JOIN_GLOBAL("Arena &e%&r is about to start! Type &e/ma j %&r to join!"),
ARENA_LBOARD_NOT_FOUND("That arena does not have a leaderboard set up."),
ARENA_AUTO_START("Arena will auto-start in &c%&r seconds."),
ARENA_START_DELAY("Arena can start in &e%&r seconds."),
JOIN_NOT_ENABLED("MobArena is not enabled."),
JOIN_IN_OTHER_ARENA("You are already in an arena! Leave that one first."),
JOIN_ARENA_NOT_ENABLED("This arena is not enabled."),

View File

@ -0,0 +1,107 @@
package com.garbagemule.MobArena.util.timer;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.Msg;
import com.garbagemule.MobArena.framework.Arena;
/**
* The StartDelayTimer is a self-contained CountdownTimer (i.e. it is its own
* callback), which prevents an arena from starting until the timer finishes.
* It contains an instance of the arena's auto-start-timer, and will start it
* when the start-delay is over.
* <p>
* The timer is preprogrammed with a series of tick interval triggers, such
* that the timer only ticks when the time remaining matches one of these
* triggers. When the timer ticks, the lobby players are informed about the
* time remaining, and when the timer finishes, the arena's auto-start-timer
* is started. If the {@code display-timer-as-level} flag is set, the timer
* will tick once per second, updating the player levels.
* <p>
* The timer realizes a semi-"Null Object" pattern if the duration (i.e. the
* value of the start-delay-timer setting) is 0, where calling the timer's
* {@link #start()} method only starts the auto-start-timer.
*/
public class StartDelayTimer extends CountdownTimer implements TimerCallback {
private Arena arena;
private CountdownTimer autoStartTimer;
private TimerCallback internalCallback;
/**
* Create a StartDelayTimer for the given arena.
* <p>
* The duration is determined from the {@code start-delay-timer} arena
* setting. If the value is non-positive, the timer acts as a type of
* Null Object, allowing it to be safely used for arenas that do not
* have a start-delay-timer, skipping the start-delay and going directly
* to the auto-start-timer.
*
* @param arena the arena the timer is responsible for
* @param autoStartTimer the auto-start-timer of the arena
*/
public StartDelayTimer(Arena arena, CountdownTimer autoStartTimer) {
super(arena.getPlugin());
super.setCallback(this);
this.arena = arena;
this.autoStartTimer = autoStartTimer;
// Set the duration
long duration = arena.getSettings().getInt("start-delay-timer", 0) * 20l;
setDuration(Math.max(0l, duration));
// Choose level- or chat-callback
boolean level = arena.getSettings().getBoolean("display-timer-as-level", false);
if (level) {
internalCallback = new LevelCallback(arena, this);
} else {
int[] triggers = {30, 10, 5, 4, 3, 2, 1};
internalCallback = new ChatCallback(arena, Msg.ARENA_START_DELAY, this, triggers);
}
}
@Override
public synchronized void start() {
// Start auto-start-timer if arena has no start-delay
if (super.getDuration() > 0) {
super.start();
} else {
autoStartTimer.start();
}
}
@Override
public void onStart() {
internalCallback.onStart();
}
@Override
public void onStop() {
internalCallback.onStop();
}
@Override
public void onTick() {
// TODO: Remove this if no one reports issues
if (arena.isRunning() || arena.getPlayersInLobby().isEmpty()) {
Messenger.severe("START DELAY TIMER WAS NOT STOPPED!");
Messenger.severe(" Please make a ticket and inform me about this at:");
Messenger.severe(" http://dev.bukkit.org/bukkit-plugins/mobarena/tickets/");
stop();
return;
}
internalCallback.onTick();
}
@Override
public void onFinish() {
// Start either the arena or the auto-start-timer
if (!arena.startArena()) {
autoStartTimer.start();
// Notify players of auto-start-timer duration
if (autoStartTimer.isRunning()) {
Messenger.announce(arena, Msg.ARENA_AUTO_START, "" + autoStartTimer.getRemaining() / 20l);
}
}
}
}