From 6af543250055bfe9b6fac18f402b9148911b045f Mon Sep 17 00:00:00 2001 From: Amaury Carrade Date: Mon, 11 Jan 2016 20:44:26 +0100 Subject: [PATCH] Added vanilla (and more generally non-SpectatorPlus) spectating mode support. (#120) * NEW: added vanilla spectator mode support, inside a structure allowing other spectators mode (e.g. from other plugins) to be easily added. The vanilla support is enabled if SpectatorPlus is not installed or compatible, there isn't an option in the config for that (useless, if you don't want SpectatorPlus, uninstall it). This said, such an option can be added if someone request it. --- .../amaury/UHCReloaded/UHCReloaded.java | 22 ++++- .../commands/uh/UHSpectatorsCommand.java | 5 - .../UHCReloaded/game/UHGameManager.java | 12 +-- .../UHCReloaded/listeners/GameListener.java | 49 +++++++--- .../spectators/SPlusSpectatorsManager.java | 62 ++++++++++++ .../spectators/SpectatorsManager.java | 98 +++++++++++++++++++ .../spectators/VanillaSpectatorsManager.java | 83 ++++++++++++++++ 7 files changed, 296 insertions(+), 35 deletions(-) create mode 100644 src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SPlusSpectatorsManager.java create mode 100644 src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SpectatorsManager.java create mode 100644 src/main/java/eu/carrade/amaury/UHCReloaded/spectators/VanillaSpectatorsManager.java diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/UHCReloaded.java b/src/main/java/eu/carrade/amaury/UHCReloaded/UHCReloaded.java index cb8ffff..21e5de3 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/UHCReloaded.java +++ b/src/main/java/eu/carrade/amaury/UHCReloaded/UHCReloaded.java @@ -29,7 +29,6 @@ * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-B license and that you accept its terms. */ - package eu.carrade.amaury.UHCReloaded; import eu.carrade.amaury.UHCReloaded.borders.BorderManager; @@ -52,6 +51,7 @@ import eu.carrade.amaury.UHCReloaded.recipes.RecipesManager; import eu.carrade.amaury.UHCReloaded.scoreboard.ScoreboardManager; import eu.carrade.amaury.UHCReloaded.spawns.SpawnsManager; +import eu.carrade.amaury.UHCReloaded.spectators.SpectatorsManager; import eu.carrade.amaury.UHCReloaded.task.UpdateTimerTask; import eu.carrade.amaury.UHCReloaded.teams.TeamChatManager; import eu.carrade.amaury.UHCReloaded.teams.TeamManager; @@ -69,6 +69,7 @@ public class UHCReloaded extends ZPlugin private TeamManager teamManager = null; private SpawnsManager spawnsManager = null; private UHGameManager gameManager = null; + private SpectatorsManager spectatorsManager = null; private ScoreboardManager scoreboardManager = null; private MOTDManager motdManager = null; private PlayerListHeaderFooterManager playerListHeaderFooterManager = null; @@ -109,10 +110,17 @@ public void onEnable() loadComponents(SidebarScoreboard.class); + wbintegration = new UHWorldBorderIntegration(); spintegration = new UHSpectatorPlusIntegration(this); dynmapintegration = new UHDynmapIntegration(this); + // Needed to avoid a NoClassDefFoundError. + // I don't like this way of doing this, but else, the plugin will not load without ProtocolLib. + protocollibintegrationwrapper = new UHProtocolLibIntegrationWrapper(this); + + + spectatorsManager = SpectatorsManager.getInstance(); teamManager = new TeamManager(this); gameManager = new UHGameManager(this); spawnsManager = new SpawnsManager(this); @@ -131,10 +139,6 @@ public void onEnable() motdManager = new MOTDManager(this); playerListHeaderFooterManager = new PlayerListHeaderFooterManager(); - // Needed to avoid a NoClassDefFoundError. - // I don't like this way of doing this, but else, the plugin will not load without ProtocolLib. - protocollibintegrationwrapper = new UHProtocolLibIntegrationWrapper(this); - UHCommandExecutor executor = new UHCommandExecutor(this); for (String commandName : getDescription().getCommands().keySet()) { @@ -214,6 +218,14 @@ public UHGameManager getGameManager() return gameManager; } + /** + * @return the spectators manager. + */ + public SpectatorsManager getSpectatorsManager() + { + return spectatorsManager; + } + /** * Returns the scoreboard manager. * diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java index 3ddf960..0629eaf 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java +++ b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java @@ -173,11 +173,6 @@ public List help(CommandSender sender) help.add(i.t("cmd.specHelpTitle")); - if (!p.getSpectatorPlusIntegration().isSPIntegrationEnabled()) - { - help.add(i.t("cmd.specHelpNoticeSpectatorPlusNotInstalled")); - } - help.add(i.t("cmd.specHelpAdd")); help.add(i.t("cmd.specHelpRemove")); help.add(i.t("cmd.specHelpList")); diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java index 383b9f2..0e62569 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java +++ b/src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java @@ -183,10 +183,7 @@ public void run() }, 20L); // Disable the spectator mode if the game is not started. - if (p.getSpectatorPlusIntegration().isSPIntegrationEnabled()) - { - p.getSpectatorPlusIntegration().getSPAPI().setSpectating(player, false); - } + p.getSpectatorsManager().setSpectating(player, false); // Resets the achievements if (p.getConfig().getBoolean("achievements.resetAchievementsAtStartup", true)) @@ -333,12 +330,9 @@ public void start(final CommandSender sender, final Boolean slow, Boolean ignore /** Initialization of the spectator mode **/ - if (p.getSpectatorPlusIntegration().isSPIntegrationEnabled()) + for (Player player : Bukkit.getOnlinePlayers()) { - for (Player player : Bukkit.getOnlinePlayers()) - { - p.getSpectatorPlusIntegration().getSPAPI().setSpectating(player, spectators.contains(player.getUniqueId())); - } + p.getSpectatorsManager().setSpectating(player, spectators.contains(player.getUniqueId())); } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java b/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java index db1b382..cd5dbc5 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java +++ b/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java @@ -47,6 +47,7 @@ import eu.carrade.amaury.UHCReloaded.misc.RuntimeCommandsExecutor; import eu.carrade.amaury.UHCReloaded.teams.UHTeam; import eu.carrade.amaury.UHCReloaded.utils.UHSound; +import fr.zcraft.zlib.tools.runners.RunTask; import fr.zcraft.zlib.tools.text.Titles; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -73,20 +74,25 @@ import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent.Result; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerStatisticIncrementEvent; import org.bukkit.event.server.ServerListPingEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.UUID; public class GameListener implements Listener { + private final UHCReloaded p; + private final I18n i; + + private final Set enableSpectatorModeOnRespawn = new HashSet<>(); - private UHCReloaded p = null; - private I18n i = null; public GameListener(UHCReloaded p) { @@ -140,6 +146,9 @@ public void onPlayerDeath(final PlayerDeathEvent ev) // Removes the player from the alive players. this.p.getGameManager().addDead(ev.getEntity()); + // Remember to enable spectator mode on respawn + enableSpectatorModeOnRespawn.add(ev.getEntity().getUniqueId()); + // Kicks the player if needed. if (this.p.getConfig().getBoolean("death.kick.do", true)) { @@ -298,6 +307,25 @@ public void run() } + /** + * Used to enable the spectator mode when the player respawns. + */ + @EventHandler + public void onPlayerRespawn(final PlayerRespawnEvent ev) + { + if (enableSpectatorModeOnRespawn.remove(ev.getPlayer().getUniqueId())) + { + RunTask.nextTick(new Runnable() { + @Override + public void run() + { + p.getSpectatorsManager().setSpectating(ev.getPlayer(), true); + } + }); + } + } + + /** * Used to disable all damages if the game is not started. * @@ -482,13 +510,6 @@ public void run() ev.getPlayer().sendMessage(i.t("load.WBNotInstalled3")); } - // The same for SpectatorPlus - if (!p.getSpectatorPlusIntegration().isSPIntegrationEnabled()) - { - ev.getPlayer().sendMessage(i.t("load.SPNotInstalled1")); - ev.getPlayer().sendMessage(i.t("load.SPNotInstalled2")); - } - // The same for ProtocolLib if (!p.getProtocolLibIntegrationWrapper().isProtocolLibIntegrationEnabled()) { @@ -526,10 +547,9 @@ public void run() // If the player is a new one, the game is started, and the option is set to true... if (p.getGameManager().isGameRunning() && p.getConfig().getBoolean("spectatorModeWhenNewPlayerJoinAfterStart") - && !p.getGameManager().getAlivePlayers().contains(ev.getPlayer()) - && p.getSpectatorPlusIntegration().isSPIntegrationEnabled()) + && !p.getGameManager().getAlivePlayers().contains(ev.getPlayer())) { - p.getSpectatorPlusIntegration().getSPAPI().setSpectating(ev.getPlayer(), true); + p.getSpectatorsManager().setSpectating(ev.getPlayer(), true); } } @@ -772,10 +792,7 @@ public void run() public void onPlayerResurrected(UHPlayerResurrectedEvent ev) { // Spectator mode disabled - if (p.getSpectatorPlusIntegration().isSPIntegrationEnabled()) - { - p.getSpectatorPlusIntegration().getSPAPI().setSpectating(ev.getPlayer(), false); - } + p.getSpectatorsManager().setSpectating(ev.getPlayer(), false); // Death point removed on the dynmap p.getDynmapIntegration().hideDeathLocation(ev.getPlayer()); diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SPlusSpectatorsManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SPlusSpectatorsManager.java new file mode 100644 index 0000000..7ab6344 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SPlusSpectatorsManager.java @@ -0,0 +1,62 @@ +/* + * Copyright or © or Copr. Amaury Carrade (2014 - 2016) + * + * http://amaury.carrade.eu + * + * This software is governed by the CeCILL-B license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-B + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-B license and that you accept its terms. + */ +package eu.carrade.amaury.UHCReloaded.spectators; + +import eu.carrade.amaury.UHCReloaded.UHCReloaded; +import org.bukkit.entity.Player; + + +/** + * Spectators managed through the SpectatorsPlus Bukkit plugin by PGMann and AmauryPi. + */ +public class SPlusSpectatorsManager extends SpectatorsManager +{ + UHCReloaded p; + + public SPlusSpectatorsManager() + { + p = UHCReloaded.get(); + } + + @Override + public void setSpectating(final Player player, final boolean spectating) + { + if (player != null && p.getSpectatorPlusIntegration().isSPIntegrationEnabled()) + p.getSpectatorPlusIntegration().getSPAPI().setSpectating(player, spectating); + } + + @Override + public boolean isSpectating(Player player) + { + return player != null && p.getSpectatorPlusIntegration().isSPIntegrationEnabled() && p.getSpectatorPlusIntegration().getSPAPI().isSpectator(player); + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SpectatorsManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SpectatorsManager.java new file mode 100644 index 0000000..8acba07 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SpectatorsManager.java @@ -0,0 +1,98 @@ +/* + * Copyright or © or Copr. Amaury Carrade (2014 - 2016) + * + * http://amaury.carrade.eu + * + * This software is governed by the CeCILL-B license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-B + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-B license and that you accept its terms. + */ +package eu.carrade.amaury.UHCReloaded.spectators; + +import eu.carrade.amaury.UHCReloaded.UHCReloaded; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.UUID; + + +/** + * Represents a spectator manager, able to put players in or remove players from spectator mode. + */ +public abstract class SpectatorsManager +{ + /** + * Changes the spectating mode of a player. + * + * @param player The player. + * @param spectating {@code true} to enable the spectator mode; {@code false} to disable it. + */ + public abstract void setSpectating(final Player player, final boolean spectating); + + /** + * Checks if the given player is currently spectating. + * + * @param player The player. + * + * @return {@code true} if spectating. + */ + public abstract boolean isSpectating(final Player player); + + /** + * Changes the spectating mode of a player. + * + * @param playerID The player's UUID. + * @param spectating {@code true} to enable the spectator mode; {@code false} to disable it. + */ + public void setSpectating(final UUID playerID, final boolean spectating) + { + setSpectating(Bukkit.getPlayer(playerID), spectating); + } + + /** + * Checks if the given player is currently spectating. + * + * @param playerID The player's UUID. + * + * @return {@code true} if spectating. + */ + public boolean isSpectating(final UUID playerID) + { + return isSpectating(Bukkit.getPlayer(playerID)); + } + + + /** + * @return an instance of a {@link SpectatorsManager}: {@link SPlusSpectatorsManager} if the + * SpectatorPlus plugin is available; {@link VanillaSpectatorsManager} else. + */ + public static SpectatorsManager getInstance() + { + if (UHCReloaded.get().getSpectatorPlusIntegration().isSPIntegrationEnabled()) + return new SPlusSpectatorsManager(); + else + return new VanillaSpectatorsManager(); + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/VanillaSpectatorsManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/VanillaSpectatorsManager.java new file mode 100644 index 0000000..81d175c --- /dev/null +++ b/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/VanillaSpectatorsManager.java @@ -0,0 +1,83 @@ +/* + * Copyright or © or Copr. Amaury Carrade (2014 - 2016) + * + * http://amaury.carrade.eu + * + * This software is governed by the CeCILL-B license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-B + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-B license and that you accept its terms. + */ +package eu.carrade.amaury.UHCReloaded.spectators; + + +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + + +/** + * Vanilla spectator mode + */ +public class VanillaSpectatorsManager extends SpectatorsManager +{ + /** + * Stores the previous gamemodes of the players. + */ + private Map oldGameModes = new HashMap<>(); + + + @Override + public void setSpectating(final Player player, final boolean spectating) + { + if (player == null) + return; + + if (spectating) + { + if (player.getGameMode() != GameMode.SPECTATOR) + { + oldGameModes.put(player.getUniqueId(), player.getGameMode()); + player.setGameMode(GameMode.SPECTATOR); + } + } + else + { + GameMode previousMode = oldGameModes.get(player.getUniqueId()); + player.setGameMode(previousMode != null ? previousMode : Bukkit.getDefaultGameMode()); + + oldGameModes.remove(player.getUniqueId()); + } + } + + @Override + public boolean isSpectating(Player player) + { + return player != null && player.getGameMode() == GameMode.SPECTATOR; + } +}