diff --git a/src/com/massivecraft/massivecore/engine/EngineMassiveCorePlayerState.java b/src/com/massivecraft/massivecore/engine/EngineMassiveCorePlayerState.java index d8049034..3d1bd72a 100644 --- a/src/com/massivecraft/massivecore/engine/EngineMassiveCorePlayerState.java +++ b/src/com/massivecraft/massivecore/engine/EngineMassiveCorePlayerState.java @@ -11,9 +11,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.player.AsyncPlayerPreLoginEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerLoginEvent; -import org.bukkit.event.player.PlayerQuitEvent; import com.massivecraft.massivecore.Engine; -import com.massivecraft.massivecore.MassiveCore; import com.massivecraft.massivecore.PlayerState; import com.massivecraft.massivecore.event.EventMassiveCorePlayerLeave; import com.massivecraft.massivecore.util.MUtil; @@ -36,10 +34,10 @@ public class EngineMassiveCorePlayerState extends Engine { if ( ! active) return; - idToState.clear(); + this.idToState.clear(); for (Player player : MUtil.getOnlinePlayers()) { - idToState.put(player.getUniqueId(), PlayerState.JOINED); + this.idToState.put(player.getUniqueId(), PlayerState.JOINED); } } @@ -47,30 +45,88 @@ public class EngineMassiveCorePlayerState extends Engine // STATE STORAGE // -------------------------------------------- // - protected Map idToState = new ConcurrentHashMap(); - - public PlayerState getState(UUID id) - { - PlayerState ret = this.idToState.get(id); - if (ret == null) ret = PlayerState.LEFT; - return ret; - } + private Map idToState = new ConcurrentHashMap(); public PlayerState getState(Player player) { - return this.getState(player.getUniqueId()); + if (player == null) throw new NullPointerException("player"); + if (MUtil.isntPlayer(player)) return PlayerState.JOINED; + UUID id = player.getUniqueId(); + return this.getState(id); + } + + public PlayerState getState(UUID id) + { + if (id == null) throw new NullPointerException("id"); + PlayerState ret = this.idToState.get(id); + if (ret == null) ret = PlayerState.LEFT; + return ret; + } + + public void setState(Player player, PlayerState state, boolean delayed, PlayerState replaceable) + { + if (player == null) throw new NullPointerException("player"); + if (MUtil.isntPlayer(player)) return; + UUID id = player.getUniqueId(); + this.setState(id, state, delayed, replaceable); + } + + public void setState(final UUID id, final PlayerState state, boolean delayed, final PlayerState replaceable) + { + // Delayed! + if (delayed) + { + Bukkit.getScheduler().runTask(this.getPlugin(), new Runnable() + { + @Override + public void run() + { + EngineMassiveCorePlayerState.this.setState(id, state, false, replaceable); + } + }); + return; + } + + // Immediately! + + // Before + PlayerState before = this.idToState.get(id); + if (before == null) before = PlayerState.LEFT; + + // After + PlayerState after = state; + if (after == null) after = PlayerState.LEFT; + + // NoChange + if (before == after) return; + + // Not Replaceable + if (replaceable != null && replaceable != before) return; + + // Perform + if (after != PlayerState.LEFT) + { + this.idToState.put(id, after); + } + else + { + this.idToState.remove(id); + } } // -------------------------------------------- // // LOGASYNC // -------------------------------------------- // + // AsyncPlayerPreLoginEvent: LOWEST and MONITOR @EventHandler(priority = EventPriority.LOWEST) public void logasync(AsyncPlayerPreLoginEvent event) { - final UUID id = event.getUniqueId(); - - this.idToState.put(id, PlayerState.LOGASYNC); + UUID id = event.getUniqueId(); + PlayerState state = PlayerState.LOGASYNC; + boolean delayed = false; + PlayerState replaceable = PlayerState.LEFT; + this.setState(id, state, delayed, replaceable); } @EventHandler(priority = EventPriority.MONITOR) @@ -79,23 +135,26 @@ public class EngineMassiveCorePlayerState extends Engine // If the player was denied entrance they are now offline. if (event.getLoginResult() == AsyncPlayerPreLoginEvent.Result.ALLOWED) return; - final UUID id = event.getUniqueId(); - - this.idToState.remove(id); + UUID id = event.getUniqueId(); + PlayerState state = PlayerState.LEFT; + boolean delayed = false; // We would actually like to delay but this only works properly for synchronous events. + PlayerState replaceable = PlayerState.LOGASYNC; + this.setState(id, state, delayed, replaceable); } // -------------------------------------------- // // LOGSYNC // -------------------------------------------- // + // PlayerLoginEvent: LOWEST and MONITOR DELAYED @EventHandler(priority = EventPriority.LOWEST) public void logsync(PlayerLoginEvent event) { - final Player player = event.getPlayer(); - if (MUtil.isntPlayer(player)) return; - final UUID id = player.getUniqueId(); - - this.idToState.put(id, PlayerState.LOGSYNC); + Player player = event.getPlayer(); + PlayerState state = PlayerState.LOGSYNC; + boolean delayed = false; + PlayerState replaceable = null; + this.setState(player, state, delayed, replaceable); } @EventHandler(priority = EventPriority.MONITOR) @@ -104,74 +163,71 @@ public class EngineMassiveCorePlayerState extends Engine // If the player was denied entrance they are now offline. if (event.getResult() == PlayerLoginEvent.Result.ALLOWED) return; - final Player player = event.getPlayer(); - if (MUtil.isntPlayer(player)) return; - final UUID id = player.getUniqueId(); - - this.idToState.remove(id); + Player player = event.getPlayer(); + PlayerState state = PlayerState.LEFT; + boolean delayed = true; + PlayerState replaceable = PlayerState.LOGSYNC; + this.setState(player, state, delayed, replaceable); } // -------------------------------------------- // // JOINING // -------------------------------------------- // + // PlayerJoinEvent: LOWEST @EventHandler(priority = EventPriority.LOWEST) public void joining(PlayerJoinEvent event) { - final Player player = event.getPlayer(); - if (MUtil.isntPlayer(player)) return; - final UUID id = player.getUniqueId(); - - this.idToState.put(id, PlayerState.JOINING); + Player player = event.getPlayer(); + PlayerState state = PlayerState.JOINING; + boolean delayed = false; + PlayerState replaceable = null; + this.setState(player, state, delayed, replaceable); } // -------------------------------------------- // // JOINED // -------------------------------------------- // + // PlayerJoinEvent: MONITOR DELAYED @EventHandler(priority = EventPriority.MONITOR) public void joined(PlayerJoinEvent event) { - final Player player = event.getPlayer(); - if (MUtil.isntPlayer(player)) return; - final UUID id = player.getUniqueId(); - - Bukkit.getScheduler().scheduleSyncDelayedTask(MassiveCore.get(), new Runnable() - { - @Override - public void run() - { - idToState.put(id, PlayerState.JOINED); - } - }); + Player player = event.getPlayer(); + PlayerState state = PlayerState.JOINED; + boolean delayed = true; + PlayerState replaceable = PlayerState.JOINING; + this.setState(player, state, delayed, replaceable); } // -------------------------------------------- // // LEAVING // -------------------------------------------- // + // EventMassiveCorePlayerLeave: LOWEST @EventHandler(priority = EventPriority.LOWEST) public void leaving(EventMassiveCorePlayerLeave event) { - final Player player = event.getPlayer(); - if (MUtil.isntPlayer(player)) return; - final UUID id = player.getUniqueId(); - - this.idToState.put(id, PlayerState.LEAVING); + Player player = event.getPlayer(); + PlayerState state = PlayerState.LEAVING; + boolean delayed = false; + PlayerState replaceable = null; + this.setState(player, state, delayed, replaceable); } // -------------------------------------------- // // LEFT // -------------------------------------------- // + // EventMassiveCorePlayerLeave: MONITOR DELAYED @EventHandler(priority = EventPriority.MONITOR) - public void left(PlayerQuitEvent event) + public void left(EventMassiveCorePlayerLeave event) { - final Player player = event.getPlayer(); - if (MUtil.isntPlayer(player)) return; - final UUID id = player.getUniqueId(); - - this.idToState.remove(id); + Player player = event.getPlayer(); + PlayerState state = PlayerState.LEFT; + boolean delayed = true; + PlayerState replaceable = PlayerState.LEAVING; + this.setState(player, state, delayed, replaceable); } } diff --git a/src/com/massivecraft/massivecore/util/MUtil.java b/src/com/massivecraft/massivecore/util/MUtil.java index abc8d13e..babcdfb6 100644 --- a/src/com/massivecraft/massivecore/util/MUtil.java +++ b/src/com/massivecraft/massivecore/util/MUtil.java @@ -58,6 +58,7 @@ import org.bukkit.potion.PotionEffectType; import org.bukkit.projectiles.ProjectileSource; import com.massivecraft.massivecore.MassiveCore; +import com.massivecraft.massivecore.collections.ExceptionSet; import com.massivecraft.massivecore.collections.MassiveList; import com.massivecraft.massivecore.collections.MassiveSet; import com.massivecraft.massivecore.collections.MassiveTreeSet; @@ -239,6 +240,55 @@ public class MUtil return asUuid(string) != null; } + // -------------------------------------------- // + // CONTAINS COMMAND + // -------------------------------------------- // + + public static boolean containsCommand(String needle, ExceptionSet haystack) + { + boolean ret = haystack.isStandard(); + if (containsCommand(needle, haystack.exceptions)) ret = !ret; + return ret; + } + + public static boolean containsCommand(String needle, Iterable haystack) + { + if (needle == null) return false; + needle = prepareCommand(needle); + + for (String straw : haystack) + { + if (straw == null) continue; + straw = prepareCommand(straw); + + // If it starts with then it is possibly a subject. + if ( ! needle.startsWith(straw)) continue; + + // Get the remainder. + String remainder = needle.substring(straw.length()); + + // If they were equal, definitely true. + if (remainder.isEmpty()) return true; + + // If the next is a space, the space is used as separator for sub commands or arguments. + // Otherwise it might just have been another command coincidentally starting with the first command. + // The old behaviour was if (needle.startsWith(straw)) return true; + // If "s" was block, then all commands starting with "s" was, now it isn't. + if (remainder.startsWith(" ")) return true; + } + + return false; + } + + private static String prepareCommand(String string) + { + if (string == null) return null; + string = Txt.removeLeadingCommandDust(string); + string = string.toLowerCase(); + string = string.trim(); + return string; + } + // -------------------------------------------- // // IP // -------------------------------------------- //