diff --git a/pom.xml b/pom.xml index 69dc8c6..1173c7a 100644 --- a/pom.xml +++ b/pom.xml @@ -32,12 +32,16 @@ 4.0.0 eu.carrade.amaury - UHCReloaded - 1.5 - UHCReloaded - Ultra Hardcore plugin + quartz-survival-games + 2.0-SNAPSHOT + Quartz Survival Games + Survival games plugin, able to handle most Minecraft survival games (like UHC) through combined modules https://github.com/zDevelopers/UHPlugin/ + + eu.carrade.amaury.quartzsurvivalgames.libs + + GitHub https://github.com/zDevelopers/UHPlugin/issues @@ -93,18 +97,28 @@ org.apache.maven.plugins maven-shade-plugin - 2.4 + 3.2.4 true - fr.zcraft:zlib + fr.zcraft:quartzlib + fr.zcraft:quartzteams + me.cassayre.florian:hawk - fr.zcraft.zlib - eu.carrade.amaury.UHCReloaded.zlib + fr.zcraft.quartzlib + ${shaded.package}.quartzlib + + + fr.zcraft.quartzteams + ${shaded.package}.quartzteams + + + me.cassayre.florian.hawk + ${shaded.package}.hawk @@ -136,33 +150,46 @@ pgmann-repo PGMann repository (SpectatorPlus) - https://mvn.pgmann.cf/ + https://repo.repsy.io/mvn/pgmann/public/ carrade-repo http://raw.carrade.eu/maven2/ - zDevelopers - http://maven.carrade.eu/artifactory/snapshots + zdevelpers-quartzlib + https://maven.zcraft.fr/QuartzLib + + + zdevelpers-quartzteams + https://maven.zcraft.fr/QuartzTeams + + + zdevelpers-hawk + https://maven.zcraft.fr/Hawk org.bukkit bukkit - 1.8.3-R0.1-SNAPSHOT + 1.15.2-R0.1-SNAPSHOT jar fr.zcraft - zlib - 0.99-SNAPSHOT + quartzlib + 0.0.4 + + + fr.zcraft + quartzteams + 0.0.2 - com.wimbli.WorldBorder - WorldBorder - 1.8.0 + me.cassayre.florian + hawk + 2.0.0 com.pgcraft diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/UHCReloaded.java b/src/main/java/eu/carrade/amaury/UHCReloaded/UHCReloaded.java deleted file mode 100644 index 34c2643..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/UHCReloaded.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * 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; - -import eu.carrade.amaury.UHCReloaded.borders.BorderManager; -import eu.carrade.amaury.UHCReloaded.commands.UHCommandExecutor; -import eu.carrade.amaury.UHCReloaded.game.UHGameManager; -import eu.carrade.amaury.UHCReloaded.integration.UHDynmapIntegration; -import eu.carrade.amaury.UHCReloaded.integration.UHProtocolLibIntegrationWrapper; -import eu.carrade.amaury.UHCReloaded.integration.UHSpectatorPlusIntegration; -import eu.carrade.amaury.UHCReloaded.integration.UHWorldBorderIntegration; -import eu.carrade.amaury.UHCReloaded.listeners.BeforeGameListener; -import eu.carrade.amaury.UHCReloaded.listeners.CraftingListener; -import eu.carrade.amaury.UHCReloaded.listeners.GameListener; -import eu.carrade.amaury.UHCReloaded.listeners.GameplayListener; -import eu.carrade.amaury.UHCReloaded.listeners.SpawnsListener; -import eu.carrade.amaury.UHCReloaded.misc.Freezer; -import eu.carrade.amaury.UHCReloaded.misc.MOTDManager; -import eu.carrade.amaury.UHCReloaded.misc.OfflinePlayersLoader; -import eu.carrade.amaury.UHCReloaded.misc.PlayerListHeaderFooterManager; -import eu.carrade.amaury.UHCReloaded.misc.RulesManager; -import eu.carrade.amaury.UHCReloaded.misc.RuntimeCommandsExecutor; -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; -import eu.carrade.amaury.UHCReloaded.timers.TimerManager; -import fr.zcraft.zlib.components.gui.Gui; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.components.i18n.I18n; -import fr.zcraft.zlib.components.scoreboard.SidebarScoreboard; -import fr.zcraft.zlib.core.ZLib; -import fr.zcraft.zlib.core.ZPlugin; -import org.bukkit.entity.Player; - -import java.util.Locale; - - -public class UHCReloaded extends ZPlugin -{ - private static UHCReloaded instance; - - 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 RulesManager rulesManager = null; - private PlayerListHeaderFooterManager playerListHeaderFooterManager = null; - private BorderManager borderManager = null; - private RecipesManager recipesManager = null; - private TeamChatManager teamChatManager = null; - private TimerManager timerManager = null; - - private RuntimeCommandsExecutor runtimeCommandsExecutor = null; - - private Freezer freezer = null; - - private UHWorldBorderIntegration wbintegration = null; - private UHSpectatorPlusIntegration spintegration = null; - private UHDynmapIntegration dynmapintegration = null; - private UHProtocolLibIntegrationWrapper protocollibintegrationwrapper = null; - - - @Override - public void onEnable() - { - instance = this; - - this.saveDefaultConfig(); - - loadComponents(SidebarScoreboard.class, Gui.class, I18n.class, UHConfig.class, OfflinePlayersLoader.class); - - final String langInConfig = UHConfig.LANG.get(); - if (langInConfig == null || langInConfig.isEmpty()) - { - //i18n = new eu.carrade.amaury.UHCReloaded.i18n.I18n(this); - I18n.useDefaultPrimaryLocale(); - } - else - { - //i18n = new eu.carrade.amaury.UHCReloaded.i18n.I18n(this, langInConfig); - I18n.setPrimaryLocale(Locale.forLanguageTag(langInConfig)); - } - - I18n.setFallbackLocale(Locale.US); - - - wbintegration = new UHWorldBorderIntegration(); - spintegration = new UHSpectatorPlusIntegration(); - dynmapintegration = new UHDynmapIntegration(); - - // 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(); - gameManager = new UHGameManager(this); - spawnsManager = new SpawnsManager(this); - borderManager = new BorderManager(this); - recipesManager = new RecipesManager(this); - teamChatManager = new TeamChatManager(this); - timerManager = new TimerManager(); - - runtimeCommandsExecutor = new RuntimeCommandsExecutor(); - - freezer = new Freezer(this); - - scoreboardManager = new ScoreboardManager(this); - motdManager = new MOTDManager(this); - rulesManager = new RulesManager(); - playerListHeaderFooterManager = new PlayerListHeaderFooterManager(); - - UHCommandExecutor executor = new UHCommandExecutor(this); - for (String commandName : getDescription().getCommands().keySet()) - { - getCommand(commandName).setExecutor(executor); - getCommand(commandName).setTabCompleter(executor); - } - - ZLib.registerEvents(new GameListener()); - ZLib.registerEvents(new GameplayListener()); - ZLib.registerEvents(new CraftingListener(this)); - ZLib.registerEvents(new SpawnsListener()); - ZLib.registerEvents(new BeforeGameListener()); - - // The freezer listener is registered by the freezer when it is needed. - - recipesManager.registerRecipes(); - gameManager.initEnvironment(); - - motdManager.updateMOTDBeforeStart(); - - // In case of reload - for (Player player : getServer().getOnlinePlayers()) - { - gameManager.initPlayer(player); - } - - // Imports spawnpoints from the config. - this.spawnsManager.importSpawnPointsFromConfig(); - - // Imports teams from the config. - this.teamManager.importTeamsFromConfig(); - - // Starts the task that updates the timers. - // Started here, so a timer can be displayed before the start of the game - // (example: countdown before the start). - new UpdateTimerTask().runTaskTimer(this, 20L, 20L); - - // Schedule commands - runtimeCommandsExecutor.registerCommandsInScheduler(RuntimeCommandsExecutor.AFTER_SERVER_START); - - getLogger().info(I.t("Ultra Hardcore plugin loaded.")); - } - - /** - * Returns the team manager. - */ - public TeamManager getTeamManager() - { - return teamManager; - } - - /** - * Returns the game manager. - */ - public UHGameManager getGameManager() - { - return gameManager; - } - - /** - * @return the spectators manager. - */ - public SpectatorsManager getSpectatorsManager() - { - return spectatorsManager; - } - - /** - * Returns the scoreboard manager. - */ - public ScoreboardManager getScoreboardManager() - { - return scoreboardManager; - } - - /** - * Returns the MOTD manager. - */ - public MOTDManager getMOTDManager() - { - return motdManager; - } - - /** - * @return the rules manager. - */ - public RulesManager getRulesManager() - { - return rulesManager; - } - - /** - * Returns the players list's headers & footers manager. - */ - public PlayerListHeaderFooterManager getPlayerListHeaderFooterManager() - { - return playerListHeaderFooterManager; - } - - /** - * Returns the spawns points manager. - */ - public SpawnsManager getSpawnsManager() - { - return spawnsManager; - } - - /** - * Returns the border manager. - */ - public BorderManager getBorderManager() - { - return borderManager; - } - - /** - * Returns the recipe manager. - */ - public RecipesManager getRecipesManager() - { - return recipesManager; - } - - /** - * Returns the team-chat manager. - */ - public TeamChatManager getTeamChatManager() - { - return teamChatManager; - } - - /** - * Returns the timer manager. - */ - public TimerManager getTimerManager() - { - return timerManager; - } - - /** - * Returns the manager used to manage the commands executed after the start/the end of the - * game (or any other moment using the generic API). - */ - public RuntimeCommandsExecutor getRuntimeCommandsExecutor() - { - return runtimeCommandsExecutor; - } - - /** - * Returns the freezer. - */ - public Freezer getFreezer() - { - return freezer; - } - - /** - * Returns the representation of the WorldBorder integration in the plugin. - */ - public UHWorldBorderIntegration getWorldBorderIntegration() - { - return wbintegration; - } - - /** - * Returns the representation of the SpectatorPlus integration in the plugin. - */ - public UHSpectatorPlusIntegration getSpectatorPlusIntegration() - { - return spintegration; - } - - /** - * Returns the representation of the dynmap integration in the plugin. - */ - public UHDynmapIntegration getDynmapIntegration() - { - return dynmapintegration; - } - - /** - * Returns a wrapper of the representation of the ProtocolLib integration in the plugin. - */ - public UHProtocolLibIntegrationWrapper getProtocolLibIntegrationWrapper() - { - return protocollibintegrationwrapper; - } - - /** - * Returns the plugin's instance. - */ - public static UHCReloaded get() - { - return instance; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/UHConfig.java b/src/main/java/eu/carrade/amaury/UHCReloaded/UHConfig.java deleted file mode 100644 index d83b0ab..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/UHConfig.java +++ /dev/null @@ -1,594 +0,0 @@ -package eu.carrade.amaury.UHCReloaded; - -import eu.carrade.amaury.UHCReloaded.borders.MapShape; -import eu.carrade.amaury.UHCReloaded.game.Cage; -import eu.carrade.amaury.UHCReloaded.teams.TeamManager; -import eu.carrade.amaury.UHCReloaded.utils.UHSound; -import fr.zcraft.zlib.components.configuration.Configuration; -import fr.zcraft.zlib.components.configuration.ConfigurationItem; -import fr.zcraft.zlib.components.configuration.ConfigurationList; -import fr.zcraft.zlib.components.configuration.ConfigurationMap; -import fr.zcraft.zlib.components.configuration.ConfigurationSection; -import fr.zcraft.zlib.components.configuration.ConfigurationValueHandlers; -import org.bukkit.Material; -import org.bukkit.Sound; -import org.bukkit.inventory.meta.BannerMeta; -import org.bukkit.util.Vector; - -import static fr.zcraft.zlib.components.configuration.ConfigurationItem.*; - - -public class UHConfig extends Configuration -{ - static public final ConfigurationItem LANG = item("lang", ""); - - static public final EpisodesSection EPISODES = section("episodes", EpisodesSection.class); - - static public class EpisodesSection extends ConfigurationSection - { - public final ConfigurationItem ENABLED = item("enabled", true); - public final ConfigurationItem LENGTH = item("length", "20:00"); - public final ConfigurationItem TITLE = item("title", true); - } - - static public final MapSection MAP = section("map", MapSection.class); - - static public class MapSection extends ConfigurationSection - { - public final ConfigurationItem SIZE = item("size", 2000); - public final ConfigurationItem SHAPE = item("shape", MapShape.SQUARED); - - public final WallSection WALL = section("wall", WallSection.class); - - static public class WallSection extends ConfigurationSection - { - public final ConfigurationItem HEIGHT = item("height", 128); - - public final BlockSection BLOCK = section("block", BlockSection.class); - - static public class BlockSection extends ConfigurationSection - { - public final ConfigurationItem REPLACE_AIR = item("replaceAir", Material.GLASS); - public final ConfigurationItem REPLACE_SOLID = item("replaceSolid", Material.BEDROCK); - } - } - - public final BorderSection BORDER = section("border", BorderSection.class); - - static public class BorderSection extends ConfigurationSection - { - public final ConfigurationItem MOTOR = item("motor", "vanilla"); - public final ConfigurationItem DAMAGES_BUFFER = item("damagesBuffer", 5d); - public final ConfigurationItem DAMAGES_AMOUNT = item("damagesAmount", 0.2); - public final ConfigurationItem WARNING_DISTANCE = item("warningDistance", 5); - - public final ShrinkingSection SHRINKING = section("shrinking", ShrinkingSection.class); - - static public class ShrinkingSection extends ConfigurationSection - { - public final ConfigurationItem ENABLED = item("enabled", false); - public final ConfigurationItem STARTS_AFTER = item("startsAfter", "30:00"); - public final ConfigurationItem SHRINKS_DURING = item("shrinksDuring", "2:00:00"); - public final ConfigurationItem DIAMETER_AFTER_SHRINK = item("diameterAfterShrink", 200); - } - - public final ConfigurationItem WARNING_INTERVAL = item("warningInterval", 90); - } - - public final SpawnPointsSection SPAWN_POINTS = section("spawnPoints", SpawnPointsSection.class); - - static public class SpawnPointsSection extends ConfigurationSection - { - public final ConfigurationItem DONT_GENERATE_ABOVE_WATER = item("dontGenerateAboveWater", true); - } - } - - static public final DaylightCycleSection DAYLIGHT_CYCLE = section("daylightCycle", DaylightCycleSection.class); - - static public class DaylightCycleSection extends ConfigurationSection - { - public final ConfigurationItem DO = item("do", false); - public final ConfigurationItem TIME = item("time", 6000l); - } - - static public final ScoreboardSection SCOREBOARD = section("scoreboard", ScoreboardSection.class); - - static public class ScoreboardSection extends ConfigurationSection - { - public final ConfigurationItem TITLE = item("title", "Kill the Patrick"); - public final ConfigurationItem ENABLED = item("enabled", true); - public final ConfigurationItem EPISODE = item("episode", true); - public final ConfigurationItem PLAYERS = item("players", true); - public final ConfigurationItem TEAMS = item("teams", true); - - public final OwnTeamSection OWN_TEAM = section("ownTeam", OwnTeamSection.class); - - static public class OwnTeamSection extends ConfigurationSection - { - public final ConfigurationItem ENABLED = item("enabled", true); - - public final TitleSection TITLE = section("title", TitleSection.class); - - static public class TitleSection extends ConfigurationSection - { - public final ConfigurationItem COLOR = item("color", ""); - public final ConfigurationItem USE_TEAM_NAME = item("useTeamName", false); - } - - public final ContentSection CONTENT = section("content", ContentSection.class); - - static public class ContentSection extends ConfigurationSection - { - public final ConfigurationItem DISPLAY_HEARTS = item("displayHearts", true); - public final ConfigurationItem COLOR_NAME = item("colorName", false); - public final ConfigurationItem STRIKE_DEAD_PLAYERS = item("strikeDeadPlayers", false); - - public final LoginStateSection LOGIN_STATE = section("loginState", LoginStateSection.class); - - static public class LoginStateSection extends ConfigurationSection - { - public final ConfigurationItem ITALIC = item("italic", true); - public final ConfigurationItem SUFFIX = item("suffix", "➥"); - } - - public final DisplayMetPlayersOnlySection DISPLAY_MET_PLAYERS_ONLY = section("displayMetPlayersOnly", DisplayMetPlayersOnlySection.class); - - static public class DisplayMetPlayersOnlySection extends ConfigurationSection - { - public final ConfigurationItem ENABLED = item("enabled", false); - public final ConfigurationItem DISPLAYED_WHEN_CLOSER_THAN = item("displayedWhenCloserThan", 10d); - } - } - } - - public final BorderSection BORDER = section("border", BorderSection.class); - - static public class BorderSection extends ConfigurationSection - { - public final ConfigurationItem DISPLAYED = item("displayed", true); - public final ConfigurationItem DISPLAY_DIAMETER = item("displayDiameter", false); - } - - public final ConfigurationItem KILLS = item("kills", true); - public final ConfigurationItem TIMER = item("timer", true); - public final ConfigurationItem FREEZE_STATUS = item("freezeStatus", true); - public final ConfigurationItem HEALTH = item("health", true); - } - - static public final PlayersListSection PLAYERS_LIST = section("playersList", PlayersListSection.class); - - static public class PlayersListSection extends ConfigurationSection - { - public final WaitingTimeSection WAITING_TIME = section("waitingTime", WaitingTimeSection.class); - - static public class WaitingTimeSection extends ConfigurationSection - { - public final ConfigurationItem HEADER = item("header", "{title}"); - public final ConfigurationItem FOOTER = item("footer", ""); - } - - public final InGameTimeSection IN_GAME_TIME = section("inGameTime", InGameTimeSection.class); - - static public class InGameTimeSection extends ConfigurationSection - { - public final ConfigurationItem HEADER = item("header", "{title}"); - public final ConfigurationItem FOOTER = item("footer", "§a{episodeText} §7- §a{playersText} §7- §a{teamsText}"); - } - } - - static public final MotdSection MOTD = section("motd", MotdSection.class); - - static public class MotdSection extends ConfigurationSection - { - public final ConfigurationItem ENABLED = item("enabled", false); - public final ConfigurationItem DISPLAY_MATCH_NAME = item("displayMatchName", true); - public final ConfigurationItem MATCH_NAME_PREFIX = item("matchNamePrefix", ""); - } - - static public final ConfigurationItem TELEPORT_TO_SPAWN_IF_NOT_STARTED = item("teleportToSpawnIfNotStarted", true); - - static public final AchievementsSection ACHIEVEMENTS = section("achievements", AchievementsSection.class); - - static public class AchievementsSection extends ConfigurationSection - { - public final ConfigurationItem RESET_ACHIEVEMENTS_AT_STARTUP = item("resetAchievementsAtStartup", true); - public final ConfigurationItem DISABLE_ACHIEVEMENTS_BEFORE_START = item("disableAchievementsBeforeStart", true); - } - - static public final StatisticsSection STATISTICS = section("statistics", StatisticsSection.class); - - static public class StatisticsSection extends ConfigurationSection - { - public final ConfigurationItem DISABLE_STATISTICS_BEFORE_START = item("disableStatisticsBeforeStart", true); - } - - static public final BeforeStartSection BEFORE_START = section("before-start", BeforeStartSection.class); - - static public class BeforeStartSection extends ConfigurationSection - { - public final InventorySection INVENTORY = section("inventory", InventorySection.class); - - static public class InventorySection extends ConfigurationSection - { - public final ConfigurationItem CLEAR = item("clear", true); - public final ConfigurationItem PREVENT_USAGE = item("preventUsage", true); - public final ConfigurationItem ALLOW_FOR_BUILDERS = item("allowForBuilders", true); - } - - public final TeamSelectorSection TEAM_SELECTOR = section("teamSelector", TeamSelectorSection.class); - - static public class TeamSelectorSection extends ConfigurationSection - { - public final ConfigurationItem ENABLED = item("enabled", true); - public final ConfigurationItem ITEM = item("item", Material.NETHER_STAR); - } - - public final ConfigurationItem TEAM_IN_ACTION_BAR = item("teamInActionBar", true); - - public final ConfigurationItem ENABLE_PVP = item("enablePVP", false); - } - - static public final StartSection START = section("start", StartSection.class); - - static public class StartSection extends ConfigurationSection - { - public final SlowSection SLOW = section("slow", SlowSection.class); - - static public class SlowSection extends ConfigurationSection - { - public final ConfigurationItem DELAY_BETWEEN_TP = item("delayBetweenTP", 3l); - public final ConfigurationItem BROADCAST_PROGRESS = item("broadcastProgress", true); - - public final CagesSection CAGES = section("cages", CagesSection.class); - - static public class CagesSection extends ConfigurationSection - { - public final ConfigurationItem ENABLED = item("enabled", true); - public final ConfigurationItem TYPE = item("type", Cage.CageType.TEAM_COLOR_TRANSPARENT); - public final ConfigurationItem CUSTOM_BLOCK = item("customBlock", Material.BARRIER); - public final ConfigurationItem BUILD_CEILING = item("buildCeiling", false); - public final ConfigurationItem VISIBLE_WALLS = item("visibleWalls", false); - public final ConfigurationItem RADIUS = item("radius", 1); - public final ConfigurationItem HEIGHT = item("height", 3); - } - } - - public final SoundSection SOUND = section("sound", SoundSection.class); - - public final ConfigurationItem DISPLAY_TITLE = item("displayTitle", true); - public final ConfigurationItem GRACE_PERIOD = item("gracePeriod", "00:30"); - public final ConfigurationItem BROADCAST_GRACE_END = item("broadcastGraceEnd", true); - public final ConfigurationItem PEACE_PERIOD = item("peacePeriod", "00"); - public final ConfigurationItem SURFACE_MOBS_FREE_PERIOD = item("surfaceMobsFreePeriod", "15:00"); - } - - static public final DeathSection DEATH = section("death", DeathSection.class); - - static public class DeathSection extends ConfigurationSection - { - public final MessagesSection MESSAGES = section("messages", MessagesSection.class); - - static public class MessagesSection extends ConfigurationSection - { - public final ConfigurationItem NOTIFY_IF_TEAM_HAS_FALLEN = item("notifyIfTeamHasFallen", true); - public final ConfigurationItem DEATH_MESSAGES_FORMAT = item("deathMessagesFormat", "§6"); - public final ConfigurationItem TEAM_DEATH_MESSAGES_FORMAT = item("teamDeathMessagesFormat", "§6"); - } - - public final KickSection KICK = section("kick", KickSection.class); - - static public class KickSection extends ConfigurationSection - { - public final ConfigurationItem DO = item("do", false); - public final ConfigurationItem TIME = item("time", 30); - public final ConfigurationItem ALLOW_RECONNECT = item("allow-reconnect", true); - } - - public final HeadSection HEAD = section("head", HeadSection.class); - - static public class HeadSection extends ConfigurationSection - { - public final ConfigurationItem DROP = item("drop", true); - public final ConfigurationItem PVP_ONLY = item("pvpOnly", false); - } - - public final GiveXpToKillerSection GIVE_XP_TO_KILLER = section("give-xp-to-killer", GiveXpToKillerSection.class); - - static public class GiveXpToKillerSection extends ConfigurationSection - { - public final ConfigurationItem LEVELS = item("levels", 2); - public final ConfigurationItem ONLY_OTHER_TEAM = item("onlyOtherTeam", true); - } - - public final AnnouncementsSection ANNOUNCEMENTS = section("announcements", AnnouncementsSection.class); - - static public class AnnouncementsSection extends ConfigurationSection - { - public final ConfigurationItem LIGHTNING_STRIKE = item("lightning-strike", false); - public final SoundSection SOUND = section("sound", SoundSection.class); - } - } - - static public final ConfigurationItem COLORIZE_CHAT = item("colorizeChat", true); - - static public final GameplayChangesSection GAMEPLAY_CHANGES = section("gameplay-changes", GameplayChangesSection.class); - - static public class GameplayChangesSection extends ConfigurationSection - { - public final ConfigurationItem NATURAL_REGENERATION = item("naturalRegeneration", false); - public final ConfigurationItem WEATHER = item("weather", true); - public final ConfigurationItem REPLACE_GHAST_TEARS_WITH_GOLD = item("replaceGhastTearsWithGold", true); - public final ConfigurationItem CRAFT_GOLDEN_MELON_WITH_GOLD_BLOCK = item("craftGoldenMelonWithGoldBlock", true); - - public final CraftGoldenAppleFromHeadSection CRAFT_GOLDEN_APPLE_FROM_HEAD = section("craftGoldenAppleFromHead", CraftGoldenAppleFromHeadSection.class); - - static public class CraftGoldenAppleFromHeadSection extends ConfigurationSection - { - public final FromHumanSection FROM_HUMAN = section("fromHuman", FromHumanSection.class); - - static public class FromHumanSection extends ConfigurationSection - { - public final ConfigurationItem DO = item("do", true); - public final ConfigurationItem NUMBER_CRAFTED = item("numberCrafted", 2); - public final ConfigurationItem ADD_LORE = item("addLore", true); - public final ConfigurationItem CRAFT_NOTCH_APPLE = item("craftNotchApple", false); - } - - - public final FromWitherSection FROM_WITHER = section("fromWither", FromWitherSection.class); - - static public class FromWitherSection extends ConfigurationSection - { - public final ConfigurationItem DO = item("do", true); - public final ConfigurationItem NUMBER_CRAFTED = item("numberCrafted", 1); - public final ConfigurationItem ADD_LORE = item("addLore", true); - public final ConfigurationItem CRAFT_NOTCH_APPLE = item("craftNotchApple", false); - } - } - - public final GoldenAppleSection GOLDEN_APPLE = section("goldenApple", GoldenAppleSection.class); - - static public class GoldenAppleSection extends ConfigurationSection - { - public final RegenerationSection REGENERATION = section("regeneration", RegenerationSection.class); - - static public class RegenerationSection extends ConfigurationSection - { - public final ConfigurationItem NORMAL = item("normal", 4); - public final ConfigurationItem NOTCH = item("notch", 180); - public final ConfigurationItem FROM_NORMAL_HEAD = item("fromNormalHead", 4); - public final ConfigurationItem FROM_NOTCH_HEAD = item("fromNotchHead", 180); - } - - public final ConfigurationItem DISABLE_NOTCH_APPLES = item("disableNotchApples", false); - } - - public final ConfigurationItem DISABLE_ENDERPEARLS_DAMAGES = item("disableEnderpearlsDamages", true); - public final ConfigurationItem DISABLE_LEVEL_II_POTIONS = item("disableLevelIIPotions", false); - - public final WitchSection WITCH = section("witch", WitchSection.class); - - static public class WitchSection extends ConfigurationSection - { - public final ConfigurationItem DISABLE_NATURAL_SPAWN = item("disableNaturalSpawn", false); - public final ConfigurationItem DISABLE_LIGHTNING_SPAWN = item("disableLightningSpawn", false); - } - - public final RabbitSection RABBIT = section("rabbit", RabbitSection.class); - - static public class RabbitSection extends ConfigurationSection - { - public final ConfigurationItem KILLER_RABBIT_SPAWN = item("killerRabbitSpawn", true); - public final ConfigurationItem KILLER_RABBIT_SPAWN_PROBABILITY = item("killerRabbitSpawnProbability", 0.05); - public final ConfigurationItem KILLER_RABBIT_NAME = item("killerRabbitName", "The Killer Rabbit of Caerbannog"); - } - - public final CompassSection COMPASS = section("compass", CompassSection.class); - - static public class CompassSection extends ConfigurationSection - { - public final ConfigurationItem ENABLED = item("enabled", true); - public final ConfigurationItem RECIPE = item("recipe", "medium"); - } - } - - static public final TeamsOptionsSection TEAMS_OPTIONS = section("teams-options", TeamsOptionsSection.class); - - static public class TeamsOptionsSection extends ConfigurationSection - { - public final ConfigurationItem CAN_SEE_FRIENDLY_INVISIBLES = item("canSeeFriendlyInvisibles", true); - public final ConfigurationItem ALLOW_FRIENDLY_FIRE = item("allowFriendlyFire", true); - public final ConfigurationItem MAX_PLAYERS_PER_TEAM = item("maxPlayersPerTeam", 0); - public final ConfigurationItem RANDOM_COLORS = item("randomColors", true); - - public final BannerSection BANNER = section("banner", BannerSection.class); - - static public class BannerSection extends ConfigurationSection - { - public final ShapeSection SHAPE = section("shape", ShapeSection.class); - - static public class ShapeSection extends ConfigurationSection - { - public final ConfigurationItem WRITE_LETTER = item("writeLetter", true); - public final ConfigurationItem ADD_BORDER = item("addBorder", true); - } - - public final GiveSection GIVE = section("give", GiveSection.class); - - static public class GiveSection extends ConfigurationSection - { - public final ConfigurationItem PLACE_ON_SPAWN = item("placeOnSpawn", true); - public final ConfigurationItem GIVE_IN_HOTBAR = item("giveInHotbar", false); - public final ConfigurationItem GIVE_IN_HEAD = item("giveInHead", false); - } - - public final ShieldSection SHIELDS = section("shields", ShieldSection.class); - - static public class ShieldSection extends ConfigurationSection - { - public final ConfigurationItem ADD_ON_SHIELDS = item("addOnShields", true); - } - } - - public final GuiSection GUI = section("gui", GuiSection.class); - - static public class GuiSection extends ConfigurationSection - { - public final ConfigurationItem DISPLAY_PLAYERS_IN_TEAMS = item("displayPlayersInTeams", true); - public final ConfigurationItem AUTO_DISPLAY = item("autoDisplay", true); - public final ConfigurationItem DELAY = item("delay", 4); - } - - public final ChestGuiSection CHEST_GUI = section("chestGui", ChestGuiSection.class); - - static public class ChestGuiSection extends ConfigurationSection - { - public final DisplaySection DISPLAY = section("display", DisplaySection.class); - - static public class DisplaySection extends ConfigurationSection - { - public final ConfigurationItem TEAM_ITEM = item("teamItem", "banner"); - public final ConfigurationItem GLOW_ON_SELECTED_TEAM = item("glowOnSelectedTeam", true); - } - } - - public final TeamChatSection TEAM_CHAT = section("teamChat", TeamChatSection.class); - - static public class TeamChatSection extends ConfigurationSection - { - public final ConfigurationItem DISABLE_LOCK_ON_DEATH = item("disableLockOnDeath", true); - public final ConfigurationItem LOG = item("log", false); - } - } - - static public final HardcoreHeartsSection HARDCORE_HEARTS = section("hardcore-hearts", HardcoreHeartsSection.class); - - static public class HardcoreHeartsSection extends ConfigurationSection - { - public final ConfigurationItem DISPLAY = item("display", true); - public final ConfigurationItem RESPAWN_MESSAGE = item("respawnMessage", false); - } - - static public final AutoRespawnSection AUTO_RESPAWN = section("auto-respawn", AutoRespawnSection.class); - - static public class AutoRespawnSection extends ConfigurationSection - { - public final ConfigurationItem DO = item("do", true); - public final ConfigurationItem DELAY = item("delay", 6); - } - - static public final FinishSection FINISH = section("finish", FinishSection.class); - - static public class FinishSection extends ConfigurationSection - { - public final AutoSection AUTO = section("auto", AutoSection.class); - - static public class AutoSection extends ConfigurationSection - { - public final ConfigurationItem DO = item("do", true); - public final ConfigurationItem TIME_AFTER_LAST_DEATH = item("timeAfterLastDeath", 3); - } - - public final ConfigurationItem MESSAGE = item("message", true); - public final ConfigurationItem TITLE = item("title", true); - - public final FireworksSection FIREWORKS = section("fireworks", FireworksSection.class); - - static public class FireworksSection extends ConfigurationSection - { - public final ConfigurationItem ENABLED = item("enabled", true); - public final ConfigurationItem DURATION = item("duration", 10l); - public final ConfigurationItem AREA_SIZE = item("areaSize", 6d); - } - } - - static public final DynmapSection DYNMAP = section("dynmap", DynmapSection.class); - - static public class DynmapSection extends ConfigurationSection - { - public final ConfigurationItem SHOW_SPAWN_LOCATIONS = item("showSpawnLocations", true); - public final ConfigurationItem SHOW_DEATH_LOCATIONS = item("showDeathLocations", true); - } - - static public final ConfigurationItem SPECTATOR_MODE_WHEN_NEW_PLAYER_JOIN_AFTER_START = item("spectatorModeWhenNewPlayerJoinAfterStart", true); - - static public final RulesSection RULES = section("rules", RulesSection.class); - - static public class RulesSection extends ConfigurationSection - { - public final DisplaySection DISPLAY = section("display", DisplaySection.class); - - static public class DisplaySection extends ConfigurationSection - { - public final ConfigurationItem ON_JOIN = item("onJoin", false); - public final ConfigurationItem ON_START = item("onStart", true); - } - - public final ConfigurationList RULES = list("rules", String.class); - } - - static public final CommandsSection COMMANDS = section("commands", CommandsSection.class); - - static public class CommandsSection extends ConfigurationSection - { - public final ConfigurationList EXECUTE_SERVER_START = list("execute-server-start", String.class); - public final ConfigurationList EXECUTE_START = list("execute-start", String.class); - public final ConfigurationList EXECUTE_END = list("execute-end", String.class); - } - - static public final ProtipsSection PROTIPS = section("protips", ProtipsSection.class); - - static public class ProtipsSection extends ConfigurationSection - { - public final SoundSection SOUND = section("sound", SoundSection.class); - - public final TeamchatSection TEAMCHAT = section("teamchat", TeamchatSection.class); - - static public class TeamchatSection extends ConfigurationSection - { - public final ConfigurationItem USE_T_COMMAND = item("useTCommand", true); - public final ConfigurationItem LOCK = item("lock", true); - public final ConfigurationItem USE_G_COMMAND = item("useGCommand", true); - } - - public final CraftsSection CRAFTS = section("crafts", CraftsSection.class); - - static public class CraftsSection extends ConfigurationSection - { - public final ConfigurationItem GOLDEN_HEAD = item("goldenHead", true); - public final ConfigurationItem COMPASS_EASY = item("compassEasy", true); - public final ConfigurationItem COMPASS_MEDIUM = item("compassMedium", true); - public final ConfigurationItem COMPASS_HARD = item("compassHard", true); - public final ConfigurationItem GLISTERING_MELON = item("glisteringMelon", true); - public final ConfigurationItem NO_ENCH_GOLDEN_APPLE = item("noEnchGoldenApple", true); - } - - public final StartSection START = section("start", StartSection.class); - - static public class StartSection extends ConfigurationSection - { - public final ConfigurationItem INVINCIBILITY = item("invincibility", true); - } - } - - static public final ConfigurationList SPAWN_POINTS = list("spawnpoints", Vector.class); - static public final ConfigurationList TEAMS = list("teams", String.class); - static public final ConfigurationMap TEAM_BANNERS = map("teambanners", String.class, BannerMeta.class); - - /* ** Helper sub-sections ** */ - - static public class SoundSection extends ConfigurationSection - { - public final ConfigurationItem NAME = item("name", Sound.class); - public final ConfigurationItem VOLUME = item("volume", 1); - public final ConfigurationItem PITCH = item("pitch", 1); - } - - /* ** Helper value handlers ** */ - - static - { - ConfigurationValueHandlers.registerHandlers(TeamManager.class); - ConfigurationValueHandlers.registerHandlers(UHSound.class); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java deleted file mode 100644 index 91ca1c9..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java +++ /dev/null @@ -1,436 +0,0 @@ -/* - * 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.borders; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.borders.exceptions.CannotGenerateWallsException; -import eu.carrade.amaury.UHCReloaded.borders.generators.WallGenerator; -import eu.carrade.amaury.UHCReloaded.borders.worldborders.WorldBorder; -import eu.carrade.amaury.UHCReloaded.task.BorderWarningTask; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.PluginLogger; -import fr.zcraft.zlib.tools.runners.RunTask; -import fr.zcraft.zlib.tools.text.Titles; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.World.Environment; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; - -import java.util.HashSet; -import java.util.Set; - - -public class BorderManager -{ - private final boolean BORDER_SHRINKING; - private final long BORDER_SHRINKING_STARTS_AFTER; - private final long BORDER_SHRINKING_DURATION; - private final double BORDER_SHRINKING_FINAL_SIZE; - - private final UHCReloaded p; - - private WorldBorder border = null; - - private Integer warningSize = 0; - private BukkitRunnable warningTask = null; - - private Boolean warningFinalTimeEnabled = false; - private String warningTimerName = null; - private CommandSender warningSender = null; - - private MapShape mapShape = null; - - - public BorderManager(UHCReloaded plugin) - { - p = plugin; - - /// The name of the warning timer displaying the time left before the next border - warningTimerName = I.t("Border shrinking"); - - mapShape = UHConfig.MAP.SHAPE.get(); - if (mapShape == null) - { - PluginLogger.warning("Invalid shape '" + UHConfig.MAP.SHAPE.get() + "'; using 'squared' instead."); - mapShape = MapShape.SQUARED; - } - - - World world = UHUtils.getOverworld(); - - if (world == null) - { - world = Bukkit.getWorlds().get(0); - PluginLogger.warning("Cannot find overworld! Using the world '{0}' instead (environment: {1}).", world.getName(), world.getEnvironment()); - } - - border = WorldBorder.getInstance(world, UHConfig.MAP.BORDER.MOTOR.get(), mapShape); - - border.setShape(mapShape); - border.setCenter(world.getSpawnLocation()); - border.setDiameter(UHConfig.MAP.SIZE.get()); - - border.init(); - - PluginLogger.info("Using {0} to set the world border.", border.getClass().getSimpleName()); - - - BORDER_SHRINKING = UHConfig.MAP.BORDER.SHRINKING.ENABLED.get(); - BORDER_SHRINKING_STARTS_AFTER = UHUtils.string2Time(UHConfig.MAP.BORDER.SHRINKING.STARTS_AFTER.get(), 30*60); // Seconds - BORDER_SHRINKING_DURATION = UHUtils.string2Time(UHConfig.MAP.BORDER.SHRINKING.SHRINKS_DURING.get(), 60*60*2); // Same - BORDER_SHRINKING_FINAL_SIZE = UHConfig.MAP.BORDER.SHRINKING.DIAMETER_AFTER_SHRINK.get(); - } - - /** - * Sets the shape of the map. Updates the WorldBorder too. - * - * @param shape The shape. - */ - public void setMapShape(MapShape shape) - { - this.mapShape = shape; - border.setShape(shape); - } - - /** - * Returns the current shape of the map. - * - * @return The shape. - */ - public MapShape getMapShape() - { - return mapShape; - } - - /** - * @return The WorldBorder proxy to set the border in-game. - */ - public WorldBorder getBorderProxy() - { - return border; - } - - /** - * Checks if a given location is inside the border with the given diameter. - * The check is performed for a circular or squared border, following the configuration. - * - * @param location The location to check. - * @param diameter The diameter of the checked border. - * - * @return {@code true} if inside. - */ - public boolean isInsideBorder(Location location, double diameter) - { - // The nether/end are not limited. - return !location.getWorld().getEnvironment().equals(Environment.NORMAL) || mapShape.getShape().isInsideBorder(location, diameter, location.getWorld().getSpawnLocation()); - } - - /** - * Checks if a given location is inside the border with the current diameter. - * The check is performed for a circular or squared border, following the configuration. - * - * @param location The location to check. - * @return {@code true} if inside. - */ - public boolean isInsideBorder(Location location) - { - return this.isInsideBorder(location, getCurrentBorderDiameter()); - } - - /** - * Returns the distance from the location to the border, if the location is outside this border. - * If it is inside, or in another world, returns 0. - * - * @param location The location to check. - * @param diameter The diameter of the checked border. - * - * @return The distance, or 0 if the player is either inside the border or not in the world. - */ - public double getDistanceToBorder(Location location, double diameter) - { - return mapShape.getShape().getDistanceToBorder(location, diameter, location.getWorld().getSpawnLocation()); - } - - - /** - * Returns a list of the players outside a border with the given diameter. - * The check is performed for a circular or squared border, following the configuration. - * - * @param diameter The diameter of the checked border. - * @return A list of players out of the given diameter. - */ - public Set getPlayersOutside(int diameter) - { - HashSet playersOutside = new HashSet(); - - for (final Player player : p.getGameManager().getOnlineAlivePlayers()) - { - if (!isInsideBorder(player.getLocation(), diameter)) - { - playersOutside.add(player); - } - } - - return playersOutside; - } - - /** - * Returns the size of the future border, used in the warning messages sent to the - * players out of this future border. - * - * @return the future border diameter. - */ - public int getWarningSize() - { - return this.warningSize; - } - - /** - * @return true if there is currently a warning with a time left displayed. - */ - public boolean getWarningFinalTimeEnabled() - { - return this.warningFinalTimeEnabled; - } - - /** - * @return the sender of the last warning configured. - */ - public CommandSender getWarningSender() - { - return this.warningSender; - } - - /** - * Sets the size of the future border, used in the warning messages sent to the - * players out of this future border. - * - * This also starts the display of the warning messages, every 90 seconds by default - * (configurable, see config.yml, map.border.warningInterval). - * - * If timeLeft is not null, the time available for the players to go inside the future - * border is displayed in the warning message. - * - * @param diameter The future diameter. - * @param timeLeft The time available for the players to go inside the future border (minutes). - * @param sender The user who requested this change. - */ - public void setWarningSize(int diameter, int timeLeft, CommandSender sender) - { - cancelWarning(); - - this.warningSize = diameter; - - if (timeLeft != 0) - { - UHTimer timer = new UHTimer(this.warningTimerName); - timer.setDuration(timeLeft * 60); - - p.getTimerManager().registerTimer(timer); - - timer.start(); - } - - if (sender != null) - { - this.warningSender = sender; - } - - RunTask.timer( - warningTask = new BorderWarningTask(), - 20L, - 20L * p.getConfig().getInt("map.border.warningInterval", 90) - ); - } - - /** - * Sets the size of the future border, used in the warning messages sent to the - * players out of this future border. - * - * This also starts the display of the warning messages, every 90 seconds by default - * (configurable, see config.yml, map.border.warningInterval). - * - * @param diameter The diameter of the future border. - */ - public void setWarningSize(int diameter) - { - setWarningSize(diameter, 0, null); - } - - /** - * Returns the UHTimer object representing the countdown before the next border reduction. - * - *

Returns {@code null} if there isn't any countdown running currently.

- * - * @return The timer. - */ - public UHTimer getWarningTimer() - { - return p.getTimerManager().getTimer(this.warningTimerName); - } - - /** - * Stops the display of the warning messages. - */ - public void cancelWarning() - { - if (warningTask != null) - { - try - { - warningTask.cancel(); - } - catch (IllegalStateException ignored) {} - } - - UHTimer timer = getWarningTimer(); - if (timer != null) - { - timer.stop(); - p.getTimerManager().unregisterTimer(timer); - } - } - - /** - * @return the current border diameter. - */ - public int getCurrentBorderDiameter() - { - return (int) border.getDiameter(); - } - - /** - * Changes the current border diameter. - * This also reconfigures the used world border. - * - * If WorldBorder is installed, all players out of this new border will be teleported inside the new one. - * Else, nothing will happens. - * - * @param diameter the new diameter. - */ - public void setCurrentBorderDiameter(int diameter) - { - cancelWarning(); - - border.setDiameter(diameter); - } - - - /** - * Sends a list of the players outside the given border to the specified sender. - * - * @param to The player/console to send the check. - * @param diameter The diameter of the border to be checked. - */ - public void sendCheckMessage(CommandSender to, int diameter) - { - Set playersOutside = getPlayersOutside(diameter); - - if (playersOutside.size() == 0) - { - to.sendMessage(I.t("{cs}All players are inside the given border.")); - } - else - { - to.sendMessage(I.t("{ci}There are {0} players outside the given border.", String.valueOf(playersOutside.size()))); - for (Player player : getPlayersOutside(diameter)) - { - double distance = getDistanceToBorder(player.getLocation(), diameter); - if (distance > 150) - { - to.sendMessage(I.t("{lightpurple} - {red}{0}{ci} (far away from the border)", player.getName())); - } - else if (distance > 25) - { - to.sendMessage(I.t("{lightpurple} - {yellow}{0}{ci} (close to the border)", player.getName())); - } - else - { - to.sendMessage(I.t("{lightpurple} - {green}{0}{ci} (very close to the border)", player.getName())); - } - } - } - } - - /** - * Generates the walls in the given world, following the current border configuration. - * - * @param world The world were the walls will be built in. - * @throws CannotGenerateWallsException - */ - public void generateWalls(World world) throws CannotGenerateWallsException - { - Integer wallHeight = UHConfig.MAP.WALL.HEIGHT.get(); - - Material wallBlockAir = UHConfig.MAP.WALL.BLOCK.REPLACE_AIR.get(); - Material wallBlockSolid = UHConfig.MAP.WALL.BLOCK.REPLACE_SOLID.get(); - - if (wallBlockAir == null || !wallBlockAir.isSolid() || wallBlockSolid == null || !wallBlockSolid.isSolid()) - { - throw new CannotGenerateWallsException("Cannot generate the walls: invalid blocks set in the config"); - } - - WallGenerator generator = mapShape.getWallGeneratorInstance(wallBlockAir, wallBlockSolid); - if (generator != null) - generator.build(world, getCurrentBorderDiameter(), wallHeight); - else - throw new CannotGenerateWallsException("Unable to load walls generator."); - } - - /** - * Schedules the automatic border reduction, if enabled in the configuration. - */ - public void scheduleBorderReduction() - { - if (BORDER_SHRINKING) - { - RunTask.later(() -> { - Integer secondsPerBlock = (int) Math.rint(BORDER_SHRINKING_DURATION / (border.getDiameter() - BORDER_SHRINKING_FINAL_SIZE)) * 2; - - border.setDiameter(BORDER_SHRINKING_FINAL_SIZE, BORDER_SHRINKING_DURATION); - - Titles.broadcastTitle(5, 30, 8, I.t("{red}Warning!"), I.t("{white}The border begins to shrink...")); - - Bukkit.broadcastMessage(I.t("{red}{bold}The border begins to shrink...")); - Bukkit.broadcastMessage(I.t("{gray}It will shrink by one block every {0} second(s) until {1} blocks in diameter.", secondsPerBlock, BORDER_SHRINKING_FINAL_SIZE)); - }, BORDER_SHRINKING_STARTS_AFTER * 20l); - } - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/MapShape.java b/src/main/java/eu/carrade/amaury/UHCReloaded/borders/MapShape.java deleted file mode 100644 index ee22c5d..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/MapShape.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.borders; - -import eu.carrade.amaury.UHCReloaded.borders.generators.CircularWallGenerator; -import eu.carrade.amaury.UHCReloaded.borders.generators.SquaredWallGenerator; -import eu.carrade.amaury.UHCReloaded.borders.generators.WallGenerator; -import eu.carrade.amaury.UHCReloaded.borders.shapes.CircularMapShape; -import eu.carrade.amaury.UHCReloaded.borders.shapes.MapShapeDescriptor; -import eu.carrade.amaury.UHCReloaded.borders.shapes.SquaredMapShape; -import fr.zcraft.zlib.tools.PluginLogger; -import org.bukkit.Material; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - - -public enum MapShape -{ - CIRCULAR(new CircularMapShape(), CircularWallGenerator.class), - SQUARED(new SquaredMapShape(), SquaredWallGenerator.class); - - - private MapShapeDescriptor shape; - private Class generatorClass; - - /** - * @param generator The wall generator class associated with this shape. - */ - MapShape(MapShapeDescriptor shape, Class generator) - { - this.shape = shape; - this.generatorClass = generator; - } - - /** - * Returns a new instance of the wall generator for this shape. - * - * @return The instance. - */ - public WallGenerator getWallGeneratorInstance(Material wallBlockAir, Material wallBlockSolid) - { - try - { - Constructor constructor = generatorClass.getConstructor(Material.class, Material.class); - return (WallGenerator) constructor.newInstance(wallBlockAir, wallBlockSolid); - - } - catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) - { - PluginLogger.error("Cannot instantiate the walls generator: invalid class.", e); - return null; - } - } - - /** - * Returns the shape descriptor. - * - * @return The shape. - */ - public MapShapeDescriptor getShape() - { - return shape; - } - - /** - * Returns a shape based on his name. - * - *

Not case sensitive.

- * - * @param name The name. - * @return The MapShape, or {@code null} if not found. - */ - public static MapShape fromString(String name) - { - try - { - return MapShape.valueOf(name.trim().toUpperCase()); - } - catch (IllegalArgumentException e) - { - return null; - } - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/worldborders/BrettflanWorldBorder.java b/src/main/java/eu/carrade/amaury/UHCReloaded/borders/worldborders/BrettflanWorldBorder.java deleted file mode 100644 index 312e85c..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/worldborders/BrettflanWorldBorder.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * 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.borders.worldborders; - -import com.wimbli.WorldBorder.BorderData; -import com.wimbli.WorldBorder.Config; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.borders.MapShape; -import fr.zcraft.zlib.tools.runners.RunTask; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.scheduler.BukkitTask; - - -/** - * Represents a Brettflan world border, from the WorldBorder Bukkit plugin. - * - *

These methods are not supported as the border cannot be bypassed and does not have - * warnings:

- *
    - *
  • {@link #setDamageBuffer(double)};
  • - *
  • {@link #setDamageAmount(double)};
  • - *
  • {@link #setWarningDistance(int)};
  • - *
  • {@link #setWarningTime(int)}.
  • - *
- */ -public class BrettflanWorldBorder extends WorldBorder -{ - private World world; - private BorderData border; - - private Double diameter = 0d; - - private BukkitTask slowReductionTask = null; - - - public BrettflanWorldBorder(World world) - { - this.world = world; - - com.wimbli.WorldBorder.WorldBorder wb = UHCReloaded.get().getWorldBorderIntegration().getWorldBorder(); - if (wb != null) - { - border = wb.getWorldBorder(world.getName()); - - if (border == null) - { - border = new BorderData(world.getSpawnLocation().getX(), world.getSpawnLocation().getZ(), 3000000); - Config.setBorder(world.getName(), border); - } - } - } - - @Override - public void init() - { - Config.setPortalRedirection(true); - } - - @Override - public World getWorld() - { - return world; - } - - @Override - public double getDiameter() - { - // If squared, the size is not changed - if (!border.getShape()) - return diameter; - - - Double realDiameter = (double) (border.getRadiusX() * 2); - - // Returns the stored diameter, except if it was changed - // manually with /wb (see #setDiameterInternal(Double) for - // details). - if (realDiameter - diameter >= 8) - diameter = realDiameter; - - return diameter; - } - - @Override - public void setDiameter(double diameter) - { - setDiameterInternal(diameter); - - if (slowReductionTask != null) - { - slowReductionTask.cancel(); - slowReductionTask = null; - } - } - - @Override - public void setDiameter(final double diameter, final long time) - { - // The behavior of the vanilla reduction is emulated. - final double currentDiameter = getDiameter(); - - final long ticksPerBlockRemoved = (int) Math.rint(time / (currentDiameter - diameter)) * 20L; - final long movement = (diameter >= currentDiameter) ? 1 : -1; - - if (slowReductionTask != null) - { - slowReductionTask.cancel(); - slowReductionTask = null; - } - - slowReductionTask = RunTask.timer(() -> { - double newDiameter = getDiameter() + movement; - - // If the final size is achieved, we set the exact requested size and we stop here. - // Calling setDiameter cancels this task. - if ((movement < 0 && newDiameter <= diameter) || (movement > 0 && newDiameter >= diameter)) - { - setDiameter(diameter); - } - else - { - setDiameterInternal(newDiameter); - } - }, ticksPerBlockRemoved, ticksPerBlockRemoved); - } - - private void setDiameterInternal(double diameter) - { - this.diameter = diameter; - - // If the wall is circular, the diameter used to check must be bigger to avoid false positives - // if a player is in an angle of the circular wall. The original diameter set is stored and - // returned by the getDiameter value (except if the diameter was changed using /wb), for nicer - // display (avoids rounding errors). - // “+3” ? Experimental. - int offset = (getShape() == MapShape.CIRCULAR) ? 3 : 0; - - border.setRadius((int) Math.floor((diameter + offset) / 2)); - } - - @Override - public Location getCenter() - { - return new Location(world, border.getX(), 0, border.getZ()); - } - - @Override - public void setCenter(double x, double z) - { - border.setX(x); - border.setZ(z); - } - - @Override - public void setCenter(Location center) - { - setCenter(center.getX(), center.getZ()); - } - - @Override - public double getDamageBuffer() { return 0; } - - @Override - public void setDamageBuffer(double distance) {} - - @Override - public double getDamageAmount() { return 0; } - - @Override - public void setDamageAmount(double damageAmount) {} - - @Override - public int getWarningTime() { return 0; } - - @Override - public void setWarningTime(int seconds) {} - - @Override - public int getWarningDistance() { return 0; } - - @Override - public void setWarningDistance(int blocks) {} - - @Override - public MapShape getShape() - { - return border.getShape() ? MapShape.CIRCULAR : MapShape.SQUARED; - } - - @Override - public void setShape(MapShape shape) - { - border.setShape(shape == MapShape.CIRCULAR); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/UHCommandExecutor.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/UHCommandExecutor.java deleted file mode 100644 index bbb9c59..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/UHCommandExecutor.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.commands; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.GlobalMessageCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.JoinCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.LeaveCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.TeamMessageCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.TeamsCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.ToggleChatCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.UHRootCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommandExecutor; - - -public class UHCommandExecutor extends AbstractCommandExecutor -{ - public UHCommandExecutor(UHCReloaded p) - { - super(p); - - registerCommand(new UHRootCommand(p)); // /uh - - registerCommand(new JoinCommand(p)); // /join - registerCommand(new LeaveCommand(p)); // /leave - registerCommand(new TeamsCommand(p)); // /teams - - registerCommand(new TeamMessageCommand(p)); // /t - registerCommand(new GlobalMessageCommand(p)); // /g - registerCommand(new ToggleChatCommand(p)); // /togglechat - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/GlobalMessageCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/GlobalMessageCommand.java deleted file mode 100644 index 8ffd5a9..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/GlobalMessageCommand.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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.commands.commands; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; - - -/** - * This command, /g , is used to send a global message while being in - * the locked team-chat. - */ -@Command (name = "g", noPermission = true) -public class GlobalMessageCommand extends AbstractCommand -{ - private UHCReloaded p; - - public GlobalMessageCommand(UHCReloaded p) - { - this.p = p; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (!(sender instanceof Player)) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.ONLY_AS_A_PLAYER); - } - - // /t - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - StringBuilder message = new StringBuilder(); - for (String arg : args) - { - message.append(arg).append(" "); - } - - p.getTeamChatManager().sendGlobalMessage((Player) sender, message.toString()); - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - - @Override - public List help(CommandSender sender) - { - /// Usage of the /g and /t commands - return Collections.singletonList(I.t("{ce}Usage: /{0} ", "g")); - } - - @Override - public List onListHelp(CommandSender sender) - { - return null; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/JoinCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/JoinCommand.java deleted file mode 100644 index 59d55f6..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/JoinCommand.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.commands.commands; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamJoinCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - - -// The permissions are too complex, we need to manage them manually. -@Command (name = "join", noPermission = true, inheritPermission = false) -public class JoinCommand extends UHTeamJoinCommand -{ - private UHCReloaded p; - - public JoinCommand(UHCReloaded plugin) - { - super(plugin); - p = plugin; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0 && sender instanceof Player - && sender.hasPermission("uh.player.join.self")) - { - p.getTeamManager().displayTeamChooserChatGUI((Player) sender); - } - - else - { - super.run(sender, args); - } - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/TeamMessageCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/TeamMessageCommand.java deleted file mode 100644 index 7b37dcc..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/TeamMessageCommand.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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.commands.commands; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; - - -/** - * This command, /t , is used to send a team-message. - */ -@Command (name = "t", noPermission = true) -public class TeamMessageCommand extends AbstractCommand -{ - private UHCReloaded p; - - public TeamMessageCommand(UHCReloaded p) - { - this.p = p; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (!(sender instanceof Player)) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.ONLY_AS_A_PLAYER); - } - - // /t - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - StringBuilder message = new StringBuilder(); - for (final String arg : args) - { - message.append(arg).append(" "); - } - - p.getTeamChatManager().sendTeamMessage((Player) sender, message.toString()); - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - - @Override - public List help(CommandSender sender) - { - /// Usage of the /g and /t commands - return Collections.singletonList(I.t("{ce}Usage: /{0} ", "t")); - } - - @Override - public List onListHelp(CommandSender sender) - { - return null; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/TeamsCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/TeamsCommand.java deleted file mode 100644 index 75d5b14..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/TeamsCommand.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.commands.commands; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamGUICommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; - - -@Command (name = "teams", noPermission = true, inheritPermission = false) -public class TeamsCommand extends UHTeamGUICommand -{ - public TeamsCommand(UHCReloaded plugin) - { - super(plugin); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/ToggleChatCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/ToggleChatCommand.java deleted file mode 100644 index 38aaf62..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/ToggleChatCommand.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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.commands.commands; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.List; - - -/** - * This command, /togglechat, is used to toggle the chat between the global chat and - * the team chat. - */ -@Command (name = "togglechat", noPermission = true) -public class ToggleChatCommand extends AbstractCommand -{ - private UHCReloaded p; - - public ToggleChatCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (!(sender instanceof Player)) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.ONLY_AS_A_PLAYER); - } - - // /togglechat - if (args.length == 0) - { - if (p.getTeamChatManager().toggleChatForPlayer((Player) sender)) - { - sender.sendMessage(I.t("{cs}You are now chatting with your team only.")); - } - else - { - sender.sendMessage(I.t("{cs}You are now chatting with everyone.")); - } - } - - // /togglechat - else - { - String teamName = UHUtils.getStringFromCommandArguments(args, 0); - UHTeam team = p.getTeamManager().getTeam(teamName); - - if (team != null) - { - if (p.getTeamChatManager().toggleChatForPlayer((Player) sender, team)) - { - sender.sendMessage(I.t("{cs}You are now chatting with the team {0}{cs}.", team.getDisplayName())); - } - } - else - { - sender.sendMessage(I.t("{ce}This team does not exists.")); - } - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - if (sender instanceof Player && sender.hasPermission("uh.teamchat.others")) - { - ArrayList teamNames = new ArrayList<>(); - - for (UHTeam team : p.getTeamManager().getTeams()) - { - teamNames.add(team.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 0), teamNames, args.length - 1); - } - - else return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return null; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/UHRootCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/UHRootCommand.java deleted file mode 100644 index 754bd26..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/UHRootCommand.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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.commands.commands; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHAboutCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHBorderCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHFeedAllCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHFeedCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHFinishCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHFreezeCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHGenerateWallsCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHHealAllCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHHealCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHInfosCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHKillCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHLoadPlayersCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHResurrectCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHRulesCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHShiftCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHSpawnsCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHSpectatorsCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHStartCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHTPBackCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHTPCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHTPSpawnCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHTeamCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.UHTimersCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import org.bukkit.command.CommandSender; - -import java.util.List; - - -@Command (name = "uh") -public class UHRootCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHRootCommand(UHCReloaded plugin) - { - p = plugin; - - // Game - registerSubCommand(new UHStartCommand(p)); - registerSubCommand(new UHShiftCommand(p)); - registerSubCommand(new UHSpawnsCommand(p)); - registerSubCommand(new UHTeamCommand(p)); - registerSubCommand(new UHBorderCommand(p)); - registerSubCommand(new UHSpectatorsCommand(p)); - registerSubCommand(new UHGenerateWallsCommand(p)); - - // Bugs - registerSubCommand(new UHHealCommand(p)); - registerSubCommand(new UHHealAllCommand(p)); - registerSubCommand(new UHFeedCommand(p)); - registerSubCommand(new UHFeedAllCommand(p)); - registerSubCommand(new UHKillCommand(p)); - registerSubCommand(new UHResurrectCommand(p)); - registerSubCommand(new UHTPBackCommand(p)); - registerSubCommand(new UHTPSpawnCommand(p)); - - // Misc - registerSubCommand(new UHFinishCommand(p)); - registerSubCommand(new UHFreezeCommand(p)); - registerSubCommand(new UHTimersCommand(p)); - registerSubCommand(new UHTPCommand(p)); - registerSubCommand(new UHInfosCommand(p)); - registerSubCommand(new UHRulesCommand(p)); - registerSubCommand(new UHLoadPlayersCommand()); - registerSubCommand(new UHAboutCommand(p)); - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NEED_DOC, this); - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return null; - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java deleted file mode 100644 index ece3639..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.components.i18n.I18n; -import org.bukkit.command.CommandSender; - -import java.io.IOException; -import java.net.URL; -import java.util.Collections; -import java.util.List; -import java.util.jar.Attributes; -import java.util.jar.Manifest; - - -/** - * This command prints some informations about the plugin and the translation. - * - * Usage: /uh about - */ -@Command (name = "about") -public class UHAboutCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHAboutCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - CommandUtils.displaySeparator(sender); - sender.sendMessage(I.t("{yellow}{0} - version {1}", p.getDescription().getDescription(), p.getDescription().getVersion())); - - // Authors - - final StringBuilder authors = new StringBuilder(); - final List listAuthors = p.getDescription().getAuthors(); - - for (final String author : listAuthors) - { - if (!author.equals(listAuthors.get(0))) - { - if (author.equals(listAuthors.get(listAuthors.size() - 1))) - { - /// The "and" in the authors list (like "Amaury Carrade, azenet and João Roda") - authors.append(" ").append(I.tc("authors_list", "and")).append(" "); - } - else - { - authors.append(", "); - } - } - - authors.append(author); - } - sender.sendMessage(I.t("Plugin made with love by {0}.", authors.toString())); - - // Build number - - String build = null; - try - { - Class clazz = p.getClass(); - String className = clazz.getSimpleName() + ".class"; - String classPath = clazz.getResource(className).toString(); - if (classPath.startsWith("jar")) // Class from JAR - { - String manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) + - "/META-INF/MANIFEST.MF"; - Manifest manifest = new Manifest(new URL(manifestPath).openStream()); - Attributes attr = manifest.getMainAttributes(); - - build = attr.getValue("Git-Commit"); - } - } - catch (IOException e) - { - // Build not available. - } - - if (build != null) - { - sender.sendMessage(I.t("Build number: {0}.", build)); - } - else - { - sender.sendMessage(I.t("Build number not available.")); - } - - // Translation - - sender.sendMessage(I.t("{aqua}------ Translations ------")); - sender.sendMessage(I.t("Current language: {0} (translated by {1}).", I18n.getPrimaryLocale(), I18n.getTranslationTeam(I18n.getPrimaryLocale()))); - sender.sendMessage(I.t("Fallback language: {0} (translated by {1}).", I18n.getFallbackLocale(), I18n.getTranslationTeam(I18n.getFallbackLocale()))); - sender.sendMessage(I.t("{aqua}------ License ------")); - sender.sendMessage(I.t("Published under the CeCILL-B License.")); - - CommandUtils.displaySeparator(sender); - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh about {ci}: informations about the plugin and the translation.")); - } - - @Override - public String getCategory() - { - return Category.MISC.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHBorderCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHBorderCommand.java deleted file mode 100644 index f83ab73..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHBorderCommand.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.border.UHBorderCheckCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.border.UHBorderGetCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.border.UHBorderSetCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.border.UHBorderWarningCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; - - -/** - * This command manages borders (gets current, checks if players are out, sets a new size, warns players - * about the future size). - * - * Usage: /uh border (doc) - * Usage: /uh border - */ -@Command (name = "border") -public class UHBorderCommand extends AbstractCommand -{ - public UHBorderCommand(UHCReloaded p) - { - registerSubCommand(new UHBorderGetCommand(p)); - registerSubCommand(new UHBorderSetCommand(p)); - registerSubCommand(new UHBorderWarningCommand(p)); - registerSubCommand(new UHBorderCheckCommand(p)); - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NEED_DOC, this); - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return Collections.singletonList(I.t("{aqua}------ Border commands ------")); - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh border {ci}: manages borders. Execute /uh border for details.")); - } - - @Override - public String getCategory() - { - return Category.GAME.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedAllCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedAllCommand.java deleted file mode 100644 index a5f1cc2..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedAllCommand.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; -/** - * This command feeds all player. - * - * Usage: /uh feed <player> [foodLevel=20] [saturation=20] - */ -@Command (name = "feedall") -public class UHFeedAllCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHFeedAllCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - int foodLevel = 20; - float saturation = 20f; - - if (args.length > 0) // /uh feedall - { - try - { - foodLevel = Integer.valueOf(args[0]); - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}Food points and saturation must be numbers (floats for the saturation)!")); - return; - } - - if (args.length > 1) // /uh feedall - { - try - { - // The saturation value cannot be more than the food level. - saturation = Math.min(foodLevel, Float.valueOf(args[1])); - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}Food points and saturation must be numbers (floats for the saturation)!")); - return; - } - } - } - - for (Player player : p.getServer().getOnlinePlayers()) - { - player.setFoodLevel(foodLevel); - player.setSaturation(saturation); - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh feedall [foodPoints=20] [saturation=max] {ci}: feeds all players.")); - } - - @Override - public String getCategory() - { - return Category.BUGS.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedCommand.java deleted file mode 100644 index a31fb19..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedCommand.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; - -/** - * This command feeds a player. - * - * Usage: /uh feed <player> [foodLevel=20] [saturation=20] - */ -@Command (name = "feed") -public class UHFeedCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHFeedCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length < 1) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - final Player target = p.getServer().getPlayer(args[0]); - if (target == null || !target.isOnline()) - { - sender.sendMessage(I.t("{ce}This player is offline.")); - return; - } - - int foodLevel = 20; - float saturation = 20f; - - if (args.length > 1) // /uh feed - { - try - { - foodLevel = Integer.valueOf(args[1]); - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}Food points and saturation must be numbers (floats for the saturation)!")); - return; - } - - if (args.length > 2) // /uh feed - { - try - { - // The saturation value cannot be more than the food level. - saturation = Math.min(foodLevel, Float.valueOf(args[2])); - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}Food points and saturation must be numbers (floats for the saturation)!")); - return; - } - } - } - - target.setFoodLevel(foodLevel); - target.setSaturation(saturation); - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh feed [foodPoints=20] [saturation=max] {ci}: feeds a player.")); - } - - @Override - public String getCategory() - { - return Category.BUGS.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFinishCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFinishCommand.java deleted file mode 100644 index deb0042..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFinishCommand.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.game.UHGameManager; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; - -/** - * This commands broadcast the winner(s) of the game and sends some fireworks at these players. - * It fails if there is more than one team alive. - * - * Usage: /uh finish - */ -@Command (name = "finish") -public class UHFinishCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHFinishCommand(UHCReloaded plugin) - { - this.p = plugin; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - try - { - p.getGameManager().finishGame(); - - } - catch (IllegalStateException e) - { - switch (e.getMessage()) - { - case UHGameManager.FINISH_ERROR_NOT_STARTED: - sender.sendMessage(I.t("{ce}The game is not started!")); - break; - - case UHGameManager.FINISH_ERROR_NOT_FINISHED: - sender.sendMessage(I.t("{ce}There's not one team alive!")); - break; - - default: - throw e; - } - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh finish {ci}: displays the name of the winner(s) and launches some fireworks.")); - } - - @Override - public String getCategory() - { - return Category.MISC.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java deleted file mode 100644 index e936ccc..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * This command freezes the players. - * - * Usage: /uh freeze - * - on [player]: freezes the given player, or the sender if no player was provided. - * - off [player]: unfreezes the given player (or the sender, same condition). - * - all: freezes all the alive players, the mobs and the timer. - * - none: unfreezes all the alive players (even if there where frozen before using - * /uh freeze all), the mobs and the timer. - */ -@Command (name = "freeze") -public class UHFreezeCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHFreezeCommand(UHCReloaded plugin) - { - p = plugin; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NEED_DOC, this); - } - - String subCommand = args[0]; - - if (subCommand.equalsIgnoreCase("on") || subCommand.equalsIgnoreCase("off")) - { - final boolean on = subCommand.equalsIgnoreCase("on"); - - // /uh freeze on: freezes the sender - if (args.length == 1) - { - if (sender instanceof Player) - { - p.getFreezer().setPlayerFreezeState((Player) sender, on); - - if (on) - { - sender.sendMessage(I.t("{cst}You where frozen by {0}.", sender.getName())); - } - else - { - sender.sendMessage(I.t("{cst}You where unfrozen by {0}.", sender.getName())); - } - } - else - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.ONLY_AS_A_PLAYER); - } - } - - // /uh freeze on : freezes . - else if (args.length == 2) - { - Player player = p.getServer().getPlayer(args[1]); - if (player == null) - { - sender.sendMessage(I.t("{ce}{0} is offline!", args[1])); - } - else - { - p.getFreezer().setPlayerFreezeState(player, on); - if (on) - { - player.sendMessage(I.t("{cst}You where frozen by {0}.", sender.getName())); - sender.sendMessage(I.t("{cs}{0} is now frozen.", player.getName())); - } - else - { - player.sendMessage(I.t("{cst}You where unfrozen by {0}.", sender.getName())); - sender.sendMessage(I.t("{cs}{0} is now unfrozen.", player.getName())); - } - } - } - } - - else if (subCommand.equalsIgnoreCase("all") || subCommand.equalsIgnoreCase("none")) - { - final boolean on = subCommand.equalsIgnoreCase("all"); - - p.getFreezer().setGlobalFreezeState(on); - - if (on) - { - p.getServer().broadcastMessage(I.t("{darkaqua}The entire game is now frozen.")); - } - else - { - p.getServer().broadcastMessage(I.t("{darkaqua}The game is now unfrozen.")); - } - - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - if (args.length == 1) - { - return CommandUtils.getAutocompleteSuggestions( - args[0], Arrays.asList("on", "off", "all", "none") - ); - } - - else if (args.length == 2) - { - if (args[0].equalsIgnoreCase("off")) - { - List suggestions = new ArrayList<>(); - - for (Player player : p.getFreezer().getFrozenPlayers()) - { - suggestions.add(player.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(args[1], suggestions); - } - - else return null; - } - - else return null; - } - - @Override - public List help(CommandSender sender) - { - return Arrays.asList( - I.t("{aqua}------ Freeze commands ------"), - I.t("{cc}/uh freeze on [player]{ci}: freezes a player, or the sender without a specified player."), - I.t("{cc}/uh freeze off [player]{ci}: unfreezes a player (or the sender), even if the entire game is frozen."), - I.t("{cc}/uh freeze all{ci}: freezes the entire game (players, mobs, timer)."), - I.t("{cc}/uh freeze none{ci}: unfreezes the entire game. You NEED to execute this in order to relaunch the timer.") - ); - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh freeze {ci}: (un)freezes the entire game, or a player. See /uh freeze for details.")); - } - - @Override - public String getCategory() - { - return Category.MISC.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHGenerateWallsCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHGenerateWallsCommand.java deleted file mode 100644 index 66780d7..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHGenerateWallsCommand.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.borders.exceptions.CannotGenerateWallsException; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.World; -import org.bukkit.command.BlockCommandSender; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; - -/** - * This command generates the walls around the map. - * - * Usage: /uh generatewalls - */ -@Command (name = "generatewalls") -public class UHGenerateWallsCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHGenerateWallsCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - sender.sendMessage(I.t("{cst}Generating the walls...")); - - final World world; - - if (sender instanceof Player) - { - world = ((Player) sender).getWorld(); - } - else if (sender instanceof BlockCommandSender) - { - world = ((BlockCommandSender) sender).getBlock().getWorld(); - } - else - { - world = p.getServer().getWorlds().get(0); - sender.sendMessage(I.t("{ci}From the console, generating the walls of the default world, {0}", world.getName())); - } - - try - { - p.getBorderManager().generateWalls(world); - - } - catch (CannotGenerateWallsException e) - { - sender.sendMessage(I.t("{ce}Unable to generate the wall: see logs for details. The blocks set in the config are probably invalid.")); - return; - - } - catch (Exception e) - { - sender.sendMessage(I.t("{ce}An error occurred, see console for details.")); - e.printStackTrace(); - return; - } - - sender.sendMessage(I.t("{cst}Generation done.")); - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh generatewalls {ci}: generates the walls according to the configuration.")); - } - - @Override - public String getCategory() - { - return Category.GAME.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealAllCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealAllCommand.java deleted file mode 100644 index 3d02795..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealAllCommand.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; - -/** - * This command feeds a player. - *

- * Usage: /uh feed <player> [foodLevel=20] [saturation=20] - */ -@Command (name = "healall") -public class UHHealAllCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHHealAllCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - double diffHealth = 0D; - double health = 0D; - boolean add = false; // "add" (±, true) or "raw" (exact health, false) mode - - - if (args.length == 0) // /uh healall : full life for all players. - { - diffHealth = 20D; - } - else // /uh heal - { - try - { - if (args[0].startsWith("+")) - { - diffHealth = Double.parseDouble(args[0].substring(1)); - add = true; - } - else if (args[0].startsWith("-")) - { - diffHealth = -1 * Double.parseDouble(args[0].substring(1)); - add = true; - } - else - { - diffHealth = Double.parseDouble(args[0]); - } - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}Hey, this is not a number of half-hearts. It's a text. Pfff.")); - return; - } - } - - if ((!add && diffHealth <= 0) || diffHealth <= -20) - { - sender.sendMessage(I.t("{ce}Serial killer!")); - return; - } - - - for (final Player player : p.getServer().getOnlinePlayers()) - { - health = !add ? diffHealth : player.getHealth() + diffHealth; - - if (health <= 0D) - { - sender.sendMessage(I.t("{ce}The health of {0} was not updated to avoid a kill.", player.getName())); - continue; - } - else if (health > 20D) - { - health = 20D; - } - - player.setHealth(health); - UHCReloaded.get().getScoreboardManager().getSidebarPlayerCache(player.getUniqueId()).updateHealth(health); - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh healall [half-hearts=20|±diff] {ci}: heals all players instead of only one.")); - } - - @Override - public String getCategory() - { - return Category.BUGS.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealCommand.java deleted file mode 100644 index b2040f0..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealCommand.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; - - -/** - * This command heals a player. - * - * Usage: /uh heal - */ -@Command (name = "heal") -public class UHHealCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHHealCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length < 1 || args.length > 2) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - Player player = p.getServer().getPlayer(args[0]); - if (player == null || !player.isOnline()) - { - sender.sendMessage(I.t("{ce}This player is offline.")); - return; - } - - double health; - boolean add = false; // "add" (±, true) or "raw" (exact health, false) mode - - if (args.length == 1) - { // /uh heal : full life for player. - health = 20D; - } - else - { // /uh heal - double diffHealth; - - try - { - if (args[1].startsWith("+")) - { - diffHealth = Double.parseDouble(args[1].substring(1)); - add = true; - } - else if (args[1].startsWith("-")) - { - diffHealth = -1 * Double.parseDouble(args[1].substring(1)); - add = true; - } - else - { - diffHealth = Double.parseDouble(args[1]); - } - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}Hey, this is not a number of half-hearts. It's a text. Pfff.")); - return; - } - - health = !add ? diffHealth : player.getHealth() + diffHealth; - - if (health <= 0D) - { - sender.sendMessage(I.t("{ce}You can't kill a player with this command, to avoid typo fails.")); - return; - } - else if (health > 20D) - { - health = 20D; - } - } - - player.setHealth(health); - UHCReloaded.get().getScoreboardManager().getSidebarPlayerCache(player.getUniqueId()).updateHealth(health); - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh heal [half-hearts=20|±diff] {ci}: heals a player to the number of half-hearts provided (default 20).")); - } - - @Override - public String getCategory() - { - return Category.BUGS.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java deleted file mode 100644 index dec93b8..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.text.RawMessage; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; - -@Command (name = "infos") -public class UHInfosCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHInfosCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - CommandUtils.displaySeparator(sender); - - if (p.getGameManager().isGameStarted()) - { - /// Header of the /uh infos command. Plural based on the players count. - sender.sendMessage(I.tn("{ci}{0} player alive in {1} team.", "{ci}{0} players alive in {1} teams.", p.getGameManager().getAlivePlayersCount(), p.getGameManager().getAlivePlayersCount(), p.getGameManager().getAliveTeamsCount())); - } - else - { - sender.sendMessage(I.t("{ci}The game is not started.")); - } - - for (UHTeam team : p.getTeamManager().getTeams()) - { - for (OfflinePlayer player : team.getPlayers()) - { - if (sender instanceof Player) - { - /* We can use a JSON-based message */ - - String json = "{\"text\":\"\",\"extra\":["; - - - // Online/offline bullet - json += "{"; - if (player.isOnline()) - { - /// Online status dot in /uh infos - json += "\"text\":\"" + I.t("{green} • ") + "\","; - json += "\"hoverEvent\":{\"action\":\"show_text\",\"value\":\"" + I.t("Currently online") + "\"}"; - } - else - { - /// Offline status dot in /uh infos - json += "\"text\":\"" + I.t("{red} • ") + "\","; - json += "\"hoverEvent\":{\"action\":\"show_text\",\"value\":\"" + I.t("Currently offline") + "\"}"; - } - json += "},"; - - - // Name and team - json += "{"; - json += "\"text\":\"" + team.getColorOrWhite().toChatColor() + player.getName() + ChatColor.RESET + "\","; - /// Team name in tooltip in /uh infos - json += "\"hoverEvent\":{\"action\":\"show_text\",\"value\":\"" + I.t("Team: {0}", team.getDisplayName()) + "\"}"; - json += "}"; - - - if (p.getGameManager().isGameStarted()) - { - /// Separator in /uh infos - json += ",{\"text\":\"" + I.t("{gray} - ") + "\"},"; - - // Alive state - json += "{"; - if (!p.getGameManager().isPlayerDead(player.getUniqueId())) - { - /// Alive state in /uh infos - json += "\"text\":\"" + I.t("{green}alive") + "\","; - if (player.isOnline()) - { - json += "\"hoverEvent\":{\"action\":\"show_text\",\"value\":\"" + I.t("{0} half-hearts", String.valueOf((int) ((Player) player).getHealth())) + "\"}"; - } - } - else - { - /// Alive state in /uh infos - json += "\"text\":\"" + I.t("{red}dead") + "\""; - } - json += "}"; - } - - // End - json += "]}"; - - RawMessage.send((Player) sender, json); - } - else - { - /* Fallback to a simple display for the console */ - - String info; - - if (player.isOnline()) - { - info = I.t("{green} • "); - } - else - { - info = I.t("{red} • "); - } - - info += team.getColorOrWhite().toChatColor() + player.getName() + ChatColor.RESET; - - if (p.getGameManager().isGameStarted()) - { - info += I.t("{gray} - "); - - if (!p.getGameManager().isPlayerDead(player.getUniqueId())) - { - info += I.t("{green}alive"); - } - else - { - info += I.t("{red}dead"); - } - } - - sender.sendMessage(info); - } - } - } - - - CommandUtils.displaySeparator(sender); - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh infos {ci}: prints some infos about the current game.")); - } - - @Override - public String getCategory() - { - return Category.MISC.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHKillCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHKillCommand.java deleted file mode 100644 index 800d74c..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHKillCommand.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * This command marks a player as dead, even if he is offline. - * - * If the player is online, this has the same effect as {@code /kill}. - * - * Usage: /uh kill <player> - */ -@Command (name = "kill") -public class UHKillCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHKillCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length < 1) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - OfflinePlayer player = p.getServer().getOfflinePlayer(args[0]); - - if (player == null) - { - sender.sendMessage(I.t("{ce}This player was never seen on this server.")); - return; - } - - if (!p.getGameManager().isPlayerDead(player.getUniqueId())) - { - if (player.isOnline()) - { - ((Player) player).setHealth(0); - } - else - { - p.getGameManager().addDead(player.getUniqueId()); - } - - sender.sendMessage(I.t("{cs}The player {0} is now marked as dead.", player.getName())); - } - else - { - sender.sendMessage(I.t("{ce}{0} is not an alive player.", player.getName())); - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - if (args.length == 1) - { - List suggestions = new ArrayList<>(); - - for (OfflinePlayer player : p.getGameManager().getAlivePlayers()) - { - suggestions.add(player.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(args[0], suggestions); - } - - else return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh kill {ci}: mark a player as dead, even if he is offline.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHLoadPlayersCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHLoadPlayersCommand.java deleted file mode 100644 index e05baf1..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHLoadPlayersCommand.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.misc.OfflinePlayersLoader; -import fr.zcraft.zlib.components.i18n.I; -import org.apache.commons.lang.StringUtils; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - - -@Command(name = "loadplayers") -public class UHLoadPlayersCommand extends AbstractCommand -{ - @Override - public void run(final CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (!Bukkit.getOnlineMode()) - { - sender.sendMessage(I.t("{ce}You cannot load unknown players in offline mode, sorry.")); - return; - } - - if (args.length == 0) - { - /// Error returned if one calls /uh loadplayers without arguments. - sender.sendMessage(I.t("{ce}You need to provide at least one player name.")); - return; - } - - /// Message displayed when the /uh loadplayers command is used, as the execution may take some time. - sender.sendMessage(I.t("{cst}Loading players...")); - - OfflinePlayersLoader.loadPlayers( - Arrays.asList(args), - addedPlayers -> sender.sendMessage(I.tn("{cs}Loaded {0} player successfully.", "{cs}Loaded {0} players successfully.", addedPlayers.size())), - notFound -> { - /// Message sent if some players cannot be loaded while /uh loadplayers is used. 0 = amount of players missing; 1 = list of nicknames (format "nick1, nick2, nick3"). - sender.sendMessage(I.tn("{ce}{0} player is missing: {1}.", "{ce}{0} players are missing: {1}.", notFound.size(), notFound.size(), StringUtils.join(notFound, ", "))); - } - ); - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh loadplayers [pseudo] ... {ci}: loads the given players in the server so they can be added to teams even if they never logged in.")); - } - - @Override - public String getCategory() - { - return Category.MISC.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHResurrectCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHResurrectCommand.java deleted file mode 100644 index 2eaa039..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHResurrectCommand.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * This command resurrects a player. - * - * Usage: /uh resurrect - */ -@Command (name = "resurrect") -public class UHResurrectCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHResurrectCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length != 1) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - boolean success = p.getGameManager().resurrect(args[0]); - - Player player = p.getServer().getPlayer(args[0]); - if (player == null || !player.isOnline()) - { - if (!success) // Player does not exists or is nod dead. - { - sender.sendMessage(I.t("{ce}This player is not playing or dead!")); - } - else // Resurrected - { - sender.sendMessage(I.t("{cs}Because {0} is offline, he will be resurrected when he logins. If he was, he is no longer banned.", args[0])); - } - } - else - { - if (!success) // The player is not dead - { - /// Trying to resurrect an alive player - sender.sendMessage(I.t("{ce}{0} is not dead!", args[0])); - } - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - if (args.length == 1) - { - List suggestions = new ArrayList<>(); - - // TODO can be optimized - for (String playerName : p.getGameManager().getPlayers()) - { - OfflinePlayer player = p.getServer().getOfflinePlayer(playerName); - if (player != null && p.getGameManager().isPlayerDead(player.getUniqueId())) - { - suggestions.add(playerName); - } - } - - return CommandUtils.getAutocompleteSuggestions(args[0], suggestions); - } - - else return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh resurrect {ci}: resurrects a player.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHShiftCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHShiftCommand.java deleted file mode 100644 index d85cb81..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHShiftCommand.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; - -@Command (name = "shift") -public class UHShiftCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHShiftCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (p.getGameManager().isGameRunning()) - { - if (sender instanceof Player) - { - p.getGameManager().shiftEpisode(sender.getName()); - } - else - { - p.getGameManager().shiftEpisode(I.t("the console")); - } - } - else - { - sender.sendMessage(I.t("{ce}You can't shift the current episode because the game is not started.")); - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh shift {ci}: shifts an episode.")); - } - - @Override - public String getCategory() - { - return Category.GAME.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpawnsCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpawnsCommand.java deleted file mode 100644 index 0ec9db5..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpawnsCommand.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.spawns.UHSpawnsAddCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.spawns.UHSpawnsDumpCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.spawns.UHSpawnsGenerateCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.spawns.UHSpawnsListCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.spawns.UHSpawnsRemoveCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.spawns.UHSpawnsResetCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; - -@Command (name = "spawns") -public class UHSpawnsCommand extends AbstractCommand -{ - public UHSpawnsCommand(UHCReloaded plugin) - { - registerSubCommand(new UHSpawnsAddCommand(plugin)); - registerSubCommand(new UHSpawnsGenerateCommand(plugin)); - registerSubCommand(new UHSpawnsListCommand(plugin)); - registerSubCommand(new UHSpawnsDumpCommand(plugin)); - registerSubCommand(new UHSpawnsRemoveCommand(plugin)); - registerSubCommand(new UHSpawnsResetCommand(plugin)); - } - - /** - * This will be executed if this command is called without argument, - * or if there isn't any sub-command executor registered. - * - * @param sender The sender. - * @param args The arguments passed to the command. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NEED_DOC, this); - } - - /** - * The result of this method will be added to the tab-complete suggestions for this command. - * - * @param sender The sender. - * @param args The arguments. - * - * @return The suggestions to add. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return Collections.singletonList(I.t("{aqua}------ Spawns points commands ------")); - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh spawns {ci}: manages the spawn points. Execute /uh spawns for details.")); - } - - @Override - public String getCategory() - { - return Category.GAME.getTitle(); - } -} 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 deleted file mode 100644 index 1e5a72a..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.misc.OfflinePlayersLoader; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; - -/** - * This command manages startup spectators (aka ignored players). - * - * Usage: /uh spec (doc) - * Usage: /uh spec - */ -@Command (name = "spec") -public class UHSpectatorsCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHSpectatorsCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(final CommandSender sender, final String[] args) throws CannotExecuteCommandException - { - // /uh spec - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NEED_DOC, this); - } - - else - { - String subcommand = args[0]; - - if (subcommand.equalsIgnoreCase("add")) - { - // /uh spec add - if (args.length == 1) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - // /uh spec add - else - { - OfflinePlayersLoader.loadPlayer(args[1], player -> { - if (player == null) - { - sender.sendMessage(I.t("{ce}Unable to retrieve the player {0}.")); - - if (!Bukkit.getOnlineMode()) - sender.sendMessage(I.t("{ce}In offline mode, you cannot add players if they never came to this server.")); - - return; - } - - p.getGameManager().addStartupSpectator(player); - sender.sendMessage(I.t("{cs}The player {0} is now a spectator.", player.getName())); - }); - } - } - - else if (subcommand.equalsIgnoreCase("remove")) - { - // /uh spec remove - if (args.length == 1) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - // /uh spec remove - else - { - OfflinePlayer oldSpectator = OfflinePlayersLoader.getOfflinePlayer(args[1]); - if (oldSpectator == null) - { - sender.sendMessage(I.t("{ce}The player {0} was not found.", args[1])); - } - else - { - p.getGameManager().removeStartupSpectator(oldSpectator); - sender.sendMessage(I.t("{cs}The player {0} is now a player.", args[1])); - } - } - } - - else if (subcommand.equalsIgnoreCase("list")) - { - HashSet spectators = p.getGameManager().getStartupSpectators(); - if (spectators.size() == 0) - { - sender.sendMessage(I.t("{ce}There isn't any spectator to list.")); - } - else - { - sender.sendMessage(I.tn("{ci}{0} registered spectator.", "{ci}{0} registered spectators.", spectators.size())); - sender.sendMessage(I.t("{ci}This count includes only the initial spectators.")); - - for (String spectator : spectators) - { - /// A list item in the startup spectators list - sender.sendMessage(I.tc("startup_specs", "{lightpurple} - {0}", spectator)); - } - } - } - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - // Manual suggestions needed because we don't use sub-commands. - if (args.length == 1) - { - return CommandUtils.getAutocompleteSuggestions(args[0], Arrays.asList("add", "remove", "list")); - } - - // /... spec remove - else if (args.length == 2 && args[1].equalsIgnoreCase("remove")) - { - List suggestions = new ArrayList<>(); - - for (String spectatorName : p.getGameManager().getStartupSpectators()) - { - suggestions.add(spectatorName); - } - - return CommandUtils.getAutocompleteSuggestions(args[1], suggestions); - } - - else return null; - } - - @Override - public List help(CommandSender sender) - { - List help = new ArrayList<>(); - - help.add(I.t("{aqua}------ Startup spectators commands ------")); - - help.add(I.t("{cc}/uh spec add {ci}: adds a startup spectator.")); - help.add(I.t("{cc}/uh spec remove {ci}: removes a startup spectator.")); - help.add(I.t("{cc}/uh spec list{ci}: lists the startup spectators.")); - - return help; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh spec {ci}: manages the spectators. Execute /uh spec for details.")); - } - - @Override - public String getCategory() - { - return Category.GAME.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHStartCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHStartCommand.java deleted file mode 100644 index 80dc3a0..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHStartCommand.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * This command starts the game. - * - * Usage: /uh start [slow:true] [ignoreTeams:true] - */ -@Command (name = "start") -public class UHStartCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHStartCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 1 && args[0].equalsIgnoreCase("help")) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NEED_DOC, this); - } - else if (p.getGameManager().isSlowStartInProgress()) - { - p.getGameManager().finalizeStartSlow(sender); - return; - } - - final Map defaultTags = new HashMap<>(); - defaultTags.put("slow", "false"); - defaultTags.put("ignoreTeams", "false"); - - final Map tags = CommandUtils.getTagsInArgs(args, defaultTags); - - try - { - p.getGameManager().start(sender, UHUtils.stringToBoolean(tags.get("slow")), UHUtils.stringToBoolean(tags.get("ignoreTeams"))); - } - catch (IllegalStateException e) - { - sender.sendMessage(I.t("{ce}The game is already started! Reload or restart the server to restart the game.")); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - final List suggestions = new ArrayList<>(); - - suggestions.add("slow:true"); - suggestions.add("ignoreTeams:true"); - - if (args.length == 1) - suggestions.add("help"); - - return CommandUtils.getAutocompleteSuggestions(args[args.length - 1], suggestions); - } - - @Override - public List help(CommandSender sender) - { - return Arrays.asList( - I.t("{aqua}------ Beginning of the game ------"), - I.t("{cc}/uh start {ci}: starts the game. Period."), - I.t("{aqua}Startup options"), - I.t("{ci}You can add some tags to change the way the game is started, just append them to the command with spaces."), - I.t("{cc}slow:true {ci}: launches the game slowly, in two steps (teleportation then beginning of the game), for smaller servers."), - I.t("{cc}ignoreTeams:true {ci}: even with teams, teleports the players like in a solo game (only one player per spawn point, not a spawn point per team).") - ); - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh start {ci}: launches the game. See /uh start help for options (slow and ignoreTeams).")); - } - - @Override - public String getCategory() - { - return Category.GAME.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPBackCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPBackCommand.java deleted file mode 100644 index cc18f3c..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPBackCommand.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Location; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -@Command (name = "tpback") -public class UHTPBackCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTPBackCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length < 1) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - Player player = p.getServer().getPlayer(args[0]); - if (player == null || !player.isOnline()) - { - sender.sendMessage(I.t("{ce}The player {0} is not online.", args[0])); - return; - } - else if (!p.getGameManager().hasDeathLocation(player)) - { - sender.sendMessage(I.t("{ce}No death location available for the player {0}.", args[0])); - return; - } - - - Location deathLocation = p.getGameManager().getDeathLocation(player); - - if (args.length >= 2 && args[1].equalsIgnoreCase("force")) - { - UHUtils.safeTP(player, deathLocation, true); - sender.sendMessage(I.t("{cs}The player {0} was teleported back.", args[0])); - p.getGameManager().removeDeathLocation(player); - } - else if (UHUtils.safeTP(player, deathLocation)) - { - sender.sendMessage(I.t("{cs}The player {0} was teleported back.", args[0])); - p.getGameManager().removeDeathLocation(player); - } - else - { - sender.sendMessage(I.t("{ce}The player {0} was NOT teleported back because no safe spot was found.", args[0])); - sender.sendMessage(I.t("{ci}Use {cc}/uh tpback {0} force{ci} to teleport the player regardless this point.", args[0])); - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - if (args.length == 1) - { - List suggestions = new ArrayList<>(); - - for (Player player : p.getServer().getOnlinePlayers()) - { - if (p.getGameManager().hasDeathLocation(player)) - { - suggestions.add(player.getName()); - } - } - - return CommandUtils.getAutocompleteSuggestions(args[0], suggestions); - } - - else if (args.length == 2) - { - return CommandUtils.getAutocompleteSuggestions(args[1], Collections.singletonList("force")); - } - - else return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh tpback [force] {ci}: safely teleports back a player to his death location.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPCommand.java deleted file mode 100644 index cdfb4b6..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPCommand.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.command.BlockCommandSender; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerTeleportEvent; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * This command teleports a team or the spectators to a given location. - * - * Usage: /uh tp team - * Usage: /uh tp team - * Usage: /uh tp spectators - * Usage: /uh tp spectators - */ -@Command (name = "tp") -public class UHTPCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTPCommand(UHCReloaded plugin) - { - this.p = plugin; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - // No action provided: doc - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NEED_DOC, this); - } - - else - { - String subcommand = args[0]; - - World targetWorld; - if (sender instanceof Player) - { - targetWorld = ((Player) sender).getWorld(); - } - else if (sender instanceof BlockCommandSender) - { - targetWorld = ((BlockCommandSender) sender).getBlock().getWorld(); - } - else - { - targetWorld = p.getServer().getWorlds().get(0); - } - - if (subcommand.equalsIgnoreCase("team")) - { - boolean mayBeNaNError = false; - - // possibly /uh tp team - if (args.length >= 6) - { - String teamName = UHUtils.getStringFromCommandArguments(args, 4); - UHTeam team = p.getTeamManager().getTeam(teamName); - - // ok, the team exists. - if (team != null) - { - try - { - double x = Integer.parseInt(args[1]) + 0.5; - double y = Integer.parseInt(args[2]) + 0.5; - double z = Integer.parseInt(args[3]) + 0.5; - - team.teleportTo(new Location(targetWorld, x, y, z)); - - return; - } - catch (NumberFormatException e) - { - // It can be either another name for the team, starting by " the name" - // or a formatting error. - // The possibility of an error is saved. - mayBeNaNError = true; - } - } - } - - // /uh tp team - if (args.length >= 3) - { - String teamName = UHUtils.getStringFromCommandArguments(args, 2); - UHTeam team = p.getTeamManager().getTeam(teamName); - - if (team == null) - { - if (mayBeNaNError) - { - sender.sendMessage(I.t("{ce}The coordinates must be three valid numbers.")); - } - else - { - sender.sendMessage(I.t("{ce}This team is not registered.")); - } - } - else - { - Player target = p.getServer().getPlayer(args[1]); - - if (target == null) - { - sender.sendMessage(I.t("{ce}{0} is offline!", args[1])); - } - else - { - team.teleportTo(target.getLocation()); - } - } - } - } - - else if (subcommand.equalsIgnoreCase("spectators")) - { - // /uh tp spectators - if (args.length == 4) - { - try - { - double x = Integer.parseInt(args[1]) + 0.5; - double y = Integer.parseInt(args[2]) + 0.5; - double z = Integer.parseInt(args[3]) + 0.5; - - for (Player player : p.getServer().getOnlinePlayers()) - { - if (p.getGameManager().isPlayerDead(player)) - { - player.teleport(new Location(targetWorld, x, y, z), PlayerTeleportEvent.TeleportCause.PLUGIN); - } - } - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}The coordinates must be three valid numbers.")); - } - } - - // /uh tp spectators - else if (args.length == 2) - { - Player target = p.getServer().getPlayer(args[1]); - - if (target == null) - { - sender.sendMessage(I.t("{ce}{0} is offline!", args[1])); - } - else - { - for (Player player : p.getServer().getOnlinePlayers()) - { - if (p.getGameManager().isPlayerDead(player)) - { - player.teleport(target.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); - } - } - } - } - } - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - - if (args.length == 1) - { - return CommandUtils.getAutocompleteSuggestions( - args[0], - Arrays.asList("team", "spectators") - ); - } - - else if (args.length > 1 && args[0].equalsIgnoreCase("team")) - { - ArrayList teamNames = new ArrayList<>(); - for (UHTeam team : this.p.getTeamManager().getTeams()) - { - teamNames.add(team.getName()); - } - - // /uh tp team : autocompletion for team names – multiple words autocompletion - if (args.length >= 5) - { - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 4), teamNames, args.length - 5); - } - - // /uh tp team : autocompletion for team names – multiple words autocompletion - if (args.length >= 3) - { - try - { - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 2), teamNames, args.length - 3); - } - catch (IllegalArgumentException ignored) - { - // Temp workaround for an unknown bug. - } - } - } - - return null; - } - - @Override - public List help(CommandSender sender) - { - return Arrays.asList( - I.t("{aqua}------ Teleportation commands ------"), - I.t("{cc}/uh tp team | {ci}: teleports the team to the given location/target."), - I.t("{cc}/uh tp spectators | {ci}: teleports the spectators (aka non-alive players) to the given location/target.") - ); - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh tp {ci}: teleports the spectators or an entire team. See /uh tp for details.")); - } - - @Override - public String getCategory() - { - return Category.MISC.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPSpawnCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPSpawnCommand.java deleted file mode 100644 index 2341887..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPSpawnCommand.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Location; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -@Command (name = "tpspawn") -public class UHTPSpawnCommand extends AbstractCommand -{ - private final UHCReloaded p; - - public UHTPSpawnCommand(UHCReloaded plugin) - { - p = plugin; - } - - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - // Spawns not assigned - if (p.getGameManager().getTeleporter() == null) - { - sender.sendMessage(I.t("{ce}The spawn points are not already assigned to the player, because the game is not started.")); - return; - } - - - if (args.length < 1) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - Player player = p.getServer().getPlayer(args[0]); - if (player == null || !player.isOnline()) - { - sender.sendMessage(I.t("{ce}The player {0} is not online.", args[0])); - return; - } - - Location spawnLocation = p.getGameManager().getTeleporter().getSpawnForPlayer(player.getUniqueId()); - - if (spawnLocation == null) - { - sender.sendMessage(I.t("{ce}No spawn location available for the player {0}.", args[0])); - return; - } - - - if (args.length >= 2 && args[1].equalsIgnoreCase("force")) - { - p.getGameManager().getTeleporter().teleportPlayer(player.getUniqueId(), true); - sender.sendMessage(I.t("{cs}The player {0} was teleported to his spawn location.", args[0])); - } - else if (UHUtils.safeTP(player, spawnLocation)) - { - sender.sendMessage(I.t("{cs}The player {0} was teleported to his spawn location.", args[0])); - } - else - { - sender.sendMessage(I.t("{ce}The player {0} was NOT teleported to his spawn because no safe spot was found.", args[0])); - sender.sendMessage(I.t("{ci}Use {cc}/uh tpspawn {0} force{ci} to teleport the player regardless this point.", args[0])); - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - // Spawns not attributed - if (p.getGameManager().getTeleporter() == null) - return null; - - - if (args.length == 1) - { - List suggestions = new ArrayList<>(); - - for (Player player : p.getServer().getOnlinePlayers()) - { - if (p.getGameManager().getTeleporter().hasSpawnForPlayer(player.getUniqueId())) - { - suggestions.add(player.getName()); - } - } - - return CommandUtils.getAutocompleteSuggestions(args[0], suggestions); - } - - else if (args.length == 2) - { - return CommandUtils.getAutocompleteSuggestions(args[1], Collections.singletonList("force")); - } - - else return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh tpspawn [force] {ci}: safely teleports back a player to his spawn location.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTeamCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTeamCommand.java deleted file mode 100644 index 8ba51f0..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTeamCommand.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamAddCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamBannerCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamBannerResetCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamGUICommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamJoinCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamLeaveCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamListCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamRemoveCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamResetCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamSpyCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * This command is used to manage the teams. - * - * Usage: /uh team (for the doc). - * Usage: /uh team (see doc for details). - */ -@Command (name = "team") -public class UHTeamCommand extends AbstractCommand -{ - public UHTeamCommand(UHCReloaded plugin) - { - registerSubCommand(new UHTeamAddCommand(plugin)); - registerSubCommand(new UHTeamRemoveCommand(plugin)); - registerSubCommand(new UHTeamJoinCommand(plugin)); - registerSubCommand(new UHTeamLeaveCommand(plugin)); - registerSubCommand(new UHTeamBannerCommand()); - registerSubCommand(new UHTeamBannerResetCommand()); - registerSubCommand(new UHTeamListCommand(plugin)); - registerSubCommand(new UHTeamSpyCommand(plugin)); - registerSubCommand(new UHTeamResetCommand(plugin)); - registerSubCommand(new UHTeamGUICommand(plugin)); - } - - /** - * This will be executed if this command is called without argument, - * or if there isn't any sub-command executor registered. - * - * @param sender The sender. - * @param args The arguments passed to the command. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NEED_DOC, this); - } - - /** - * The result of this method will be added to the tab-complete suggestions for this command. - * - * @param sender The sender. - * @param args The arguments. - * - * @return The suggestions to add. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return Arrays.asList( - I.t("{aqua}------ Team commands ------"), - I.t("{cc}/join [player] {ci}: adds “player” (or the sender) inside the given team. Without arguments, displays the chat-based team selector."), - I.t("{cc}/leave [player] {ci}: removes “player” (or the sender) from his team.") - ); - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh team {ci}: manages the teams. Execute /uh team for details.")); - } - - @Override - public String getCategory() - { - return Category.GAME.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTimersCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTimersCommand.java deleted file mode 100644 index c137550..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTimersCommand.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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.commands.commands.uh; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.timers.UHTimersAddCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.timers.UHTimersDisplayCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.timers.UHTimersHideCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.timers.UHTimersListCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.timers.UHTimersPauseCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.timers.UHTimersRemoveCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.timers.UHTimersResumeCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.timers.UHTimersSetCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.timers.UHTimersStartCommand; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.timers.UHTimersStopCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; - -/** - * This command manages timers. - * - * Usage: /uh timers < add | set | display | hide | start | pause | resume | stop | remove | list > - */ -@Command (name = "timers") -public class UHTimersCommand extends AbstractCommand -{ - public UHTimersCommand(UHCReloaded plugin) - { - registerSubCommand(new UHTimersAddCommand(plugin)); - registerSubCommand(new UHTimersSetCommand(plugin)); - registerSubCommand(new UHTimersDisplayCommand(plugin)); - registerSubCommand(new UHTimersHideCommand(plugin)); - registerSubCommand(new UHTimersStartCommand(plugin)); - registerSubCommand(new UHTimersPauseCommand(plugin)); - registerSubCommand(new UHTimersResumeCommand(plugin)); - registerSubCommand(new UHTimersStopCommand(plugin)); - registerSubCommand(new UHTimersRemoveCommand(plugin)); - registerSubCommand(new UHTimersListCommand(plugin)); - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NEED_DOC, this); - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return Collections.singletonList(I.t("{aqua}------ Timers commands ------")); - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh timers {ci}: manages the timers. See /uh timers for details.")); - } - - @Override - public String getCategory() - { - return Category.MISC.getTitle(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderCheckCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderCheckCommand.java deleted file mode 100644 index 11feab9..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderCheckCommand.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.commands.commands.uh.border; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; - -@Command (name = "check") -public class UHBorderCheckCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHBorderCheckCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - // /uh border check - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - // /uh border check - else - { - try - { - p.getBorderManager().sendCheckMessage(sender, Integer.valueOf(args[0])); - - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}“{0}” is not a number...", args[0])); - } - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh border check {ci}: returns a list of the players outside the given border size.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderGetCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderGetCommand.java deleted file mode 100644 index 135df11..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderGetCommand.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.commands.commands.uh.border; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.borders.MapShape; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; - -@Command (name = "get") -public class UHBorderGetCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHBorderGetCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (p.getBorderManager().getMapShape() == MapShape.CIRCULAR) - { - sender.sendMessage(I.tn("{ci}The current diameter of the map is {0} block.", "{ci}The current diameter of the map is {0} blocks.", p.getBorderManager().getCurrentBorderDiameter())); - } - else - { - sender.sendMessage(I.t("{ci}The current map size is {0}×{0}.", p.getBorderManager().getCurrentBorderDiameter())); - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh border get{ci}: returns the current size of the map.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java deleted file mode 100644 index 38e4951..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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.commands.commands.uh.border; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.borders.MapShape; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; - -@Command (name = "set") -public class UHBorderSetCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHBorderSetCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - // /uh border set - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - // /uh border set - else if (args.length == 1) - { - try - { - final int newDiameter = Integer.valueOf(args[0]); - - // Some players are outside - if (p.getBorderManager().getPlayersOutside(newDiameter).size() != 0) - { - sender.sendMessage(I.t("{ce}Some players are outside the future border, so this operation was cancelled.")); - sender.sendMessage(I.t("{ci}Use {cc}/uh border set {0} force{ci} to resize the border regardless to this point.", args[0])); - - if (!p.getWorldBorderIntegration().isWBIntegrationEnabled()) - { - sender.sendMessage(I.t("{ce}WARNING: {ci}because WorldBorder is not installed, players out of the border will not be teleported!")); - } - - p.getBorderManager().sendCheckMessage(sender, newDiameter); - } - else - { - p.getBorderManager().setCurrentBorderDiameter(newDiameter); - - if (p.getBorderManager().getMapShape() == MapShape.CIRCULAR) - { - p.getServer().broadcastMessage(I.tn("{lightpurple}The diameter of the map is now {0} block.", "{lightpurple}The diameter of the map is now {0} blocks.", newDiameter)); - } - else - { - p.getServer().broadcastMessage(I.t("{lightpurple}The size of the map is now {0}×{0}.", newDiameter)); - } - } - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}“{0}” is not a number...", args[0])); - } - } - - // /uh border set force - else if (args.length == 2 && args[1].equalsIgnoreCase("force")) - { - try - { - Integer newDiameter = Integer.valueOf(args[0]); - - p.getBorderManager().setCurrentBorderDiameter(newDiameter); - - if (p.getBorderManager().getMapShape() == MapShape.CIRCULAR) - { - p.getServer().broadcastMessage(I.tn("{lightpurple}The diameter of the map is now {0} block.", "{lightpurple}The diameter of the map is now {0} blocks.", newDiameter)); - } - else - { - p.getServer().broadcastMessage(I.t("{lightpurple}The size of the map is now {0}×{0}.", newDiameter)); - } - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}“{0}” is not a number...", args[0])); - } - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - if (args.length == 2) - { - return CommandUtils.getAutocompleteSuggestions(args[1], Collections.singletonList("force")); - } - - else return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh border set [force]{ci}: changes the size of the map. If force is not given, the operation will be canceled if there is a player outside the border.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderWarningCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderWarningCommand.java deleted file mode 100644 index 1e57c3c..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderWarningCommand.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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.commands.commands.uh.border; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - - -@Command (name = "warning") -public class UHBorderWarningCommand extends AbstractCommand -{ - private final Integer WARNING_INTERVAL; - - private final UHCReloaded p; - - - public UHBorderWarningCommand(UHCReloaded p) - { - this.p = p; - - WARNING_INTERVAL = UHConfig.MAP.BORDER.WARNING_INTERVAL.get(); - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0) - { // /uh border warning - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - else if (args[0].equalsIgnoreCase("cancel")) - { // /uh border warning cancel - p.getBorderManager().cancelWarning(); - sender.sendMessage(I.t("{cs}Warning canceled.")); - } - else - { // /uh border warning - try - { - int warnDiameter = Integer.parseInt(args[0]); - int warnTime = 0; - - // /uh border warning - if (args.length >= 4) - { - warnTime = Integer.parseInt(args[1]); - } - - p.getBorderManager().setWarningSize(warnDiameter, warnTime, sender); - sender.sendMessage(I.tn("{cs}Future size saved. All players outside this future border will be warned every {0} second.", "{cs}Future size saved. All players outside this future border will be warned every {0} seconds.", WARNING_INTERVAL)); - - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}“{0}” is not a number...", args[0])); - } - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - if (args.length == 1) - { - return CommandUtils.getAutocompleteSuggestions(args[0], Collections.singletonList("cancel")); - } - - else return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Arrays.asList(I.t("{cc}/uh border warning [minutesBeforeReduction]{ci}: warns all players outside the given future diameter. It's just a notice, nothing else."), I.t("{cc}/uh border warning cancel{ci}: cancels a previously-set warning.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsAddCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsAddCommand.java deleted file mode 100644 index 95ae84f..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsAddCommand.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * 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.commands.commands.uh.spawns; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.World; -import org.bukkit.command.BlockCommandSender; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; - - -@Command (name = "add") -public class UHSpawnsAddCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHSpawnsAddCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - // World? - World world; - if (sender instanceof Player) - { - world = ((Player) sender).getWorld(); - } - else if (sender instanceof BlockCommandSender) - { - world = ((BlockCommandSender) sender).getBlock().getWorld(); - } - else - { - world = p.getServer().getWorlds().get(0); - } - - // /uh spawns add - if (args.length == 0) - { - if (!(sender instanceof Player)) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.ONLY_AS_A_PLAYER); - } - else - { - Player pl = (Player) sender; // Just a way to avoid casts everywhere. - try - { - p.getSpawnsManager().addSpawnPoint(pl.getLocation()); - sender.sendMessage(I.t("{cs}Spawn added in the world {0}: {1};{2}", world.getName(), String.valueOf(pl.getLocation().getBlockX()), String.valueOf(pl.getLocation().getBlockZ()))); - } - catch (IllegalArgumentException e) - { - sender.sendMessage(I.t("{ce}You cannot add a spawn point out of the borders.")); - } - catch (RuntimeException e) - { - sender.sendMessage(I.t("{ce}Unable to add this spawn point: no safe spot found in the Nether.")); - } - } - } - - // /uh spawns add : Two coordinates needed! - else if (args.length == 1) - { - sender.sendMessage(I.t("{ce}You need to specify two coordinates.")); - } - - // /uh spawns add - else - { - try - { - p.getSpawnsManager().addSpawnPoint(world, Double.parseDouble(args[0]), Double.parseDouble(args[1])); - sender.sendMessage(I.t("{cs}Spawn added in the world {0}: {1};{2}", world.getName(), args[0], args[1])); - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}This is not a number!")); - } - catch (IllegalArgumentException e) - { - sender.sendMessage(I.t("{ce}You cannot add a spawn point out of the borders.")); - } - catch (RuntimeException e) - { - sender.sendMessage(I.t("{ce}Unable to add this spawn point: no safe spot found in the Nether.")); - } - } - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh spawns add {ci}: adds a spawn point for a team or a player, at the current location of the sender or at the provided coordinates.")); - } - - @Override - public List onListHelp(CommandSender sender) - { - return null; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsDumpCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsDumpCommand.java deleted file mode 100644 index 0c77ad7..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsDumpCommand.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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.commands.commands.uh.spawns; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - - -@Command (name = "dump") -public class UHSpawnsDumpCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHSpawnsDumpCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - // We want one list per world - Map> spanwsInWorlds = new HashMap>(); - for (World world : p.getServer().getWorlds()) - { - spanwsInWorlds.put(world, new LinkedList<>()); - } - - for (Location spawn : p.getSpawnsManager().getSpawnPoints()) - { - spanwsInWorlds.get(spawn.getWorld()).add(spawn); - } - - StringBuilder dump = new StringBuilder(); - - for (Map.Entry> spanwsInWorld : spanwsInWorlds.entrySet()) - { - if (spanwsInWorld.getValue().size() == 0) - { - continue; - } - - dump.append("\n* ").append(spanwsInWorld.getKey().getName()).append("\n"); - - for (Location spawn : spanwsInWorld.getValue()) - { - dump.append(spawn.getBlockX()).append(",").append(spawn.getBlockZ()).append("\n"); - } - } - - sender.sendMessage(dump.toString()); - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh spawns dump {ci}: displays the registered spawn points in an exportable format. {gray}Use this to plot the spawn points, as example.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java deleted file mode 100644 index a48807d..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * 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.commands.commands.uh.spawns; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.spawns.Generator; -import eu.carrade.amaury.UHCReloaded.spawns.exceptions.CannotGenerateSpawnPointsException; -import eu.carrade.amaury.UHCReloaded.spawns.exceptions.UnknownGeneratorException; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.World; -import org.bukkit.command.BlockCommandSender; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - - -@Command (name = "generate") -public class UHSpawnsGenerateCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHSpawnsGenerateCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - - if (args.length == 0) - { // Help - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NEED_DOC, this); - } - - String generationMethod = args[0]; - - // Default values - int size = p.getBorderManager().getCurrentBorderDiameter() - 25; // Avoid spawn points being too close to the border - int distanceMinBetweenTwoPoints = 250; - World world = p.getServer().getWorlds().get(0); - double xCenter = world.getSpawnLocation().getX(); - double zCenter = world.getSpawnLocation().getZ(); - - int spawnsCount = 0; - for (final UHTeam team : p.getTeamManager().getTeams()) - { - if (!team.isEmpty()) spawnsCount++; - } - - if (args.length < 7) - { - if (sender instanceof Player) - { - world = ((Player) sender).getWorld(); - } - else if (sender instanceof BlockCommandSender) - { - world = ((BlockCommandSender) sender).getBlock().getWorld(); - } - - xCenter = world.getSpawnLocation().getX(); - zCenter = world.getSpawnLocation().getZ(); - } - - // What if the game is in solo, or some players are out of all team? - // Only if the spawn count is not provided of course. Else, we don't care, this count - // will be overwritten. - if (args.length < 5) - { - if (spawnsCount == 0) - { // Solo mode? - sender.sendMessage(I.t("{ci}No team found: assuming the game is a solo game.")); - spawnsCount = p.getServer().getOnlinePlayers().size() - p.getGameManager().getStartupSpectators().size(); - } - else - { - // Trying to find players without team - int playersWithoutTeam = 0; - for (Player player : p.getServer().getOnlinePlayers()) - { - if (p.getTeamManager().getTeamForPlayer(player) == null) - { - playersWithoutTeam++; - } - } - - if (playersWithoutTeam != 0) - { - sender.sendMessage(I.t("{ci}Some players are not in a team; their number was added to the spawn count.")); - spawnsCount += playersWithoutTeam; - } - } - } - - try - { - if (args.length >= 2) - { // size included - size = Integer.parseInt(args[1]); - - if (args.length >= 3) - { // distance minimal included - distanceMinBetweenTwoPoints = Integer.parseInt(args[2]); - - if (args.length >= 4) - { // spawn count included - spawnsCount = Integer.parseInt(args[3]); - - if (args.length >= 5) - { // xCenter included - xCenter = Double.parseDouble(args[4]); - - if (args.length >= 6) - { // zCenter included - zCenter = Double.parseDouble(args[5]); - - if (args.length >= 7) - { // world included - World inputWorld = p.getServer().getWorld(args[6]); - - if (inputWorld != null) - { - world = inputWorld; - } - else - { - sender.sendMessage(I.t("{ce}The world {0} doesn't exists.", args[6])); - return; - } - } - } - } - } - } - } - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}This is not a number!")); - return; - } - - - if (spawnsCount <= 0) - { - sender.sendMessage(I.t("{ci}You asked for a void generation. Thus, the generation is empty.")); - return; - } - - - try - { - p.getSpawnsManager().generateSpawnPoints(generationMethod, world, spawnsCount, size, distanceMinBetweenTwoPoints, xCenter, zCenter); - - } - catch (UnknownGeneratorException e) - { - sender.sendMessage(I.t("{ce}The generation method “{0}” is not (yet?) supported.", generationMethod)); - return; - - } - catch (CannotGenerateSpawnPointsException e) - { - sender.sendMessage(I.t("{ce}You asked for the impossible: there are too many spawn points on a too small surface. Decrease the spawn count or the minimal distance between two points.")); - return; - } - - sender.sendMessage(I.t("{cs}Successfully generated the asked spawn points.")); - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - // Generation methods - /uh spawns generate - if (args.length == 1) - return CommandUtils.getAutocompleteSuggestions( - args[0], - Arrays.stream(Generator.values()) - .map(generator -> generator.name().toLowerCase()) - .collect(Collectors.toList()) - ); - - // Worlds - /uh spawns generate - - - - - - - else if (args.length == 7) - return CommandUtils.getAutocompleteSuggestions(args[6], p.getServer().getWorlds().stream().map(World::getName).collect(Collectors.toList())); - - else return null; - } - - /** - * Returns the help of this command. - *

- *

- * The first line should describe briefly the command, as this line is displayed as - * a line of the help of the parent command. - *

- *

- * The other lines will only be displayed if the {@link eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException} - * is caught by the command executor. - *

- * - * @param sender The sender. - * - * @return The help. One line per entry in the list. - */ - @Override - public List help(CommandSender sender) - { - return Arrays.asList( - I.t("{aqua}Command"), - I.t("{cc}/uh spawns generate [size] [distanceMin] [count] [xCenter] [zCenter] [world]"), - I.t("{aqua}Shapes"), - I.t(" - {cc}random{ci}: generates random spawn points on the map, with a minimal distance between them."), - I.t(" - {cc}grid{ci}: generates the spawn points on concentric squares, with a constant distance between two generated points."), - I.t(" - {cc}circular{ci}: generates the spawn points on concentric circles, with a minimal distance between two generated points. In each circle, the angle (and the distance) between two spawn points is constant."), - I.t("{aqua}Arguments"), - I.t(" - {cc}size{ci}: the size of the region where the spawn points will be generated. Squared or circular, following the shape of the map. Default: map' size."), - I.t(" - {cc}distanceMin{ci}: the minimal distance between two spawn points. Default: 250 blocks."), - I.t(" - {cc}count{ci}: the number of spawn points to generate. Default: the number of players or teams."), - I.t(" - {cc}xCenter{ci}, {cc}zCenter{ci}: the center of the region where the points are generated. Default: world' spawn point."), - I.t(" - {cc}world{ci}: the world where the spawn points will be generated.") - ); - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh spawns generate {ci}: automagically generates spawn points. See /uh spawns generate for details.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsListCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsListCommand.java deleted file mode 100644 index 25718e5..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsListCommand.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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.commands.commands.uh.spawns; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - - -@Command (name = "list") -public class UHSpawnsListCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHSpawnsListCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - List spawnPoints = p.getSpawnsManager().getSpawnPoints(); - - if (spawnPoints.size() == 0) - { - sender.sendMessage(I.t("{ce}There isn't any registered spawn point.")); - } - else - { - sender.sendMessage(I.t("{ci}There are {0} registered spawn points.", String.valueOf(spawnPoints.size()))); - - // We want one list per world - Map> spanwsInWorlds = new HashMap>(); - for (World world : p.getServer().getWorlds()) - { - spanwsInWorlds.put(world, new LinkedList()); - } - - for (Location spawn : spawnPoints) - { - spanwsInWorlds.get(spawn.getWorld()).add(spawn); - } - - for (Map.Entry> spanwsInWorld : spanwsInWorlds.entrySet()) - { - if (spanwsInWorld.getValue().size() == 0) - { - continue; - } - - sender.sendMessage(I.t("{lightpurple}World {0}", spanwsInWorld.getKey().getName())); - - - // Displaying this number of spawn points per line - final int spawnsPerLine = 5; - - for (int j = 0; j < Math.ceil((double) spanwsInWorld.getValue().size() / spawnsPerLine); j++) - { - StringBuilder line = new StringBuilder(); - - for (int k = 0; k < spawnsPerLine; k++) - { - if (spawnPoints.size() > j * spawnsPerLine + k) - { - line.append( - getSpawnItem( - spanwsInWorld.getValue().get(j * spawnsPerLine + k).getBlockX(), - spanwsInWorld.getValue().get(j * spawnsPerLine + k).getBlockZ(), - spanwsInWorld.getKey().getEnvironment() - ) - ).append(" "); - } - } - - sender.sendMessage(line.toString()); - } - } - } - } - - private String getSpawnItem(int x, int z, World.Environment environment) - { - switch (environment) - { - case NORMAL: - /// A spawn point in the /uh spawns list command (in the overworld) - return I.t("{green}{0}{darkgreen};{green}{1}", x, z); - - case NETHER: - /// A spawn point in the /uh spawns list command (in the Nether) - return I.t("{red}{0}{darkred};{red}{1}", x, z); - - case THE_END: - /// A spawn point in the /uh spawns list command (in the End) - return I.t("{yellow}{0}{gold};{yellow}{1}", x, z); - - default: - /// A spawn point in the /uh spawns list command (in a custom world) - return I.t("{gray}{0}{darkgray};{gray}{1}", x, z); - } - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - /** - * Returns the help of this command. - *

- *

- * The first line should describe briefly the command, as this line is displayed as - * a line of the help of the parent command. - *

- *

- * The other lines will only be displayed if the {@link eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException} - * is caught by the command executor. - *

- * - * @param sender The sender. - * - * @return The help. One line per entry in the list. - */ - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh spawns list {ci}: lists the registered spawn points.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsRemoveCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsRemoveCommand.java deleted file mode 100644 index 0772056..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsRemoveCommand.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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.commands.commands.uh.spawns; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; - - -@Command (name = "remove") -public class UHSpawnsRemoveCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHSpawnsRemoveCommand(UHCReloaded plugin) - { - p = plugin; - } - - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0) - { // /uh spawns remove - if (!(sender instanceof Player)) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.ONLY_AS_A_PLAYER); - } - else - { - Player pl = (Player) sender; // Just a way to avoid casts everywhere. - p.getSpawnsManager().removeSpawnPoint(pl.getLocation(), false); - sender.sendMessage(I.t("{cs}The spawn point {1};{2} in the world {0} was removed.", pl.getWorld().getName(), String.valueOf(pl.getLocation().getBlockX()), String.valueOf(pl.getLocation().getBlockZ()))); - } - } - else if (args.length == 1) - { // /uh spawns add : Two coordinates needed! - sender.sendMessage(I.t("{ce}You need to specify two coordinates.")); - } - else - { // /uh spawns remove - try - { - World world; - if (sender instanceof Player) - { - world = ((Player) sender).getWorld(); - } - else - { - world = p.getServer().getWorlds().get(0); - } - - p.getSpawnsManager().removeSpawnPoint(new Location(world, Double.parseDouble(args[2]), 0, Double.parseDouble(args[3])), true); - sender.sendMessage(I.t("{cs}The spawn point {1};{2} in the world {0} was removed.", p.getServer().getWorlds().get(0).getName(), args[2], args[3])); - } - catch (NumberFormatException e) - { - sender.sendMessage(I.t("{ce}This is not a number!")); - } - } - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh spawns remove [ ] {ci}: removes the spawn points at the specified coordinates, or at the current location if the sender without coordinates.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsResetCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsResetCommand.java deleted file mode 100644 index f093f0f..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsResetCommand.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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.commands.commands.uh.spawns; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; - - -@Command (name = "reset") -public class UHSpawnsResetCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHSpawnsResetCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - p.getSpawnsManager().reset(); - sender.sendMessage(I.t("{cs}All the spawn points were removed.")); - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh spawns reset {ci}: removes all registered spawn points.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamAddCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamAddCommand.java deleted file mode 100644 index 7be11b5..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamAddCommand.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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.commands.commands.uh.team; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.teams.TeamColor; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - - -@Command (name = "add") -public class UHTeamAddCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTeamAddCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - // /uh team add - if (args.length == 1) - { - - TeamColor color = TeamColor.fromString(args[0]); - UHTeam team; - - if (color == null) - { - sender.sendMessage(I.t("{ce}Unable to add the team, check the color name. Tip: use Tab to autocomplete.")); - } - else - { - try - { - team = p.getTeamManager().addTeam(color); - } - catch (IllegalArgumentException e) - { - sender.sendMessage(I.t("{ce}This team already exists.")); - return; - } - - sender.sendMessage(I.t("{cs}Team {0}{cs} added.", team.getDisplayName())); - } - - } - else if (args.length >= 2) - { // /uh team add - - TeamColor color = TeamColor.fromString(args[0]); - UHTeam team; - - if (color == null) - { - sender.sendMessage(I.t("{ce}Unable to add the team, check the color name. Tip: use Tab to autocomplete.")); - } - else - { - String name = UHUtils.getStringFromCommandArguments(args, 1); - - try - { - team = p.getTeamManager().addTeam(color, name); - } - catch (IllegalArgumentException e) - { - sender.sendMessage(I.t("{ce}This team already exists.")); - return; - } - - sender.sendMessage(I.t("{cs}Team {0}{cs} added.", team.getDisplayName())); - } - - } - else - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - if (args.length == 1) - { - List colors = Arrays.asList("aqua", "black", "blue", "darkaqua", - "darkblue", "darkgray", "darkgreen", "darkpurple", "darkred", - "gold", "gray", "green", "lightpurple", "red", "white", "yellow", "?"); - - return CommandUtils.getAutocompleteSuggestions(args[0], colors); - } - - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh team add [] {ci}: adds a team with the provided color.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerCommand.java deleted file mode 100644 index 1a1e146..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerCommand.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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.commands.commands.uh.team; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Material; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -@Command (name = "banner") -public class UHTeamBannerCommand extends AbstractCommand -{ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (!(sender instanceof Player)) - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.ONLY_AS_A_PLAYER, this); - - final UHTeam team; - - if (args.length >= 1) - { - String name = UHUtils.getStringFromCommandArguments(args, 0); - team = UHCReloaded.get().getTeamManager().getTeam(name); - } - else - { - team = UHCReloaded.get().getTeamManager().getTeamForPlayer((Player) sender); - } - - if (team == null) - { - sender.sendMessage(I.t("{ce}Either this team does not exists, or you are not in a team.")); - } - else if (((Player) sender).getItemInHand().getType() != Material.BANNER) - { - sender.sendMessage(I.t("{ce}You must run this command with a banner in your main hand.")); - } - else - { - team.setBanner(((Player) sender).getItemInHand()); - sender.sendMessage(I.t("{cs}The banner of the team {0}{cs} was successfully updated.", team.getDisplayName())); - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - ArrayList teamNames = new ArrayList<>(); - - for (UHTeam team : UHCReloaded.get().getTeamManager().getTeams()) - { - teamNames.add(team.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 0), teamNames, args.length - 1); - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh team banner [team name ...] {ci}: updates the team's banner using the banner in the sender hand. If the team name is not provided, uses the sender's team.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerResetCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerResetCommand.java deleted file mode 100644 index c203289..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerResetCommand.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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.commands.commands.uh.team; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import org.bukkit.inventory.ItemStack; - - -@Command (name = "bannerreset") -public class UHTeamBannerResetCommand extends AbstractCommand -{ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - UHTeam team = null; - - if (args.length >= 1) - { - String name = UHUtils.getStringFromCommandArguments(args, 0); - team = UHCReloaded.get().getTeamManager().getTeam(name); - } - else if (sender instanceof Player) - { - team = UHCReloaded.get().getTeamManager().getTeamForPlayer((Player) sender); - } - else - { - /// Error message of /uh team bannerreset from the console without name - sender.sendMessage(I.t("{ce}From the console, you must provide a team name.")); - } - - - if (team == null) - { - sender.sendMessage(I.t("{ce}Either this team does not exists, or you are not in a team.")); - } - else - { - team.setBanner((ItemStack) null); - sender.sendMessage(I.t("{cs}The banner of the team {0}{cs} was successfully reset to the default one.", team.getDisplayName())); - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - ArrayList teamNames = new ArrayList<>(); - - for (UHTeam team : UHCReloaded.get().getTeamManager().getTeams()) - { - teamNames.add(team.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 0), teamNames, args.length - 1); - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh team bannerreset [team name ...] {ci}: resets the banner of the team to the default. If the team name is not provided, uses the sender's team.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamJoinCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamJoinCommand.java deleted file mode 100644 index 5b21b29..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamJoinCommand.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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.commands.commands.uh.team; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.misc.OfflinePlayersLoader; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -/** - * This class is used for both /uh team join and /join commands. - * - * @see {@link eu.carrade.amaury.UHCReloaded.commands.commands.JoinCommand}. - */ -@Command (name = "join") -public class UHTeamJoinCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTeamJoinCommand(UHCReloaded plugin) - { - p = plugin; - } - - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(final CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0) - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - - UHTeam team; - - String targetName = ""; - Boolean self = null; - - // /... join ? - team = p.getTeamManager().getTeam(UHUtils.getStringFromCommandArguments(args, 0)); - if (team != null) - { - if (sender instanceof Player) - { - targetName = sender.getName(); - self = true; - } - else - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.ONLY_AS_A_PLAYER); - } - } - - // /... join ? - else if (args.length >= 2) - { - team = p.getTeamManager().getTeam(UHUtils.getStringFromCommandArguments(args, 1)); - if (team != null) - { - targetName = args[0]; - self = false; - } - } - - if (team == null) - { - sender.sendMessage(I.t("{ce}This team does not exists.")); - } - else if (sender.hasPermission("uh.team.join") - || (self && sender.hasPermission("uh.player.join.self")) - || (!self && sender.hasPermission("uh.player.join.others"))) - { - final UHTeam finalTeam = team; - OfflinePlayersLoader.loadPlayer(targetName, player -> { - if (player == null) - { - sender.sendMessage(I.t("{ce}Unable to retrieve the player {0}.")); - - if (!Bukkit.getOnlineMode()) - sender.sendMessage(I.t("{ce}In offline mode, you cannot add players if they never came to this server.")); - - return; - } - - finalTeam.addPlayer(player); - - if (!sender.equals(player)) - { - sender.sendMessage(I.t("{cs}The player {0} was successfully added to the team {1}", player.getName(), finalTeam.getName())); - } - }); - } - else - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NOT_ALLOWED, this); - } - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - - if (args.length >= 2) - { - ArrayList teamNames = new ArrayList<>(); - - for (UHTeam team : this.p.getTeamManager().getTeams()) - { - teamNames.add(team.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 1), teamNames, args.length - 2); - } - - else return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh team join {ci}: adds a player inside the given team. The name of the team is it color, or the explicit name given.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamLeaveCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamLeaveCommand.java deleted file mode 100644 index 2e32eef..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamLeaveCommand.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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.commands.commands.uh.team; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.misc.OfflinePlayersLoader; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; - - -@Command (name = "leave") -public class UHTeamLeaveCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTeamLeaveCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - final OfflinePlayer target; - - if (args.length == 0) - { - if (sender instanceof Player) - { - target = (OfflinePlayer) sender; - } - else - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.ONLY_AS_A_PLAYER); - } - } - - // /uh team leave - else - { - target = OfflinePlayersLoader.getOfflinePlayer(args[0]); - } - - - if (target == null) - { - sender.sendMessage(I.t("{ce}The player {0} is disconnected and never logged in before!", args[0])); // args.length >= 1 here. - } - - else - { - - // Permissions check - if (sender.hasPermission("uh.team.leave") - || (target.equals(sender) && sender.hasPermission("uh.player.leave.self")) - || (!target.equals(sender) && sender.hasPermission("uh.player.leave.others"))) - { - - - p.getTeamManager().removePlayerFromTeam(target); - - if (!target.equals(sender)) - { - sender.sendMessage(I.t("{cs}The player {0} was successfully removed from his team.", target.getName())); - } - - } - else - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NOT_ALLOWED); - } - } - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh team leave {ci}: removes a player from his team.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamListCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamListCommand.java deleted file mode 100644 index 844508e..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamListCommand.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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.commands.commands.uh.team; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; - - -@Command (name = "list") -public class UHTeamListCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTeamListCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (p.getTeamManager().getTeams().size() == 0) - { - sender.sendMessage(I.t("{ce}There isn't any team to show.")); - return; - } - - for (final UHTeam team : p.getTeamManager().getTeams()) - { - sender.sendMessage(I.tn("{0} ({1} player)", "{0} ({1} players)", team.getSize(), team.getDisplayName(), team.getSize())); - for (final OfflinePlayer player : team.getPlayers()) - { - String bullet; - if (player.isOnline()) - { - /// Online dot in /uh team list - bullet = I.t("{green} • "); - } - else - { - /// Offline dot in /uh team list - bullet = I.t("{red} • "); - } - - /// Player name after the online status dot in /uh teams list - sender.sendMessage(bullet + I.tc("teams_list", "{0}", player.getName())); - } - } - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh team list {ci}: lists the teams and their players.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamRemoveCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamRemoveCommand.java deleted file mode 100644 index 6f53cb9..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamRemoveCommand.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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.commands.commands.uh.team; - - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -@Command (name = "remove") -public class UHTeamRemoveCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTeamRemoveCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length >= 1) - { // /uh team remove - String name = UHUtils.getStringFromCommandArguments(args, 0); - if (!p.getTeamManager().removeTeam(name)) - { - sender.sendMessage(I.t("{ce}This team does not exists.")); - } - else - { - sender.sendMessage(I.t("{cs}Team {0} deleted.", name)); - } - } - else - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - ArrayList teamNames = new ArrayList<>(); - - for (UHTeam team : this.p.getTeamManager().getTeams()) - { - teamNames.add(team.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 0), teamNames, args.length - 1); - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh team remove {ci}: removes a team")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamResetCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamResetCommand.java deleted file mode 100644 index fbc1d7d..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamResetCommand.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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.commands.commands.uh.team; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; - - -@Command (name = "reset") -public class UHTeamResetCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTeamResetCommand(UHCReloaded plugin) - { - p = plugin; - } - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - p.getTeamManager().reset(); - sender.sendMessage(I.t("{cs}All teams where removed.")); - } - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh team reset {ci}: removes all teams.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamSpyCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamSpyCommand.java deleted file mode 100644 index fc18e0b..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamSpyCommand.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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.commands.commands.uh.team; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.List; - - -@Command (name = "spy") -public class UHTeamSpyCommand extends AbstractCommand -{ - private final UHCReloaded p; - - public UHTeamSpyCommand(UHCReloaded plugin) - { - p = plugin; - } - - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - Player target; - - if (args.length >= 1) - { - if (sender.hasPermission("uh.team.spy.others")) - { - target = Bukkit.getPlayer(args[0]); - if (target == null) - { - sender.sendMessage(I.t("{ce}Cannot toggle the spy mode of {0} because he/she is offline.", args[0])); - return; - } - } - else - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NOT_ALLOWED, this); - } - } - else - { - if (!(sender instanceof Player)) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.ONLY_AS_A_PLAYER, this); - } - - target = (Player) sender; - } - - - String message; - - if (p.getTeamChatManager().isGlobalSpy(target.getUniqueId())) - { - p.getTeamChatManager().removeGlobalSpy(target.getUniqueId()); - message = I.t("{cs}Spy mode {darkred}disabled{cs} for {0}.", target.getName()); - } - else - { - p.getTeamChatManager().addGlobalSpy(target.getUniqueId()); - message = I.t("{cs}Spy mode {darkgreen}enabled{cs} for {0}.", target.getName()); - } - - target.sendMessage(message); - if (!sender.equals(target)) - sender.sendMessage(message); - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh team spy [player] {ci}: allows yourself (or the target player) to receive all the team chats (read-only). Execute again to stop.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersAddCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersAddCommand.java deleted file mode 100644 index 20e4c6d..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersAddCommand.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.commands.commands.uh.timers; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; - - -/** - * Usage: /uh timers add - */ -@Command (name = "add") -public class UHTimersAddCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTimersAddCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - - if (args.length < 2) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - else - { - try - { - Integer duration = UHUtils.string2Time(args[0]); - String timerName = UHUtils.getStringFromCommandArguments(args, 1); - - if (p.getTimerManager().getTimer(timerName) != null) - { - sender.sendMessage(I.t("{ce}A timer called {0}{ce} already exists; please choose another name.", timerName)); - return; - } - - UHTimer timer = new UHTimer(timerName); - timer.setDuration(duration); - - p.getTimerManager().registerTimer(timer); - sender.sendMessage(I.t("{cs}The timer {0}{cs} (duration {1}) has been registered.", timer.getDisplayName(), args[0])); - - } - catch (IllegalArgumentException e) - { - sender.sendMessage(I.t("{ce}The duration' syntax is invalid; accepted formats are mm, mm:ss or hh:mm:ss.")); - } - } - } - - @Override - public List tabComplete(CommandSender sender, String[] args) - { - return null; - } - - @Override - public List help(CommandSender sender) - { - return null; - } - - @Override - public List onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh timers add {ci}: adds a timer.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersDisplayCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersDisplayCommand.java deleted file mode 100644 index 27f7a4f..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersDisplayCommand.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.commands.commands.uh.timers; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -@Command (name = "display") -public class UHTimersDisplayCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTimersDisplayCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - String timerName = UHUtils.getStringFromCommandArguments(args, 0); - UHTimer timer = p.getTimerManager().getTimer(timerName); - - if (timer == null) - { - sender.sendMessage(I.t("{ce}This timer is not registered.")); - return; - } - - sender.sendMessage(I.t("{cs}The timer {0}{cs} is now displayed.", timer.getDisplayName())); - } - - @Override - public List<String> tabComplete(CommandSender sender, String[] args) - { - List<String> suggestions = new ArrayList<>(); - - for (UHTimer timer : p.getTimerManager().getTimers()) - { - suggestions.add(timer.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 0), suggestions, args.length - 1); - } - - @Override - public List<String> help(CommandSender sender) - { - return null; - } - - @Override - public List<String> onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh timers display <title ...> {ci}: displays a timer in the scoreboard. Automatic when a timer is started.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersHideCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersHideCommand.java deleted file mode 100644 index b047eb5..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersHideCommand.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.commands.commands.uh.timers; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -@Command (name = "hide") -public class UHTimersHideCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTimersHideCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - String timerName = UHUtils.getStringFromCommandArguments(args, 0); - - UHTimer timer = p.getTimerManager().getTimer(timerName); - if (timer == null) - { - sender.sendMessage(I.t("{ce}This timer is not registered.")); - return; - } - - sender.sendMessage(I.t("{cs}The timer {0}{cs} is now hidden.", timer.getDisplayName())); - } - - @Override - public List<String> tabComplete(CommandSender sender, String[] args) - { - List<String> suggestions = new ArrayList<>(); - - for (UHTimer timer : p.getTimerManager().getTimers()) - { - suggestions.add(timer.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 0), suggestions, args.length - 1); - } - - @Override - public List<String> help(CommandSender sender) - { - return null; - } - - @Override - public List<String> onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh timers hide <title ...> {ci}: removes a timer from the scoreboard. Don't stops the timer.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersListCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersListCommand.java deleted file mode 100644 index 331c1ab..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersListCommand.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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.commands.commands.uh.timers; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - - -@Command (name = "list") -public class UHTimersListCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTimersListCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - Collection<UHTimer> timers = p.getTimerManager().getTimers(); - - sender.sendMessage(I.tn("{ci}{0} timer is registered.", "{ci}{0} timers are registered.", timers.size())); - - for (UHTimer timer : timers) - { - if (timer.isRunning()) - { - if (timer.isPaused()) - { - sender.sendMessage(I.tn("{yellow} • {{ci}{0}{ci} - total {1} second - {2}", "{yellow} • {{ci}{0}{ci} - total {1} seconds - {2}", - timer.getDuration(), - timer.getDisplayName(), - timer.getDuration(), - timer.toString() - )); - } - else - { - sender.sendMessage(I.tn("{green} • {ci}{0}{ci} - total {1} second - {2}", "{green} • {ci}{0}{ci} - total {1} seconds - {2}", - timer.getDuration(), - timer.getDisplayName(), - timer.getDuration(), - timer.toString() - )); - } - } - else - { - sender.sendMessage(I.tn("{red} • {ci}{0}{ci} - total {1} second", "{red} • {ci}{0}{ci} - total {1} seconds", - timer.getDuration(), - timer.getDisplayName(), - timer.getDuration() - )); - } - } - } - - @Override - public List<String> tabComplete(CommandSender sender, String[] args) - { - List<String> suggestions = new ArrayList<>(); - - for (UHTimer timer : p.getTimerManager().getTimers()) - { - suggestions.add(timer.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 0), suggestions, args.length - 1); - } - - @Override - public List<String> help(CommandSender sender) - { - return null; - } - - @Override - public List<String> onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh timers list {ci}: lists the registered timers.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersPauseCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersPauseCommand.java deleted file mode 100644 index d6ac577..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersPauseCommand.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.commands.commands.uh.timers; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -@Command (name = "pause") -public class UHTimersPauseCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTimersPauseCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - String timerName = UHUtils.getStringFromCommandArguments(args, 0); - UHTimer timer = p.getTimerManager().getTimer(timerName); - - if (timer == null) - { - sender.sendMessage(I.t("{ce}This timer is not registered.")); - return; - } - - timer.setPaused(true); - sender.sendMessage(I.t("{cs}The timer {0}{cs} is now paused.", timer.getDisplayName())); - } - - @Override - public List<String> tabComplete(CommandSender sender, String[] args) - { - List<String> suggestions = new ArrayList<>(); - - for (UHTimer timer : p.getTimerManager().getTimers()) - { - suggestions.add(timer.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 0), suggestions, args.length - 1); - } - - @Override - public List<String> help(CommandSender sender) - { - return null; - } - - @Override - public List<String> onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh timers pause <title ...> {ci}: pauses a timer.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersRemoveCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersRemoveCommand.java deleted file mode 100644 index 0b4b45e..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersRemoveCommand.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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.commands.commands.uh.timers; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -@Command (name = "remove") -public class UHTimersRemoveCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTimersRemoveCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - String timerName = UHUtils.getStringFromCommandArguments(args, 0); - UHTimer timer = p.getTimerManager().getTimer(timerName); - - if (timer == null) - { - sender.sendMessage(I.t("{ce}This timer is not registered.")); - return; - } - - p.getTimerManager().unregisterTimer(timer); - timer.stop(); - - sender.sendMessage(I.t("{cs}The timer {0}{cs} has been deleted.", timer.getDisplayName())); - } - - @Override - public List<String> tabComplete(CommandSender sender, String[] args) - { - List<String> suggestions = new ArrayList<>(); - - for (UHTimer timer : p.getTimerManager().getTimers()) - { - suggestions.add(timer.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 0), suggestions, args.length - 1); - } - - @Override - public List<String> help(CommandSender sender) - { - return null; - } - - @Override - public List<String> onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh timers remove <title ...> {ci}: deletes a timer.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersResumeCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersResumeCommand.java deleted file mode 100644 index 85239c4..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersResumeCommand.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.commands.commands.uh.timers; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -@Command (name = "resume") -public class UHTimersResumeCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTimersResumeCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - String timerName = UHUtils.getStringFromCommandArguments(args, 0); - UHTimer timer = p.getTimerManager().getTimer(timerName); - - if (timer == null) - { - sender.sendMessage(I.t("{ce}This timer is not registered.")); - return; - } - - timer.setPaused(false); - sender.sendMessage(I.t("{cs}The timer {0}{cs} was resumed.", timer.getDisplayName())); - } - - @Override - public List<String> tabComplete(CommandSender sender, String[] args) - { - List<String> suggestions = new ArrayList<>(); - - for (UHTimer timer : p.getTimerManager().getTimers()) - { - suggestions.add(timer.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 0), suggestions, args.length - 1); - } - - @Override - public List<String> help(CommandSender sender) - { - return null; - } - - @Override - public List<String> onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh timers resume <title ...> {ci}: resumes a timer.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersSetCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersSetCommand.java deleted file mode 100644 index 5bce4a5..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersSetCommand.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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.commands.commands.uh.timers; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -/** - * Usage: /uh timers set <duration> <name ...> - */ -@Command (name = "set") -public class UHTimersSetCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTimersSetCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - - if (args.length < 2) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - else - { - try - { - Integer duration = UHUtils.string2Time(args[0]); - String timerName = UHUtils.getStringFromCommandArguments(args, 1); - - UHTimer timer = p.getTimerManager().getTimer(timerName); - if (timer == null) - { - sender.sendMessage(I.t("{ce}This timer is not registered.")); - return; - } - - timer.setDuration(duration); - sender.sendMessage(I.t("{cs}The duration of the timer {0}{cs} is now {1}.", timer.getDisplayName(), args[0])); - - } - catch (IllegalArgumentException e) - { - sender.sendMessage(I.t("{ce}The duration' syntax is invalid; accepted formats are mm, mm:ss or hh:mm:ss.")); - } - } - } - - @Override - public List<String> tabComplete(CommandSender sender, String[] args) - { - - if (args.length >= 2) - { - List<String> suggestions = new ArrayList<>(); - - for (UHTimer timer : p.getTimerManager().getTimers()) - { - suggestions.add(timer.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 1), suggestions, args.length - 2); - } - - else return null; - } - - @Override - public List<String> help(CommandSender sender) - { - return null; - } - - @Override - public List<String> onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh timers set <duration> <title ...> {ci}: sets the duration of a timer.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersStartCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersStartCommand.java deleted file mode 100644 index e169a14..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersStartCommand.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.commands.commands.uh.timers; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -@Command (name = "start") -public class UHTimersStartCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTimersStartCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - String timerName = UHUtils.getStringFromCommandArguments(args, 0); - UHTimer timer = p.getTimerManager().getTimer(timerName); - - if (timer == null) - { - sender.sendMessage(I.t("{ce}This timer is not registered.")); - return; - } - - if (timer.isRunning()) - { - timer.stop(); - } - - timer.start(); - sender.sendMessage(I.t("{cs}The timer {0}{cs} was started.", timer.getDisplayName())); - } - - @Override - public List<String> tabComplete(CommandSender sender, String[] args) - { - List<String> suggestions = new ArrayList<>(); - - for (UHTimer timer : p.getTimerManager().getTimers()) - { - suggestions.add(timer.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 0), suggestions, args.length - 1); - } - - @Override - public List<String> help(CommandSender sender) - { - return null; - } - - @Override - public List<String> onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh timers start <title ...> {ci}: starts a timer.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersStopCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersStopCommand.java deleted file mode 100644 index c4d629d..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersStopCommand.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.commands.commands.uh.timers; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -@Command (name = "stop") -public class UHTimersStopCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHTimersStopCommand(UHCReloaded p) - { - this.p = p; - } - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.BAD_USE, this); - } - - String timerName = UHUtils.getStringFromCommandArguments(args, 0); - UHTimer timer = p.getTimerManager().getTimer(timerName); - - if (timer == null) - { - sender.sendMessage(I.t("{ce}This timer is not registered.")); - return; - } - - timer.stop(); - sender.sendMessage(I.t("{cs}The timer {0}{cs} was stopped.", timer.getDisplayName())); - } - - @Override - public List<String> tabComplete(CommandSender sender, String[] args) - { - List<String> suggestions = new ArrayList<>(); - - for (UHTimer timer : p.getTimerManager().getTimers()) - { - suggestions.add(timer.getName()); - } - - return CommandUtils.getAutocompleteSuggestions(UHUtils.getStringFromCommandArguments(args, 0), suggestions, args.length - 1); - } - - @Override - public List<String> help(CommandSender sender) - { - return null; - } - - @Override - public List<String> onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh timers stop <title ...> {ci}: stops a timer. The timer will be removed from the scoreboard.")); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/AbstractCommand.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/AbstractCommand.java deleted file mode 100644 index 9c11b97..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/AbstractCommand.java +++ /dev/null @@ -1,409 +0,0 @@ -/* - * 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.commands.core; - -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import org.bukkit.command.CommandSender; - -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - - -/** - * Represents a command with subcommands (or not). - * - * <p> - * Add the subcommands with the {@link #registerSubCommand} method in the constructor.<br /> - * A subcommand is simply an {@link AbstractCommand} object. - * </p> - * - * @version 1.0 - * @author Amaury Carrade - */ -public abstract class AbstractCommand -{ - /** - * Stores the sub-commands of this complex command. - * - * <p>name → command.</p> - */ - private Map<String, AbstractCommand> subcommands = new LinkedHashMap<>(); - - /** - * Stores the permissions of the sub-commands. - * - * <p>name → permission.</p> - */ - private Map<String, String> permissions = new LinkedHashMap<>(); - - /** - * Stores the sub-commands per category. - * - * <p>name → category.</p> - */ - private Map<String, String> subcommandsCategories = new LinkedHashMap<>(); - - /** - * The parent command. - * - * <p> - * Example, for {@code /cmd foo bar}, the parent command of {@code bar} - * is the command {@code foo}. - * </p> - * <p> - * Without parent (root command), {@code null}. - * </p> - */ - private AbstractCommand parent = null; - - - /** - * Runs the command. - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - * - * @throws eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException If the command cannot be executed. - */ - public abstract void run(CommandSender sender, String[] args) throws CannotExecuteCommandException; - - /** - * Tab-completes this command. - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - public abstract List<String> tabComplete(CommandSender sender, String[] args); - - /** - * Returns the help of this command. - * - * <p> - * These lines will only be displayed if the {@link CannotExecuteCommandException} is - * caught by the command executor, with the reasons {@code BAD_USE} or {@code NEED_DOC}. - * </p> - * <p> - * If this returns null, fallsback to {@link #onListHelp}. - * </p> - * - * - * @param sender The sender. - * - * @return The help. One line per entry in the list. - */ - public abstract List<String> help(CommandSender sender); - - /** - * Returns the help displayed in the list of the commands, in the help - * of the parent command. - * - * <p> - * You should return one single line here, except for special cases. - * </p> - * - * @param sender The sender. - * - * @return The help. One line displayed per entry in the list. - */ - public abstract List<String> onListHelp(CommandSender sender); - - /** - * Returns the title of the category of the command. - * - * <p> - * This category will be displayed as a title in the commands' list.<br /> - * If the value defined is empty, or null, or the method not overwritten, - * the command will be not categorized. - * </p> - * - * <p> - * This category must be unique in the sub-commands of a command. - * </p> - * - * <p> - * You should either use a category for all subcommands of a command, either no categories - * at all for these commands. Else, the non-categorized commands will be displayed somewhere, - * and this place may vary. - * </p> - */ - public String getCategory() - { - return null; - } - - - /** - * Sets the parent command of this command. Can be set only one time. - * - * @param parent The parent. - * - * @throws IllegalArgumentException If the parent command is already set. - */ - public void setParent(AbstractCommand parent) - { - if (this.parent != null) - { - throw new IllegalArgumentException("The parent command is already set!"); - } - - this.parent = parent; - } - - /** - * Returns the parent command. - * - * @return The parent; {@code null} if this command is a root one. - */ - public AbstractCommand getParent() - { - return parent; - } - - - /** - * Registers a subcommand of this command. - * - * @param command The command to register. - * - * @throws IllegalArgumentException If the command object don't have the {@link eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command} annotation. - */ - public void registerSubCommand(AbstractCommand command) - { - Command commandAnnotation = command.getClass().getAnnotation(Command.class); - - if (commandAnnotation == null) - { - throw new IllegalArgumentException("Cannot register a command without @Command annotation. Class: " + command.getClass().getCanonicalName() + "."); - } - - command.setParent(this); - - String name = commandAnnotation.name(); - String permission = commandAnnotation.permission(); - - if (permission == null && !commandAnnotation.useParentPermission()) - { - permission = commandAnnotation.name(); - } - - if (permission != null && permission.isEmpty() || commandAnnotation.noPermission()) - { - permission = null; - } - - if (commandAnnotation.inheritPermission() || commandAnnotation.useParentPermission()) - { - - AbstractCommand parent = this; - if (commandAnnotation.useParentPermission()) - { - // We starts at the parent to get the parent's permission. - parent = this.getParent(); - } - - while (parent != null) - { - // The parent will always have the @Command annotation, because it is always - // added in this method and the presence of the annotation is checked. - Command parentAnnotation = parent.getClass().getAnnotation(Command.class); - if (parentAnnotation.permission() != null && !parentAnnotation.permission().isEmpty()) - { - permission = parentAnnotation.permission(); - if (permission != null && !permission.isEmpty()) - { - permission += "." + permission; - } - } - parent = parent.getParent(); - } - } - - // Let's save these permissions and executors. - subcommands.put(name, command); - permissions.put(name, permission); - - // Categories - if (command.getCategory() != null && !command.getCategory().isEmpty()) - { - subcommandsCategories.put(name, command.getCategory()); - } - } - - /** - * Routes the command, to a sub command, with a fallback to the - * {@link #run} method of this command if no subcommand matches - * or if there isn't any argument passed to this command. - * - * <p> - * Internal use. Do not override this. Ignore this. - * </p> - * - * @param sender The sender of the command. - * @param args The arguments passed to the command. - */ - public void routeCommand(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (args.length == 0) - { - run(sender, new String[0]); - } - else - { - AbstractCommand cmd = subcommands.get(args[0]); - if (cmd != null) - { - // Allowed? - String permission = permissions.get(args[0]); - if (permission == null || sender.hasPermission(permission)) - { - cmd.routeCommand(sender, CommandUtils.getSubcommandArguments(args)); - } - else - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NOT_ALLOWED); - } - } - else - { - run(sender, args); - } - } - } - - /** - * Routes to the autocompleter of this command. - * - * <p> - * Internal use. Do not override this. Ignore this. - * </p> - * - * @param sender The sender. - * @param args The arguments passed to the command. - * - * @return A list of suggestions. - */ - public List<String> routeTabComplete(CommandSender sender, String[] args) - { - // Autocompletion for this command - if (args.length == 1) - { - List<String> suggestions = new LinkedList<>(); - - for (String command : subcommands.keySet()) - { - String permission = permissions.get(command); - if (permission == null || sender.hasPermission(permission)) - { - suggestions.add(command); - } - } - - suggestions = CommandUtils.getAutocompleteSuggestions(args[0], suggestions); - - List<String> suggestionsFromThisCommand = tabComplete(sender, args); - if (suggestionsFromThisCommand != null) - { - suggestions.addAll(suggestionsFromThisCommand); - } - - return suggestions; - } - - // Autocompletion for a subcommand - else - { - AbstractCommand subcommand = subcommands.get(args[0]); - if (subcommand != null) - { - return subcommand.routeTabComplete(sender, CommandUtils.getSubcommandArguments(args)); - } - else - { - return tabComplete(sender, args); - } - } - } - - /** - * Returns the subcommands. - * - * <p> - * Map: name of the command → UHCommand object. - * </p> - * - * @return the subcommands. - */ - public Map<String, AbstractCommand> getSubcommands() - { - return subcommands; - } - - /** - * Returns the permissions of the subcommands. - * - * <p> - * Map: name of the command → raw permission of this command. - * </p> - * - * @return the permissions of the subcommands. - */ - public Map<String, String> getSubcommandsPermissions() - { - return permissions; - } - - /** - * Returns true if this command has subcommands. - */ - public boolean hasSubCommands() - { - return subcommands.size() > 0; - } - - /** - * Returns the categories of the subcommands. - * - * <p> - * Map: name of the command → title of the category of this command. - * </p> - */ - public Map<String, String> getSubcommandsCategories() - { - return subcommandsCategories; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/AbstractCommandExecutor.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/AbstractCommandExecutor.java deleted file mode 100644 index dbb2861..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/AbstractCommandExecutor.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * 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.commands.core; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; - -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - - -/** - * The base of every command executor. - * - * <p> - * The command executors needs to extend this class and to register the commands in the constructor - * with the method {@link #registerCommand}. - * </p> - * - * @version 1.0 - * @author Amaury Carrade - */ -public abstract class AbstractCommandExecutor implements TabExecutor -{ - private UHCReloaded p; - - /** - * Stores the main commands, i.e. the commands registered in the {@code plugin.yml} file. - */ - private Map<String, AbstractCommand> mainCommands = new LinkedHashMap<>(); - - /** - * Stores the base permissions of these commands. - */ - private Map<String, String> mainCommandsPermissions = new LinkedHashMap<>(); - - - public AbstractCommandExecutor(UHCReloaded plugin) - { - p = plugin; - } - - - /** - * Registers a main, root command. This command must be in the {@code plugin.yml}, or - * it will never be called. - * - * @param command The command. - * - * @throws IllegalArgumentException If the command class doesn't have the @Command - * annotation. - */ - public void registerCommand(AbstractCommand command) - { - Command commandAnnotation = command.getClass().getAnnotation(Command.class); - if (commandAnnotation == null) - { - throw new IllegalArgumentException("Cannot register a command without @Command annotation. Class: " + command.getClass().getCanonicalName() + "."); - } - - mainCommands.put(commandAnnotation.name(), command); - - String permission = commandAnnotation.permission(); - - if (commandAnnotation.noPermission()) - { - permission = null; - } - else if (permission != null && permission.isEmpty()) - { - if (commandAnnotation.useParentPermission()) - { - permission = null; - } - else - { - permission = commandAnnotation.name(); - } - } - - mainCommandsPermissions.put(commandAnnotation.name(), permission); - } - - - /** - * Displays the help of a command. - * - * <p> - * If the command is a complex command, this will display the help of the complex command, - * first line excepted, ath then the short help of all sub-commands.<br /> - * Else, this will display the full help for the command. - * </p> - * - * @param sender The sender. - * @param command The command. - * @param isAnError {@code true} if this is displayed due to an error. - */ - public void displayHelp(CommandSender sender, AbstractCommand command, boolean isAnError) - { - if (command.hasSubCommands()) - { - List<String> help = new LinkedList<>(); - - // Root help - List<String> rootHelp = command.help(sender); - if (rootHelp != null) - { - help.addAll(rootHelp); - } - - // Then, the help of the sub-commands sorted by category. - // We first organize the commands per-category. - Map<String, LinkedList<String>> helpPerCategory = new LinkedHashMap<>(); - - for (Map.Entry<String, AbstractCommand> subCommand : command.getSubcommands().entrySet()) - { - List<String> subHelp = subCommand.getValue().onListHelp(sender); - String permission = command.getSubcommandsPermissions().get(subCommand.getKey()); - String category = command.getSubcommandsCategories().get(subCommand.getKey()); - - if (category == null) category = ""; - - if (subHelp != null && subHelp.size() > 0 && (permission == null || sender.hasPermission(permission))) - { - - LinkedList<String> helpForThisCategory = helpPerCategory.get(category); - if (helpForThisCategory != null) - { - helpForThisCategory.addAll(subHelp); - } - else - { - helpForThisCategory = new LinkedList<>(); - helpForThisCategory.addAll(subHelp); - helpPerCategory.put(category, helpForThisCategory); - } - } - } - - // After, we add to the help to display these commands, with the titles of the - // categories. - for (Map.Entry<String, LinkedList<String>> category : helpPerCategory.entrySet()) - { - help.add(category.getKey()); - help.addAll(category.getValue()); - } - - displayHelp(sender, help, isAnError); - } - else - { - List<String> help = command.help(sender); - if (help == null) help = command.onListHelp(sender); - - displayHelp(sender, help, isAnError); - } - } - - /** - * Displays the help of a command. - * - * @param sender The sender; this user will receive the help. - * @param help The help to display (one line per entry; raw display). - * @param isAnError {@code true} if this is displayed due to an error. - */ - public void displayHelp(CommandSender sender, List<String> help, boolean isAnError) - { - CommandUtils.displaySeparator(sender); - - if (!isAnError) - { - sender.sendMessage(I.t("{yellow}{0} - version {1}", p.getDescription().getDescription(), p.getDescription().getVersion())); - sender.sendMessage(I.t("{ci}Legend: {cc}/uh command <required> [optional=default] <spaces allowed ...>{ci}.")); - } - - if (help != null) - { - for (String line : help) - { - if (line != null && !line.isEmpty()) - sender.sendMessage(line); - } - } - - CommandUtils.displaySeparator(sender); - - if (isAnError) - { - sender.sendMessage(I.t("{ce}{bold}You cannot execute this command this way.")); - sender.sendMessage(I.t("{ce}The help is displayed above.")); - CommandUtils.displaySeparator(sender); - } - } - - - @Override - public boolean onCommand(CommandSender sender, org.bukkit.command.Command command, String alias, String[] args) - { - AbstractCommand abstractCommand = mainCommands.get(command.getName()); - if (abstractCommand == null) - { - return false; - } - - try - { - String permission = mainCommandsPermissions.get(command.getName()); - if (permission != null && !sender.hasPermission(permission)) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.NOT_ALLOWED); - } - - abstractCommand.routeCommand(sender, args); - - } - catch (CannotExecuteCommandException e) - { - switch (e.getReason()) - { - case NOT_ALLOWED: - sender.sendMessage(I.t("{ce}You are not allowed to execute this command.")); - break; - - case ONLY_AS_A_PLAYER: - sender.sendMessage(I.t("{ce}This can only be executed as a player.")); - break; - - case BAD_USE: - case NEED_DOC: - displayHelp(sender, e.getOrigin() != null ? e.getOrigin() : abstractCommand, e.getReason() == CannotExecuteCommandException.Reason.BAD_USE); - break; - - case UNKNOWN: - break; - } - } - - return true; - } - - @Override - public List<String> onTabComplete(CommandSender sender, org.bukkit.command.Command command, String alias, String[] args) - { - AbstractCommand abstractCommand = mainCommands.get(command.getName()); - return abstractCommand.routeTabComplete(sender, args); - } - - public Map<String, AbstractCommand> getMainCommands() - { - return mainCommands; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/annotations/Command.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/annotations/Command.java deleted file mode 100644 index 2a3f2be..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/annotations/Command.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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.commands.core.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - - -/** - * This annotation needs to be applied to every command class. It is used to define the - * name and the permission of the command. - * - * @version 1.0 - * @author Amaury Carrade - */ -@Retention (RetentionPolicy.RUNTIME) -@Target (ElementType.TYPE) -public @interface Command -{ - - /** - * The name of the command, needed to type in the console/chat to execute - * the (sub-)command. - */ - String name(); - - /** - * The permission needed to execute this command. - * - * <p> - * Please note that with the current version of this API, the user will need to have the right to - * access the parent commands, to access this command.<br /> - * This situation may evolve in the future. - * </p> - * <p> - * If the {@code inheritPermission} option is unset or set to {@code true}, - * this permission is <strong>concatened to the parent permissions</strong>.<br /> - * As example, if the permission is set to {@code sb}, and if the parent command - * have the permission {@code cmd.norris}, the real permission of the command will - * be {@code cmd.norris.sb}. - * </p> - * <p> - * If this is left empty, or not set, the permission will be the name of the command, excepted - * if {@link #useParentPermission} is set to true. - * </p> - */ - String permission() default ""; - - /** - * If this is set to {@code false}, the permission will be interpreted <em>as-is</em>, - * without concatenation with the permissions of the parent commands. - * - * <p> - * You should not set this to {@code false} if the command have sub-commands with this - * set to {@code true}, or weired behavior may happens. - * </p> - */ - boolean inheritPermission() default true; - - /** - * If this is set to {@code true}, the permission of the parent command will be used. - * - * <p> - * If the parent command is {@code null} (i.e. this command is a root one), the command will be - * accessible to everyone. - * </p> - */ - boolean useParentPermission() default false; - - /** - * If this is set to true, no permissions check will be done when someone - * executes this command. - */ - boolean noPermission() default false; -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/exceptions/CannotExecuteCommandException.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/exceptions/CannotExecuteCommandException.java deleted file mode 100644 index b755752..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/exceptions/CannotExecuteCommandException.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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.commands.core.exceptions; - -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; - - -/** - * This exception is fired when a command cannot be executed, for whatever reason. - * - * @version 1.0 - * @author Amaury Carrade - */ -public class CannotExecuteCommandException extends Exception -{ - - public enum Reason - { - /** - * Use this if the player is not allowed to execute the command. - */ - NOT_ALLOWED, - - /** - * Use this if the command can only be executed as a player, and - * the sender is not a player. - */ - ONLY_AS_A_PLAYER, - - /** - * Use this if the sender used the command badly. - * - * <p> - * This will display the documentation and an error message. - * </p> - */ - BAD_USE, - - /** - * Use this to have the documentation of the command displayed. - */ - NEED_DOC, - - /** - * Use this in other cases. - */ - UNKNOWN - } - - private Reason reason; - private AbstractCommand origin; - - public CannotExecuteCommandException(Reason reason, AbstractCommand origin) - { - this.reason = reason; - this.origin = origin; - } - - public CannotExecuteCommandException(Reason reason) - { - this(reason, null); - } - - public Reason getReason() - { - return reason; - } - - public AbstractCommand getOrigin() - { - return origin; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/utils/CommandUtils.java b/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/utils/CommandUtils.java deleted file mode 100644 index 6d760bd..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/utils/CommandUtils.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * 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.commands.core.utils; - -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import org.apache.commons.lang.StringUtils; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.text.Collator; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - - -public class CommandUtils -{ - - /** - * Returns {@code true} if the sender is allowed to execute the given command. - * - * <p> - * Use that only if you have an isolated UHCommand object. Not if you have a direct access to - * the parent command, or if you know the command is a root command. - * </p> - * - * @param sender The sender. - * @param command The command. - * - * @return {@code true} if the sender is allowed to execute the command. - */ - public static boolean isAllowed(CommandSender sender, AbstractCommand command) - { - // root command - if (command.getParent() == null) - { - Command commandAnnotation = command.getClass().getAnnotation(Command.class); - if (commandAnnotation != null) - { - if (commandAnnotation.permission() == null) - { - return true; - } - else if (commandAnnotation.permission().isEmpty()) - { - return sender.hasPermission(commandAnnotation.name()); - } - else - { - return sender.hasPermission(commandAnnotation.permission()); - } - } - } - else - { - return sender.hasPermission(command.getParent().getSubcommandsPermissions().get(command.getClass().getAnnotation(Command.class).name())); - } - - return false; // should never happens. - } - - /** - * Returns the args without the first item. - * - * @param args The arguments sent to the parent command. - * @return The arguments to send to the child command. - */ - public static String[] getSubcommandArguments(String[] args) - { - if (args.length <= 1) - { - return new String[0]; - } - - return Arrays.copyOfRange(args, 1, args.length); - } - - - /** - * Returns the tags in the arguments, following the format "tagname:value". - * - * <p> - * If a tag is defined multiple times, the value used is the last one. - * </p> - * <p> - * Invalid tags (other format that « key:value ») are ignored. - * </p> - * - * @param args The args. - * @param defaults The defaults values. The values defined here will always be in the returned map, - * with the same value if the key is not in the arguments. - * {@code null} if no default values are needed. - * - * @return A map tagname -> value. - */ - public static Map<String, String> getTagsInArgs(String[] args, Map<String, String> defaults) - { - Map<String, String> tagsCollected; - - if (defaults != null) - { - tagsCollected = new HashMap<>(defaults); - } - else - { - tagsCollected = new HashMap<>(); - } - - for (String arg : args) - { - String[] argSpilt = arg.split(":"); - if (argSpilt.length >= 2) // valid - { - String key = argSpilt[0]; - String value = StringUtils.join(Arrays.copyOfRange(argSpilt, 1, argSpilt.length), ":"); - - tagsCollected.put(key, value); - } - } - - return tagsCollected; - } - - - /** - * Returns a list of autocompletion suggestions based on what the user typed and on a list of - * available commands. - * - * @param typed What the user typed. This string needs to include <em>all</em> the words typed. - * @param suggestionsList The list of the suggestions. - * @param numberOfWordsToIgnore If non-zero, this number of words will be ignored at the beginning of the string. This is used to handle multiple-words autocompletion. - * - * @return The list of matching suggestions. - */ - public static List<String> getAutocompleteSuggestions(String typed, List<String> suggestionsList, int numberOfWordsToIgnore) - { - List<String> list = new ArrayList<String>(); - - // For each suggestion: - // - if there isn't any world to ignore, we just compare them; - // - else, we removes the correct number of words at the beginning of the string; - // then, if the raw suggestion matches the typed text, we adds to the suggestion list - // the filtered suggestion, because the Bukkit's autocompleter works on a “per-word” basis. - - for (String rawSuggestion : suggestionsList) - { - String suggestion; - - if (numberOfWordsToIgnore == 0) - { - suggestion = rawSuggestion; - } - else - { - // Not the primary use, but, hey! It works. - suggestion = UHUtils.getStringFromCommandArguments(rawSuggestion.split(" "), numberOfWordsToIgnore); - } - - if (rawSuggestion.toLowerCase().startsWith(typed.toLowerCase())) - { - list.add(suggestion); - } - } - - list.sort(Collator.getInstance()); - - return list; - } - - /** - * Returns a list of autocompletion suggestions based on what the user typed and on a list of - * available commands. - * - * @param typed What the user typed. - * @param suggestionsList The list of the suggestions. - * - * @return The list of matching suggestions. - */ - public static List<String> getAutocompleteSuggestions(String typed, List<String> suggestionsList) - { - return getAutocompleteSuggestions(typed, suggestionsList, 0); - } - - - /** - * Displays a separator around the output of the commands. - * - * <p> - * To be called before and after the output (prints a line only). - * </p> - * - * @param sender The line will be displayed for this sender. - */ - public static void displaySeparator(CommandSender sender) - { - if (!(sender instanceof Player)) - { - return; - } - - sender.sendMessage(ChatColor.GRAY + "⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅"); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java deleted file mode 100644 index 9d8d8da..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java +++ /dev/null @@ -1,1287 +0,0 @@ -/* - * 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.game; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.events.EpisodeChangedCause; -import eu.carrade.amaury.UHCReloaded.events.UHEpisodeChangedEvent; -import eu.carrade.amaury.UHCReloaded.events.UHGameStartsEvent; -import eu.carrade.amaury.UHCReloaded.events.UHPlayerResurrectedEvent; -import eu.carrade.amaury.UHCReloaded.misc.OfflinePlayersLoader; -import eu.carrade.amaury.UHCReloaded.protips.ProTips; -import eu.carrade.amaury.UHCReloaded.task.FireworksOnWinnersTask; -import eu.carrade.amaury.UHCReloaded.teams.TeamColor; -import eu.carrade.amaury.UHCReloaded.teams.TeamManager; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHSound; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.components.rawtext.RawText; -import fr.zcraft.zlib.tools.Callback; -import fr.zcraft.zlib.tools.runners.RunTask; -import fr.zcraft.zlib.tools.text.ActionBar; -import fr.zcraft.zlib.tools.text.RawMessage; -import fr.zcraft.zlib.tools.text.Titles; -import org.bukkit.Achievement; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Difficulty; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.World; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.potion.PotionEffect; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Queue; -import java.util.Random; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; - - -public class UHGameManager -{ - public final boolean START_GIVE_BANNER; - public final boolean START_PLACE_BANNER_HEAD; - public final boolean START_PLACE_BANNER_SPAWN; - - private final Boolean RANDOM_COLORS_IN_SOLO; - private final Boolean BROADCAST_SLOW_START_PROGRESS; - private final Long GRACE_PERIOD; - private final Long PEACE_PERIOD; - private final Long SURFACE_MOBS_FREE_PERIOD; - private final UHSound DEATH_SOUND; - - private UHCReloaded p; - private TeamManager tm; - private Random random; - - private Boolean damagesEnabled = false; - private Boolean mobsOnSurface = false; - - private Set<String> players = new HashSet<>(); // Will be converted to UUID when a built-in API for name->UUID conversion will be available - private Set<UUID> alivePlayers = new HashSet<>(); - private Set<UHTeam> aliveTeams = new HashSet<>(); - private Set<UUID> spectators = new HashSet<>(); - private Map<UUID, Location> deathLocations = new HashMap<>(); - - private Set<String> deadPlayersToBeResurrected = new HashSet<>(); // Same - - private Integer alivePlayersCount = 0; - private Integer aliveTeamsCount = 0; - - private Boolean gameWithTeams = true; - - // Used for the slow start. - private Boolean slowStartInProgress = false; - private Boolean slowStartTPFinished = false; - - private Boolean gameStarted = false; - private Boolean gameFinished = false; - private Integer episode = 0; - - private Teleporter teleporter = null; - - // Used to send a contextual error message in UHCommandManager, using only one exception, - // by checking the message. (Used in this.finishGame().) - public final static String FINISH_ERROR_NOT_STARTED = "Unable to finish the game: the game is not started"; - public final static String FINISH_ERROR_NOT_FINISHED = "Unable to finish the game: the game is not finished"; - - - public UHGameManager(UHCReloaded plugin) - { - this.p = plugin; - this.tm = p.getTeamManager(); - - this.random = new Random(); - - - // Loads the config - - RANDOM_COLORS_IN_SOLO = UHConfig.TEAMS_OPTIONS.RANDOM_COLORS.get(); - - BROADCAST_SLOW_START_PROGRESS = UHConfig.START.SLOW.BROADCAST_PROGRESS.get(); - - GRACE_PERIOD = (long) Math.max(UHUtils.string2Time(UHConfig.START.GRACE_PERIOD.get(), 30), 15) * 20l; - PEACE_PERIOD = (long) UHUtils.string2Time(UHConfig.START.PEACE_PERIOD.get(), 0) * 20l; - SURFACE_MOBS_FREE_PERIOD = (long) UHUtils.string2Time(UHConfig.START.SURFACE_MOBS_FREE_PERIOD.get(), 900) * 20l; - - DEATH_SOUND = new UHSound(UHConfig.DEATH.ANNOUNCEMENTS.SOUND); - - START_GIVE_BANNER = UHConfig.TEAMS_OPTIONS.BANNER.GIVE.GIVE_IN_HOTBAR.get(); - START_PLACE_BANNER_SPAWN = UHConfig.TEAMS_OPTIONS.BANNER.GIVE.PLACE_ON_SPAWN.get(); - START_PLACE_BANNER_HEAD = UHConfig.TEAMS_OPTIONS.BANNER.GIVE.GIVE_IN_HEAD.get(); - } - - /** - * Initializes the environment before the start of the game. - */ - public void initEnvironment() - { - p.getServer().getWorlds().get(0).setGameRuleValue("doDaylightCycle", "false"); - p.getServer().getWorlds().get(0).setTime(6000L); - p.getServer().getWorlds().get(0).setStorm(false); - p.getServer().getWorlds().get(0).setDifficulty(Difficulty.HARD); - } - - /** - * Initializes the given player. - * - * - Teleportation to the default world's spawn point. - * - Max food level & health. - * - Scoreboard. - * - Fixed health score. - * - Spectate mode disabled. - * - Gamemode: creative (if permission "uh.build" granted) or adventure (else). - * - * @param player The player to initialize. - */ - public void initPlayer(final Player player) - { - if (UHConfig.TELEPORT_TO_SPAWN_IF_NOT_STARTED.get()) - { - Location l = player.getWorld().getSpawnLocation().add(0.5, 0.5, 0.5); - if (!UHUtils.safeTP(player, l)) - { - player.teleport(l.add(0, 1, 0)); - } - } - - player.setFoodLevel(20); - player.setSaturation(20f); - player.setHealth(20d); - - p.getScoreboardManager().setScoreboardForPlayer(player); - - // Used to update the "health" objective, to avoid a null one. - // Launched later because else, the health is constantly set to 20, - // and this prevents the health score to be updated. - Bukkit.getScheduler().runTaskLater(p, () -> p.getScoreboardManager().updateHealthScore(player), 20L); - - // Disable the spectator mode if the game is not started. - p.getSpectatorsManager().setSpectating(player, false); - - // Resets the achievements - if (UHConfig.ACHIEVEMENTS.RESET_ACHIEVEMENTS_AT_STARTUP.get()) - { - player.removeAchievement(Achievement.OPEN_INVENTORY); - } - - // If the user has the permission to build before the game, he will probably needs - // the creative mode. - if (!player.hasPermission("uh.build")) - { - player.setGameMode(GameMode.ADVENTURE); - } - else - { - player.setGameMode(GameMode.CREATIVE); - } - } - - - /** - * Starts the game. - * - * - Teleports the teams - * - Changes the gamemode, reset the life, clear inventories, etc. - * - Launches the timer - * - * @param sender The player who launched the game. - * @param slow If true, the slow mode is enabled. With the slow mode, the players are, at - * first, teleported one by one with a configurable delay, and with the - * fly. Then, the fly is removed and the game starts. - * @param ignoreTeams If true, the players will be teleported in individual teleportation spots, - * just like without teams, even with teams. - * - * @throws IllegalStateException if the game is running. - */ - public void start(final CommandSender sender, final Boolean slow, Boolean ignoreTeams) throws IllegalStateException - { - if (isGameRunning()) - { - throw new IllegalStateException("The game is currently running!"); - } - - - /* ** Initialization of the teams ** */ - - alivePlayers.clear(); - aliveTeams.clear(); - alivePlayersCount = 0; - aliveTeamsCount = 0; - - // Stores the teams created on-the-fly, to unregister them if something bad happens. - final Set<UHTeam> onTheFlyTeams = new HashSet<>(); - - // If there isn't any team, we add all players (startup spectators excluded) to a new solo team. - if (tm.getTeams().isEmpty()) - { - gameWithTeams = false; - - Bukkit.getOnlinePlayers().stream().filter(player -> !spectators.contains(player.getUniqueId())).forEach(player -> - { - final UHTeam team = new UHTeam(player.getName(), RANDOM_COLORS_IN_SOLO ? TeamColor.RANDOM : null); - team.addPlayer(player, true); - - tm.addTeam(team); - onTheFlyTeams.add(team); - }); - } - - // Else, every non-startup-spectator out of any team player is added to a solo team. - else - { - gameWithTeams = true; - - Bukkit.getOnlinePlayers().stream() - .filter(player -> !spectators.contains(player.getUniqueId())) - .filter(player -> tm.getTeamForPlayer(player) == null) - .forEach(player -> - { - // We need an unique name for the team. - String teamName = player.getName(); - while (tm.isTeamRegistered(teamName)) - { - teamName = player.getName() + " " + random.nextInt(1000000); - } - - final UHTeam team = new UHTeam(teamName, RANDOM_COLORS_IN_SOLO ? TeamColor.RANDOM : null); - - team.addPlayer(player, true); - - tm.addTeam(team); - onTheFlyTeams.add(team); - }); - } - - - /* ** Initialization of the players ** */ - - tm.getTeams().forEach( - team -> team.getPlayers().stream() - .map(OfflinePlayer::getUniqueId) - .filter(player -> !spectators.contains(player)) - .forEach(player -> alivePlayers.add(player)) - ); - - updateAliveCache(); - - - /* ** Spawns check ** */ - - Integer spawnsNeeded = ignoreTeams ? alivePlayersCount : aliveTeamsCount; - - if (p.getSpawnsManager().getSpawnPoints().size() < spawnsNeeded) - { - if (sender instanceof Player) sender.sendMessage(""); - sender.sendMessage(I.t("{ce}Unable to start the game: not enough teleportation spots.")); - sender.sendMessage(I.t("{ci}You can use {cc}/uh spawns generate <random|circular|grid>{ci} to generate the missing spawns automatically.")); - - /// In the sentence: "Or click here to generate the spawns randomly." - RawMessage.send(sender, new RawText(I.t("Or")) - .then(" ") - /// In the sentence: "Or click here to generate the spawns randomly." - .then(I.t("click here")) - .color(ChatColor.GREEN).style(ChatColor.BOLD) - .command("/uh spawns generate random") - .hover(new RawText("/uh spawns generate random")) - .then(" ") - /// In the sentence: "Or click here to generate the spawns randomly." - .then(I.t("to generate the spawns randomly.")).color(ChatColor.WHITE) - .build() - ); - - // We clears the teams created on-the-fly - onTheFlyTeams.forEach(team -> tm.removeTeam(team, true)); - - aliveTeamsCount = 0; - alivePlayersCount = 0; - - return; - } - - - /* ** MOTD (now the game WILL start) ** */ - - p.getMOTDManager().updateMOTDDuringStart(); - - - /* ** Removes the teams action bar (if any) ** */ - if (UHConfig.BEFORE_START.TEAM_IN_ACTION_BAR.get()) - { - tm.getTeams().stream() - .flatMap(team -> team.getPlayers().stream()) - .forEach(player -> ActionBar.removeMessage(player.getUniqueId(), true)); - } - - - /* ** Initialization of the spectator mode ** */ - - Bukkit - .getOnlinePlayers() - .forEach(player -> p.getSpectatorsManager().setSpectating(player, spectators.contains(player.getUniqueId()))); - - - /* ** Teleportation ** */ - - teleporter = new Teleporter(); - - List<Location> spawnPoints = new ArrayList<>(p.getSpawnsManager().getSpawnPoints()); - Collections.shuffle(spawnPoints); - - Queue<Location> unusedTP = new ArrayDeque<>(spawnPoints); - - tm.getTeams().stream().filter(team -> !team.isEmpty()).forEach(team -> - { - if (!ignoreTeams && gameWithTeams) - { - final Location teamSpawn = unusedTP.poll(); - final Cage cage = Cage.createInstanceForTeamIfEnabled(team, teamSpawn); - - p.getDynmapIntegration().showSpawnLocation(team, teamSpawn); - - team.getPlayersUUID().forEach(player -> - { - teleporter.setSpawnForPlayer(player, teamSpawn); - if (cage != null) teleporter.setCageForPlayer(player, cage); - }); - } - else - { - team.getPlayersUUID().forEach(player -> - { - final Location playerSpawn = unusedTP.poll(); - final Cage cage = Cage.createInstanceForTeamIfEnabled(team, playerSpawn); - - teleporter.setSpawnForPlayer(player, playerSpawn); - if (cage != null) teleporter.setCageForPlayer(player, cage); - - p.getDynmapIntegration().showSpawnLocation(Bukkit.getOfflinePlayer(player), playerSpawn); - }); - } - }); - - if (slow) - { - slowStartInProgress = true; - slowStartTPFinished = false; - - // The players are frozen during the start (if cages are not used). - if (!UHConfig.START.SLOW.CAGES.ENABLED.get()) - p.getFreezer().setGlobalFreezeState(true, false); - - // A simple information, because this start is slower (yeah, Captain Obvious here) - p.getServer().broadcastMessage(I.t("{lightpurple}Teleportation in progress... Please wait.")); - - teleporter.whenTeleportationOccurs(new Callback<UUID>() - { - private int teleported = 0; - private final int total = alivePlayersCount; - - @Override - public void call(UUID uuid) - { - teleported++; - - if (BROADCAST_SLOW_START_PROGRESS) - { - /// Displayed in the action bar while the slow teleportation occurs. - final String message = I.t("{lightpurple}Teleporting... {gray}({0}/{1})", teleported, total); - for (Player player : Bukkit.getOnlinePlayers()) - { - ActionBar.sendPermanentMessage(player, message); - } - } - } - }); - } - - teleporter - .whenTeleportationSuccesses(uuid -> - { - final Player player = Bukkit.getPlayer(uuid); - - if (slow) - { - sender.sendMessage(I.t("{gray}Player {0}{gray} teleported.", player.getName())); - - if (!UHConfig.START.SLOW.CAGES.ENABLED.get()) - { - RunTask.nextTick(() -> - { - player.setAllowFlight(true); - player.setFlying(true); - }); - } - } - - if (UHConfig.START.SLOW.CAGES.ENABLED.get()) - player.setGameMode(GameMode.ADVENTURE); - else - player.setGameMode(GameMode.SURVIVAL); - - resetPlayer(player); - - player.getActivePotionEffects().stream().map(PotionEffect::getType).forEach(player::removePotionEffect); - player.setCompassTarget(player.getWorld().getSpawnLocation()); - }) - - .whenTeleportationFails(uuid -> sender.sendMessage(I.t("{ce}Cannot teleport player {0}!", Bukkit.getPlayer(uuid).getName()))) - - .whenTeleportationEnds(uuids -> - { - if (slow) - { - slowStartTPFinished = true; - - try - { - sender.sendMessage(I.t("{cs}All teams are teleported.")); - RawMessage.send(sender, new RawText(I.t("{gray}Use {cc}/uh start{gray} or click here to start the game.")) - .hover(new RawText(I.t("Click here to start the game"))) - .command("/uh start") - ); - } - catch (NullPointerException ignored) {} - - if (BROADCAST_SLOW_START_PROGRESS) - { - /// Displayed in the action bar when the slow teleportation is finished but the game not started. - String message = I.t("{lightpurple}Teleportation complete. {gray}The game will start soon..."); - Bukkit.getOnlinePlayers().forEach(player -> ActionBar.sendPermanentMessage(player, message)); - } - } - else - { - startEnvironment(); - startTimer(); - scheduleDamages(); - sendStartupProTips(); - finalizeStart(); - } - }) - - .startTeleportationProcess(slow); - } - - /** - * Finalizes the start of the game, with the slow mode. Removes the fly and ends the start - * (environment, timer...) - * - * @param sender The sender of the {@code /uh start slow go} command - */ - public void finalizeStartSlow(CommandSender sender) - { - if (!slowStartInProgress) - { - sender.sendMessage(I.t("{ce}Please execute {cc}/uh start slow:true{ce} before.")); - return; - } - - if (!slowStartTPFinished) - { - sender.sendMessage(I.t("{ce}Please wait while the players are teleported.")); - return; - } - - // The freeze is removed. - if (!UHConfig.START.SLOW.CAGES.ENABLED.get()) - { - p.getFreezer().setGlobalFreezeState(false, false); - - // The fly is removed to everyone - p.getServer().getOnlinePlayers().stream() - .filter(player -> alivePlayers.contains(player.getUniqueId())) - .forEach(player -> - { - player.setFlying(false); - player.setAllowFlight(false); - } - ); - } - - // The action bar is cleared - if (BROADCAST_SLOW_START_PROGRESS) - { - Bukkit.getOnlinePlayers().forEach(ActionBar::removeMessage); - } - - // The environment is initialized, the game is started. - startEnvironment(); - startTimer(); - scheduleDamages(); - sendStartupProTips(); - finalizeStart(); - - slowStartInProgress = false; - } - - /** - * Initializes the environment at the beginning of the game. - */ - private void startEnvironment() - { - World overworld = UHUtils.getOverworld(); - - if (overworld != null) - { - overworld.setGameRuleValue("doDaylightCycle", (UHConfig.DAYLIGHT_CYCLE.DO.get()).toString()); - overworld.setTime(UHConfig.DAYLIGHT_CYCLE.TIME.get()); - overworld.setStorm(false); - } - - for (World world : Bukkit.getWorlds()) - { - world.setGameRuleValue("keepInventory", Boolean.FALSE.toString()); // Just in case... - world.setGameRuleValue("naturalRegeneration", (UHConfig.GAMEPLAY_CHANGES.NATURAL_REGENERATION.get()).toString()); - world.setDifficulty(Difficulty.HARD); - } - } - - /** - * Launches the timer by launching the task that updates the scoreboard every second. - */ - private void startTimer() - { - if (UHConfig.EPISODES.ENABLED.get()) - { - this.episode = 1; - - // An empty string is used for the name of the main timer, because - // such a name can't be used by players. - UHTimer mainTimer = new UHTimer(""); - mainTimer.setDuration(this.getEpisodeLength()); - - p.getTimerManager().registerMainTimer(mainTimer); - - mainTimer.start(); - } - } - - /** - * Enables the damages 30 seconds (600 ticks) later, the PvP after if needed, and the mobs spawns. - */ - private void scheduleDamages() - { - // When the grace period is over, damages are enabled. - RunTask.later(() -> { - damagesEnabled = true; - - if (UHConfig.START.BROADCAST_GRACE_END.get()) - { - Bukkit.broadcastMessage(I.t("{red}{bold}Warning!{white} The grace period ended, you are now vulnerable.")); - } - }, GRACE_PERIOD); - - // When the peace period is over, PVP is enabled - if (PEACE_PERIOD > 0) - { - Bukkit.getWorlds().forEach(world -> world.setPVP(false)); - - RunTask.later(() -> - { - Bukkit.getWorlds().forEach(world -> world.setPVP(true)); - Bukkit.broadcastMessage(I.t("{red}{bold}Warning!{white} PvP is now enabled.")); - }, PEACE_PERIOD); - } - - // Allows mobs to spawn on the surface after the mobs-free period - RunTask.later(() -> mobsOnSurface = true, SURFACE_MOBS_FREE_PERIOD); - } - - /** - * Sends two ProTips: - * - about the team chat, to all players, 20 seconds after the beginning of the game; - * - about the invincibility, 5 seconds after the beginning of the game. - */ - private void sendStartupProTips() - { - // Team chat - 20 seconds after - if (isGameWithTeams()) - { - Bukkit.getScheduler().runTaskLater(p, () -> getOnlineAlivePlayers().forEach(ProTips.USE_T_COMMAND::sendTo), 400L); - } - - // Invincibility - 5 seconds after - Bukkit.getScheduler().runTaskLater(p, () -> getOnlineAlivePlayers().forEach(ProTips.STARTUP_INVINCIBILITY::sendTo), 100L); - } - - /** - * Changes the state of the game. Also, forces the global freeze start to false, to avoid toggle - * bugs (like inverted state). - */ - private void finalizeStart() - { - p.getFreezer().setGlobalFreezeState(false); - - teleporter.cleanup(); - - gameStarted = true; - gameFinished = false; - - updateAliveCache(); - - // Survival gamemode for everyone - p.getServer().getOnlinePlayers().stream() - .filter(player -> alivePlayers.contains(player.getUniqueId())) - .forEach(player -> - { - player.setGameMode(GameMode.SURVIVAL); - resetPlayer(player); - } - ); - - // Fires the event - p.getServer().getPluginManager().callEvent(new UHGameStartsEvent()); - } - - /** - * Reinitializes a player (health, XP, inventory...). - * - * @param player The player - */ - private void resetPlayer(Player player) - { - player.setHealth(20D); - player.setFoodLevel(20); - player.setSaturation(20); - player.getInventory().clear(); - player.getInventory().setArmorContents(null); - player.setExp(0L); - player.setLevel(0); - player.closeInventory(); - } - - /** - * @return true if the slow start is in progress. - */ - public boolean isSlowStartInProgress() - { - return slowStartInProgress; - } - - /** - * Updates the cached values of the alive players and teams. - */ - public void updateAliveCache() - { - // Alive teams - aliveTeams.clear(); - for (UHTeam t : tm.getTeams()) - { - for (UUID pid : t.getPlayersUUID()) - { - if (!this.isPlayerDead(pid)) aliveTeams.add(t); - } - } - - // Counters - this.alivePlayersCount = alivePlayers.size(); - this.aliveTeamsCount = aliveTeams.size(); - - if (isGameRunning()) - p.getMOTDManager().updateMOTDDuringGame(); - } - - /** - * Updates the cached values of the alive players and teams. - * - * @deprecated Use {@link #updateAliveCache()} instead. - */ - @Deprecated - public void updateAliveCounters() { updateAliveCache(); } - - - /** - * Shifts an episode. - * - * @param shifter The player who shifts the episode, an empty string if the episode is shifted - * because the timer is up. - */ - public void shiftEpisode(String shifter) - { - if (UHConfig.EPISODES.ENABLED.get()) - { - this.episode++; - - final EpisodeChangedCause cause; - if (shifter == null || shifter.equals("")) cause = EpisodeChangedCause.FINISHED; - else cause = EpisodeChangedCause.SHIFTED; - - // Restarts the timer. - // Useless for a normal start (restarted in the event), but needed if the episode was shifted. - if (cause == EpisodeChangedCause.SHIFTED) - { - p.getTimerManager().getMainTimer().start(); - } - - p.getServer().getPluginManager().callEvent(new UHEpisodeChangedEvent(episode, cause, shifter)); - } - } - - /** - * Shift an episode because the timer is up. - */ - public void shiftEpisode() - { - shiftEpisode(""); - } - - - /** - * Resurrects an offline player. The tasks that needed to be executed when the player is online - * are delayed and executed when the player joins. - * - * @param playerName The name of the player to resurrect - * - * @return true if the player was dead, false otherwise. - */ - public boolean resurrect(String playerName) - { - Player playerOnline = Bukkit.getPlayer(playerName); - - if (playerOnline != null && playerOnline.isOnline()) - { - return resurrectPlayerOnlineTask(playerOnline); - } - else - { - // We checks if the player was a player - if (!this.players.contains(playerName)) - { - return false; - } - } - - // So, now, we are sure that the player is really offline. - // The task needed to be executed will be executed when the player join. - this.deadPlayersToBeResurrected.add(playerName); - - return true; - } - - /** - * The things that have to be done in order to resurrect the players and that needs the player - * to be online. - * - * @param player The player to resurrect - * - * @return true if the player was dead, false otherwise. - */ - public boolean resurrectPlayerOnlineTask(Player player) - { - if (alivePlayers.contains(player.getUniqueId())) - { - return false; - } - - // Player registered as alive - alivePlayers.add(player.getUniqueId()); - updateAliveCache(); - - // This method can be used to add a player after the game start. - players.add(player.getName()); - - // Event - p.getServer().getPluginManager().callEvent(new UHPlayerResurrectedEvent(player)); - - return true; - } - - /** - * Returns true if a player need to be resurrected. - * - * @param player - * - * @return - */ - public boolean isDeadPlayersToBeResurrected(Player player) - { - return deadPlayersToBeResurrected.contains(player.getName()); - } - - /** - * Registers a player as resurrected. - * - * @param player - */ - public void markPlayerAsResurrected(Player player) - { - deadPlayersToBeResurrected.remove(player.getName()); - } - - - /** - * This method saves the location of the death of a player. - * - * @param player - * @param location - */ - public void addDeathLocation(Player player, Location location) - { - deathLocations.put(player.getUniqueId(), location); - } - - /** - * This method removes the stored death location. - * - * @param player - */ - public void removeDeathLocation(Player player) - { - deathLocations.remove(player.getUniqueId()); - } - - /** - * This method returns the stored death location. - * - * @param player The player to retrieve the death location of. - * - * @return The death location, or {@code null} if not defined. - */ - public Location getDeathLocation(Player player) - { - if (deathLocations.containsKey(player.getUniqueId())) - { - return deathLocations.get(player.getUniqueId()); - } - - return null; - } - - /** - * This method returns true if a death location is stored for the given player. - * - * @param player The player to check the death location of. - * - * @return {@code true} if a death location is set. - */ - public boolean hasDeathLocation(Player player) - { - return deathLocations.containsKey(player.getUniqueId()); - } - - /** - * Adds a spectator. When the game is started, spectators are ignored and the spectator mode is - * enabled if SpectatorPlus is present. - * - * @param player The player to register as a spectator. - */ - public void addStartupSpectator(OfflinePlayer player) - { - spectators.add(player.getUniqueId()); - tm.removePlayerFromTeam(player); - } - - /** - * Removes a spectator. - * - * @param player The spectator to remove. - */ - public void removeStartupSpectator(OfflinePlayer player) - { - spectators.remove(player.getUniqueId()); - } - - /** - * Returns a list of the current registered spectators. - * - * This returns only a list of the <em>initial</em> spectators. Use {@link #getAlivePlayers()} - * to get the alive players, and remove the elements of this list from the online players to get - * the spectators. - * - * @return The initial spectators. - */ - public HashSet<String> getStartupSpectators() - { - HashSet<String> spectatorNames = new HashSet<>(); - - for (UUID id : spectators) - { - final OfflinePlayer player = OfflinePlayersLoader.getOfflinePlayer(id); - final String playerName = player.getName(); - - if (playerName != null) - spectatorNames.add(playerName); - else - /// Spectators list item if the nick cannot be found - spectatorNames.add(I.t("Unknown player with UUID {0}", player.getUniqueId())); - } - - return spectatorNames; - } - - /** - * @return true if the game was launched and is not finished. - */ - public boolean isGameRunning() - { - return gameStarted && !gameFinished; - } - - /** - * @return true if the game is started. - */ - public boolean isGameStarted() - { - return gameStarted; - } - - /** - * @return true if the game is finished. - */ - public boolean isGameFinished() - { - return gameFinished; - } - - /** - * Registers the state of the game. - * - * @param finished If true, the game will be marked as finished. - */ - public void setGameFinished(boolean finished) - { - gameFinished = finished; - } - - /** - * @return true if the game is a game with teams, and false if the game is a solo game. - */ - public boolean isGameWithTeams() - { - return gameWithTeams; - } - - /** - * @return true if damages are enabled. Damages are enabled 30 seconds after the beginning of - * the game. - */ - public boolean isTakingDamage() - { - return damagesEnabled; - } - - public boolean isSurfaceSpawnEnabled() - { - return mobsOnSurface; - } - - /** - * Returns true if the given player is dead. - * - * @param player The player. - * - * @return True if the player is dead. - */ - public boolean isPlayerDead(Player player) - { - return !alivePlayers.contains(player.getUniqueId()); - } - - /** - * Returns true if the given player is dead. - * - * @param player The UUID of the player. - * - * @return True if the player is dead. - */ - public boolean isPlayerDead(UUID player) - { - return !alivePlayers.contains(player); - } - - /** - * Registers a player as dead. - * - * @param player The player to mark as dead. - */ - public void addDead(Player player) - { - alivePlayers.remove(player.getUniqueId()); - updateAliveCache(); - } - - /** - * Registers a player as dead. - * - * @param player The UUID of the player to mark as dead. - */ - public void addDead(UUID player) - { - alivePlayers.remove(player); - updateAliveCache(); - } - - - /** - * Broadcasts the winner(s) of the game and launches some fireworks - * - * @throws IllegalStateException if the game is not started or not finished (use the message to - * distinguish these cases, {@link #FINISH_ERROR_NOT_STARTED} or - * {@link #FINISH_ERROR_NOT_FINISHED}). - */ - public void finishGame() - { - if (!p.getGameManager().isGameStarted()) - { - throw new IllegalStateException(FINISH_ERROR_NOT_STARTED); - } - - if (p.getGameManager().getAliveTeamsCount() != 1) - { - throw new IllegalStateException(FINISH_ERROR_NOT_FINISHED); - } - - // There's only one team. - UHTeam winnerTeam = p.getGameManager().getAliveTeams().iterator().next(); - Set<OfflinePlayer> listWinners = winnerTeam.getPlayers(); - - if (UHConfig.FINISH.MESSAGE.get()) - { - if (isGameWithTeams()) - { - StringBuilder winners = new StringBuilder(); - int j = 0; - - for (OfflinePlayer winner : listWinners) - { - if (j != 0) - { - if (j == listWinners.size() - 1) - { - /// The "and" in the winners players list (like "player1, player2 and player3"). - winners.append(" ").append(I.tc("winners_list", "and")).append(" "); - } - else - { - winners.append(", "); - } - } - - winners.append(winner.getName()); - j++; - } - - p.getServer().broadcastMessage(I.t("{darkgreen}{obfuscated}--{green} Congratulations to {0} (team {1}{green}) for their victory! {darkgreen}{obfuscated}--", winners.toString(), winnerTeam.getDisplayName())); - } - else - { - p.getServer().broadcastMessage(I.t("{darkgreen}{obfuscated}--{green} Congratulations to {0} for his victory! {darkgreen}{obfuscated}--", winnerTeam.getName())); - } - } - - if (UHConfig.FINISH.TITLE.get()) - { - final String title; - final String subtitle; - - if (isGameWithTeams()) - { - /// The main title of the /title displayed when a team wins the game. {0} becomes the team display name (with colors). - title = I.t("{darkgreen}{0}", winnerTeam.getDisplayName()); - /// The subtitle of the /title displayed when a team wins the game. {0} becomes the team display name (with colors). - subtitle = I.t("{green}This team wins the game!", winnerTeam.getDisplayName()); - } - else - { - /// The main title of the /title displayed when a player wins the game (in solo). {0} becomes the player display name (with colors). - title = I.t("{darkgreen}{0}", winnerTeam.getDisplayName()); - /// The subtitle of the /title displayed when a player wins the game (in solo). {0} becomes the player display name (with colors). - subtitle = I.t("{green}wins the game!", winnerTeam.getDisplayName()); - } - - Titles.broadcastTitle(5, 142, 21, title, subtitle); - } - - if (UHConfig.FINISH.FIREWORKS.ENABLED.get()) - { - new FireworksOnWinnersTask(listWinners).runTaskTimer(p, 0L, 15L); - } - } - - /** - * Returns the names of the players of this game. - * - * @return The set. - */ - public Set<String> getPlayers() - { - return players; - } - - /** - * Returns a list of the currently alive teams. - * - * @return The set. - */ - public Set<UHTeam> getAliveTeams() - { - return aliveTeams; - } - - /** - * Returns a list of the currently alive players. - * - * @return The set. - */ - public Set<OfflinePlayer> getAlivePlayers() - { - return alivePlayers.stream() - .map(id -> p.getServer().getOfflinePlayer(id)) - .collect(Collectors.toCollection(HashSet::new)); - } - - /** - * Returns a list of the currently alive and online players. - * - * @return The list. - */ - public HashSet<Player> getOnlineAlivePlayers() - { - return alivePlayers.stream() - .map(id -> p.getServer().getPlayer(id)) - .filter(Objects::nonNull) - .filter(Player::isOnline) - .collect(Collectors.toCollection(HashSet::new)); - } - - /** - * @return the death sound, or null if no death sound is registered. - */ - public UHSound getDeathSound() - { - return DEATH_SOUND; - } - - /** - * @return the length of one episode, in seconds. - */ - public Integer getEpisodeLength() - { - return UHUtils.string2Time(UHConfig.EPISODES.LENGTH.get(), 20*60); - } - - /** - * @return the (cached) number of alive players. - */ - public Integer getAlivePlayersCount() - { - return alivePlayersCount; - } - - /** - * @return the (cached) number of alive teams. - */ - public Integer getAliveTeamsCount() - { - return aliveTeamsCount; - } - - /** - * @return the number of the current episode. - */ - public Integer getEpisode() - { - return episode; - } - - - /** - * @return the teleporter instance used to start the game, containing the spawn points of each - * player. - */ - public Teleporter getTeleporter() - { - return teleporter; - } - - - - /* *** Deprecated methods *** */ - - /** - * Adds a spectator. When the game is started, spectators are ignored and the spectator mode is - * enabled if SpectatorPlus is present. - * - * @param player The player to register as a spectator. - * - * @deprecated Use {@link #addStartupSpectator(OfflinePlayer)} instead. - */ - @Deprecated - public void addSpectator(Player player) - { - addStartupSpectator(player); - } - - /** - * Removes a spectator. - * - * @param player The player to remove. - * - * @deprecated Use {@link #removeStartupSpectator(OfflinePlayer)} instead. - */ - @Deprecated - public void removeSpectator(Player player) - { - removeStartupSpectator(player); - } - - /** - * Returns a list of the current registered spectators. - * - * This returns only a list of the <em>initial</em> spectators. Use {@link #getAlivePlayers()} - * to get the alive players, and remove the elements of this list from the online players to get - * the spectators. - * - * @return The initial spectators. - * @deprecated Use {@link #getStartupSpectators()} instead. - */ - @Deprecated - public HashSet<String> getSpectators() - { - return getStartupSpectators(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java b/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java deleted file mode 100644 index 2b352d8..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * 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.gui.teams; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.gui.teams.builder.TeamBuilderStepColorGUI; -import eu.carrade.amaury.UHCReloaded.gui.teams.editor.TeamEditGUI; -import eu.carrade.amaury.UHCReloaded.teams.TeamManager; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.ColorsUtils; -import fr.zcraft.zlib.components.gui.ExplorerGui; -import fr.zcraft.zlib.components.gui.Gui; -import fr.zcraft.zlib.components.gui.GuiAction; -import fr.zcraft.zlib.components.gui.GuiUtils; -import fr.zcraft.zlib.components.gui.PromptGui; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.items.ItemStackBuilder; -import org.bukkit.DyeColor; -import org.bukkit.Material; -import org.bukkit.OfflinePlayer; -import org.bukkit.inventory.ItemStack; - -import java.util.ArrayList; -import java.util.List; - - -public class TeamsSelectorGUI extends ExplorerGui<UHTeam> -{ - private final String TEAM_ITEM_TYPE; - private final boolean GLOW_ON_CURRENT_TEAM; - - private final TeamManager tm = UHCReloaded.get().getTeamManager(); - - public TeamsSelectorGUI() - { - TEAM_ITEM_TYPE = UHConfig.TEAMS_OPTIONS.CHEST_GUI.DISPLAY.TEAM_ITEM.get().toLowerCase(); - GLOW_ON_CURRENT_TEAM = UHConfig.TEAMS_OPTIONS.CHEST_GUI.DISPLAY.GLOW_ON_SELECTED_TEAM.get(); - } - - @Override - protected void onUpdate() - { - /// The title of the teams selector GUI. {0} = teams count. - setTitle(I.t("{black}Select a team {reset}({0})", tm.getTeams().size())); - setData(tm.getTeams().toArray(new UHTeam[tm.getTeams().size()])); - - setMode(Mode.READONLY); - setKeepHorizontalScrollingSpace(true); - - if (getPlayer().hasPermission("uh.player.renameTeam")) - { - int renameSlot = getPlayer().hasPermission("uh.team") ? getSize() - 6 : getSize() - 5; - - action("rename", renameSlot, GuiUtils.makeItem( - /// The title of a button to rename our team, in the selector GUI. - Material.BOOK_AND_QUILL, I.t("{white}Rename your team"), - /// Warning displayed in the "Rename your team" button, if the player is not in a team - tm.getTeamForPlayer(getPlayer()) == null ? GuiUtils.generateLore(I.t("{gray}You have to be in a team")) : null - )); - } - - if (getPlayer().hasPermission("uh.team")) - { - int newTeamSlot = getPlayer().hasPermission("uh.player.renameTeam") ? getSize() - 4 : getSize() - 5; - - /// The title of a button to create a new team, in the selector GUI. - action("new", newTeamSlot, GuiUtils.makeItem(Material.EMERALD, I.t("{white}New team"))); - } - } - - @Override - protected ItemStack getViewItem(UHTeam team) - { - final boolean playerInTeam = team.getPlayersUUID().contains(getPlayer().getUniqueId()); - - - // Lore - final List<String> lore = new ArrayList<>(); - - lore.add(""); - - if (team.getSize() != 0) - { - /// The "Players" title in the selector GUI, on a team's tooltip - lore.add(I.t("{blue}Players")); - for (OfflinePlayer player : team.getPlayers()) - { - /// An item of the players list in the selector GUI, on a team's tooltip - lore.add(I.t("{darkgray}- {white}{0}", player.getName())); - } - - lore.add(""); - } - - if (getPlayer().hasPermission("uh.player.join.self") && !playerInTeam) - { - if (!team.isFull()) - { - lore.add(I.t("{darkgray}» {white}Click {gray}to join this team")); - } - else - { - lore.add(I.t("{darkgray}» {red}This team is full")); - } - } - else if (getPlayer().hasPermission("uh.player.leave.self") && playerInTeam) - { - lore.add(I.t("{darkgray}» {white}Click {gray}to leave this team")); - } - - if (getPlayer().hasPermission("uh.team")) // TODO adapt with new granular permissions - { - lore.add(I.t("{darkgray}» {white}Right-click {gray}to manage this team")); - } - - - // Item - final ItemStack item; - final DyeColor dye = ColorsUtils.chat2Dye(team.getColorOrWhite().toChatColor()); - - switch (TEAM_ITEM_TYPE) - { - case "banner": - item = team.getBanner(); - break; - - case "clay": - item = new ItemStack(Material.STAINED_CLAY, 1, dye.getWoolData()); - break; - - case "glass": - item = new ItemStack(Material.STAINED_GLASS_PANE, 1, dye.getWoolData()); - break; - - case "glass_pane": - item = new ItemStack(Material.STAINED_GLASS_PANE, 1, dye.getWoolData()); - break; - - case "dye": - item = new ItemStack(Material.INK_SACK, 1, dye.getDyeData()); - break; - - default: - item = new ItemStack(Material.WOOL, 1, dye.getWoolData()); - } - - - // Title - final String title = tm.getMaxPlayersPerTeam() != 0 - /// Title of the team item in the teams selector GUI (with max). {0}: team display name. {1}: players count. {2}: max count. - ? I.t("{white}Team {0} {gray}({1}/{2})", team.getDisplayName(), team.getSize(), tm.getMaxPlayersPerTeam()) - /// Title of the team item in the teams selector GUI (without max) {0}: team display name. {1}: players count. - : I.tn("{white}Team {0} {gray}({1} player)", "{white}Team {0} {gray}({1} players)", team.getSize(), team.getDisplayName(), team.getSize()); - - return new ItemStackBuilder(item) - .title(title) - .lore(lore) - .glow(GLOW_ON_CURRENT_TEAM && playerInTeam) - .hideAttributes() - .item(); - } - - @Override - protected ItemStack getEmptyViewItem() - { - return new ItemStackBuilder(Material.BARRIER) - .title(I.t("{red}No team created")) - .lore(getPlayer().hasPermission("uh.team") - /// Subtitle of the item displayed in the teams selector GUI if there isn't anything to display. - ? GuiUtils.generateLore(I.t("{gray}Click the emerald button below to create one.")) - /// Subtitle of the item displayed in the teams selector GUI if there isn't anything to display and the player cannot create a team. - : GuiUtils.generateLore(I.t("{gray}Wait for an administrator to create one."))) - .hideAttributes() - .item(); - } - - @Override - protected ItemStack getPickedUpItem(UHTeam team) - { - final boolean playerInTeam = team.getPlayersUUID().contains(getPlayer().getUniqueId()); - - if (getPlayer().hasPermission("uh.player.join.self") && !playerInTeam) - { - try - { - team.addPlayer(getPlayer()); - } - catch (RuntimeException ignored) {} // team full, does nothing - } - else if (getPlayer().hasPermission("uh.player.leave.self") && playerInTeam) - { - team.removePlayer(getPlayer()); - } - - update(); - return null; - } - - @Override - protected void onRightClick(UHTeam team) - { - if (getPlayer().hasPermission("uh.team")) // TODO adapt with new granular permissions - { - Gui.open(getPlayer(), new TeamEditGUI(team), this); - } - else - { - getPickedUpItem(team); - } - } - - @GuiAction ("rename") - public void rename() - { - final UHTeam team = tm.getTeamForPlayer(getPlayer()); - if (team == null) return; - - Gui.open(getPlayer(), new PromptGui(team::setName, team.getName()), this); - } - - @GuiAction ("new") - public void newTeam() - { - Gui.open(getPlayer(), new TeamBuilderStepColorGUI()); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderBaseGUI.java b/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderBaseGUI.java deleted file mode 100644 index d23acc0..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderBaseGUI.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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.gui.teams.builder; - -import eu.carrade.amaury.UHCReloaded.teams.TeamColor; -import eu.carrade.amaury.UHCReloaded.utils.TextUtils; -import fr.zcraft.zlib.components.gui.ActionGui; -import fr.zcraft.zlib.components.gui.GuiUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.ChatColor; -import org.bukkit.DyeColor; -import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; - -import java.util.Collections; - - -/** - * The base of the team creator GUIs: contains the breadcrumb generator. - */ -public abstract class TeamBuilderBaseGUI extends ActionGui -{ - protected void generateBreadcrumbs(BuildingStep step) - { - for (int i = 0; i < 9; i++) - { - if (i != 1 && i != 4 && i != 7) - { - action("", i, GuiUtils.makeItem(new ItemStack(Material.STAINED_GLASS_PANE, 1, DyeColor.WHITE.getWoolData()), ChatColor.RESET + " ", null)); - } - else - { - final BuildingStep slotStep; - final String achievedSubtitle; - - if (i == 1) - { - slotStep = BuildingStep.COLOR; - achievedSubtitle = getColor() != null ? (getColor() == TeamColor.RANDOM ? ChatColor.WHITE + "" + ChatColor.MAGIC + "Random color" : getColor().toChatColor() + TextUtils.friendlyEnumName(getColor())) : ""; - } - else if (i == 4) - { - slotStep = BuildingStep.NAME; - achievedSubtitle = getName() != null ? ChatColor.GRAY + getName() : ""; - } - else - { - slotStep = BuildingStep.PLAYERS; - achievedSubtitle = ""; // Never displayed as achieved: it's the last one. - } - - final boolean achieved = slotStep.isAchieved(step); - - action("", i, GuiUtils.makeItem( - new ItemStack(Material.STAINED_GLASS_PANE, 1, achieved ? DyeColor.LIME.getWoolData() : DyeColor.RED.getWoolData()), - slotStep.getName(), - achieved ? Collections.singletonList(achievedSubtitle) : null - )); - } - } - } - - /** - * @return the selected color. {@code null} if not selected yet. - */ - protected abstract TeamColor getColor(); - - /** - * @return the chosen name. {@code null} if not chosen yet. - */ - protected abstract String getName(); - - - /** - * The current step used by {@link #generateBreadcrumbs(BuildingStep)} - */ - protected enum BuildingStep - { - /// The title of the first step in the team creator GUIs - COLOR (I.t("{gray}1. {white}{bold}Team color")), - /// The title of the second step in the team creator GUIs - NAME (I.t("{gray}2. {white}{bold}Team name")), - /// The title of the third step in the team creator GUIs - PLAYERS (I.t("{gray}3. {white}{bold}Team members")); - - - private final String name; - - BuildingStep(String name) - { - this.name = name; - } - - public String getName() - { - return name; - } - - /** - * Checks if this step is achieved, at the given step. - * - * @param step The current step. - * @return {@code true} if achieved. - */ - public boolean isAchieved(BuildingStep step) - { - return step.ordinal() > this.ordinal(); - } - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepColorGUI.java b/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepColorGUI.java deleted file mode 100644 index 1faf91c..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepColorGUI.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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.gui.teams.builder; - -import eu.carrade.amaury.UHCReloaded.teams.TeamColor; -import eu.carrade.amaury.UHCReloaded.utils.ColorsUtils; -import eu.carrade.amaury.UHCReloaded.utils.TextUtils; -import fr.zcraft.zlib.components.gui.Gui; -import fr.zcraft.zlib.components.gui.GuiAction; -import fr.zcraft.zlib.components.gui.GuiUtils; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.items.ItemStackBuilder; -import fr.zcraft.zlib.tools.runners.RunTask; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitTask; - -import java.util.Random; - - -public class TeamBuilderStepColorGUI extends TeamBuilderBaseGUI -{ - private final Random randomSource = new Random(); - - private BukkitTask randomUpdate = null; - - - @Override - protected void onUpdate() - { - /// The title of the color selector GUI, in the create team GUIs - setTitle(I.t("New team » {black}Color")); - setSize(6 * 9); - - generateBreadcrumbs(BuildingStep.COLOR); - - insertColors(3); - } - - protected void insertColors(final int firstLine) - { - final int offset = (firstLine - 1) * 9; - - /// The random color button in a colors selector GUI. - action("random", offset + 4, GuiUtils.makeItem(Material.WOOL, I.t("{lightpurple}Random color"))); - - insertColor(offset + 10, ChatColor.WHITE); - insertColor(offset + 11, ChatColor.AQUA); - insertColor(offset + 12, ChatColor.BLUE); - insertColor(offset + 13, ChatColor.GREEN); - insertColor(offset + 14, ChatColor.YELLOW); - insertColor(offset + 15, ChatColor.GOLD); - insertColor(offset + 16, ChatColor.LIGHT_PURPLE); - - insertColor(offset + 19, ChatColor.RED); - insertColor(offset + 20, ChatColor.DARK_RED); - insertColor(offset + 21, ChatColor.DARK_GREEN); - insertColor(offset + 22, ChatColor.DARK_PURPLE); - insertColor(offset + 23, ChatColor.DARK_BLUE); - insertColor(offset + 24, ChatColor.DARK_AQUA); - insertColor(offset + 25, ChatColor.BLACK); - - insertColor(offset + 29, ChatColor.GRAY); - insertColor(offset + 33, ChatColor.DARK_GRAY); - - randomUpdate = RunTask.timer(() -> - { - ItemStack random = getInventory().getItem(offset + 4); - if (random != null) - random.setDurability((short) randomSource.nextInt(16)); - }, 15L, 15L); - } - - private void insertColor(int slot, ChatColor color) - { - action( - "", - slot, - new ItemStackBuilder(Material.WOOL) - .data(ColorsUtils.chat2Dye(color).getWoolData()) - .title(color, TextUtils.friendlyEnumName(color)) - .item() - ); - } - - - @GuiAction ("random") - protected void random() - { - saveColor(TeamColor.RANDOM); - } - - @Override - protected void unknown_action(String name, int slot, ItemStack item) - { - if (item.hasItemMeta() && item.getItemMeta().hasDisplayName()) - saveColor(TeamColor.fromChatColor(ChatColor.getByChar(ChatColor.getLastColors(item.getItemMeta().getDisplayName()).substring(1)))); - } - - protected void saveColor(TeamColor color) - { - Gui.open(getPlayer(), new TeamBuilderStepNameGUI(color)); - } - - @Override - protected void onClose() - { - if (randomUpdate != null) - { - randomUpdate.cancel(); - randomUpdate = null; - } - - super.onClose(); - } - - @Override - protected TeamColor getColor() { return null; } - - @Override - protected String getName() { return null; } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepNameGUI.java b/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepNameGUI.java deleted file mode 100644 index bc488dc..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepNameGUI.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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.gui.teams.builder; - -import eu.carrade.amaury.UHCReloaded.teams.TeamColor; -import fr.zcraft.zlib.components.gui.Gui; -import fr.zcraft.zlib.components.gui.GuiAction; -import fr.zcraft.zlib.components.gui.GuiUtils; -import fr.zcraft.zlib.components.gui.PromptGui; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Material; - - -public class TeamBuilderStepNameGUI extends TeamBuilderBaseGUI -{ - private final TeamColor color; - - public TeamBuilderStepNameGUI(TeamColor color) - { - this.color = color; - } - - @Override - protected void onUpdate() - { - /// The title of the name selector GUI, in the create team GUIs - setTitle(I.t("New team » {black}Name")); - setSize(6 * 9); - - generateBreadcrumbs(BuildingStep.NAME); - - action("name", 22, GuiUtils.makeItem( - Material.BOOK_AND_QUILL, - /// The title of the button opening the sign to write the team name (creator GUIs) - I.t("{white}Name the team"), - /// The legend of the button opening the sign to write the team name (creator GUIs) - GuiUtils.generateLore(I.t("{gray}When clicked, a sign will open; write the name of the team inside.")) - )); - } - - @GuiAction ("name") - protected void name() - { - Gui.open(getPlayer(), new PromptGui(name -> - { - if (name.trim().isEmpty()) - Gui.open(getPlayer(), new TeamBuilderStepNameGUI(getColor())); - else - Gui.open(getPlayer(), new TeamBuilderStepPlayersGUI(getColor(), name)); - })); - } - - - @Override - protected TeamColor getColor() { return color; } - - @Override - protected String getName() { return null; } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java b/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java deleted file mode 100644 index 23285d9..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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.gui.teams.builder; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.gui.teams.TeamsSelectorGUI; -import eu.carrade.amaury.UHCReloaded.misc.OfflinePlayersLoader; -import eu.carrade.amaury.UHCReloaded.teams.TeamColor; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.OfflinePlayersComparator; -import eu.carrade.amaury.UHCReloaded.utils.TextUtils; -import fr.zcraft.zlib.components.gui.Gui; -import fr.zcraft.zlib.components.gui.GuiAction; -import fr.zcraft.zlib.components.gui.GuiUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.OfflinePlayer; -import org.bukkit.SkullType; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.SkullMeta; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import java.util.UUID; - - -public class TeamBuilderStepPlayersGUI extends TeamBuilderBaseGUI -{ - private final TeamColor color; - private final String name; - - private final Set<UUID> teamMembers = new HashSet<>(); - - - public TeamBuilderStepPlayersGUI(TeamColor color, String name) - { - this.color = color; - this.name = name; - } - - @Override - protected void onUpdate() - { - /// The title of the members selector GUI, in the create team GUIs - setTitle(I.t("New team » {black}Members")); - setSize(6 * 9); - - generateBreadcrumbs(BuildingStep.PLAYERS); - - - // Players - - final Set<OfflinePlayer> players = new TreeSet<>(new OfflinePlayersComparator()); - players.addAll(OfflinePlayersLoader.getOfflinePlayers()); - - int slot = 9; - for (OfflinePlayer player : players) - { - action(player.getUniqueId().toString(), slot, generatePlayerButton(player)); - - if (slot < 44) slot++; - else break; - } - - - // Done button - - final List<String> lore = new ArrayList<>(); - lore.add(""); - - /// The summary title in the final « create the team » button of the create team GUIs - lore.add(I.t("{blue}{bold}Summary")); - - /// The team name in the final « create the team » button of the create team GUIs - lore.add(I.t("{gray}Team name: {white}{0}", getName())); - - /// The team color in the final « create the team » button of the create team GUIs - lore.add(I.t("{gray}Color: {0}", getColor() == TeamColor.RANDOM ? ChatColor.MAGIC + "Random" : getColor().toChatColor() + TextUtils.friendlyEnumName(getColor()))); - - /// The team members count in the final « create the team » button of the create team GUIs - lore.add(I.t("{gray}Members: {white}{0}", teamMembers.size())); - lore.add(""); - - for (UUID teamMember : teamMembers) - { - OfflinePlayer player = Bukkit.getOfflinePlayer(teamMember); - /// A member bullet in the final « create the team » button of the create team GUIs - lore.add(I.t("{darkgray}- {white}{0}", player != null ? player.getName() : teamMember)); - } - - /// The title of the final « create the team » button of the create team GUIs - action("done", getSize() - 5, GuiUtils.makeItem(Material.EMERALD, I.t("{green}Create the team"), lore)); - } - - private ItemStack generatePlayerButton(OfflinePlayer player) - { - ItemStack button = new ItemStack(Material.SKULL_ITEM, 1, (short) SkullType.PLAYER.ordinal()); - SkullMeta meta = (SkullMeta) button.getItemMeta(); - - String displayName = player instanceof Player ? ((Player) player).getDisplayName() : player.getName(); - UHTeam team = UHCReloaded.get().getTeamManager().getTeamForPlayer(player); - - meta.setOwner(player.getName()); - /// The title of a button to select a player (a skull button). {0} = player's display name. - meta.setDisplayName(I.t("{reset}{0}", displayName)); - meta.setLore(Arrays.asList( - player.isOnline() ? I.t("{gray}Online") : I.t("{gray}Offline"), - team != null ? I.t("{gray}Current team: {0}", team.getDisplayName()) : I.t("{gray}Current team: none"), - "", - teamMembers.contains(player.getUniqueId()) ? I.t("{lightpurple}Selected!") : I.t("{darkgray}» {white}Click {gray}to add to the team") - )); - - button.setItemMeta(meta); - return button; - } - - - @Override - protected void unknown_action(String name, int slot, ItemStack item) - { - UUID playerUUID; - try { playerUUID = UUID.fromString(name); } catch(IllegalArgumentException e) { return; } - - if (teamMembers.contains(playerUUID)) - teamMembers.remove(playerUUID); - else - teamMembers.add(playerUUID); - - update(); - } - - @GuiAction ("done") - protected void done() - { - UHTeam team = new UHTeam(getName(), getColor()); - - try - { - UHCReloaded.get().getTeamManager().addTeam(team); - getPlayer().sendMessage(I.t("{cs}Team created.")); - - teamMembers.stream().map(OfflinePlayersLoader::getOfflinePlayer).forEach(team::addPlayer); - } - catch (IllegalArgumentException e) - { - getPlayer().sendMessage(I.t("{ce}This team already exists.")); - } - - Gui.open(getPlayer(), new TeamsSelectorGUI()); - } - - - @Override - protected TeamColor getColor() { return color; } - - @Override - protected String getName() { return name; } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamActionGUI.java b/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamActionGUI.java deleted file mode 100644 index 92a432a..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamActionGUI.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.gui.teams.editor; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import fr.zcraft.zlib.components.gui.ActionGui; -import fr.zcraft.zlib.components.gui.GuiUtils; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.items.ItemStackBuilder; -import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; - - -public abstract class TeamActionGUI extends ActionGui -{ - protected final UHTeam team; - - public TeamActionGUI(UHTeam team) - { - this.team = team; - } - - /** - * Checks if the team still exists. - * @return {@code true} if the team exists. - */ - protected boolean exists() - { - return UHCReloaded.get().getTeamManager().isTeamRegistered(team); - } - - /** - * Generates the item to display if the team was deleted while a player edited the team on a GUI. - * @return the item. - */ - protected ItemStack getDeletedItem() - { - return new ItemStackBuilder(Material.BARRIER) - /// Title of the item displayed if a team was deleted while someone edited it in a GUI. - .title(I.t("{red}Team deleted")) - /// Lore of the item displayed if a team was deleted while someone edited it in a GUI. - .lore(GuiUtils.generateLore(I.t("{gray}The team {0}{gray} was deleted by another player.", team.getDisplayName()))) - .lore("") - /// Lore of the item displayed if a team was deleted while someone edited it in a GUI. - .lore(GuiUtils.generateLore(I.t("{gray}Press {white}Escape{gray} to go back to the teams list."))) - .hideAttributes() - .item(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditDeleteGUI.java b/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditDeleteGUI.java deleted file mode 100644 index 0a6910d..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditDeleteGUI.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.gui.teams.editor; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.gui.teams.TeamsSelectorGUI; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import fr.zcraft.zlib.components.gui.Gui; -import fr.zcraft.zlib.components.gui.GuiAction; -import fr.zcraft.zlib.components.gui.GuiUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.DyeColor; -import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; - - -public class TeamEditDeleteGUI extends TeamActionGUI -{ - public TeamEditDeleteGUI(UHTeam team) - { - super(team); - } - - - @Override - protected void onUpdate() - { - /// The title of the delete team GUI. {0} = team name (raw). - setTitle(I.t("{0} » {darkred}Delete", team.getName())); - setSize(9); - - if (!exists()) - { - action("", 4, getDeletedItem()); - return; - } - - for (int slot = 0; slot < 3; slot++) - { - action("keep", slot, GuiUtils.makeItem( - new ItemStack(Material.STAINED_GLASS_PANE, 1, DyeColor.LIME.getWoolData()), - /// The title of the "keep" button in the delete team GUI - I.t("{green}Keep this team alive"), - null - )); - } - - action("", 4, team.getBanner()); - - for (int slot = 6; slot < 9; slot++) - { - action("delete", slot, GuiUtils.makeItem( - new ItemStack(Material.STAINED_GLASS_PANE, 1, DyeColor.RED.getWoolData()), - /// The title of the "delete" button in the delete team GUI - I.t("{red}Delete this team {italic}forever"), - null - )); - } - } - - - @GuiAction ("keep") - protected void keep() - { - close(); - } - - @GuiAction ("delete") - protected void delete() - { - UHCReloaded.get().getTeamManager().removeTeam(team); - Gui.open(getPlayer(), new TeamsSelectorGUI()); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java b/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java deleted file mode 100644 index a8af539..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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.gui.teams.editor; - -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.ColorsUtils; -import eu.carrade.amaury.UHCReloaded.utils.TextUtils; -import fr.zcraft.zlib.components.gui.Gui; -import fr.zcraft.zlib.components.gui.GuiAction; -import fr.zcraft.zlib.components.gui.GuiUtils; -import fr.zcraft.zlib.components.gui.PromptGui; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.items.ItemStackBuilder; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.OfflinePlayer; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.inventory.ItemStack; - -import java.util.ArrayList; -import java.util.List; - - -public class TeamEditGUI extends TeamActionGUI -{ - public TeamEditGUI(UHTeam team) - { - super(team); - } - - - @Override - protected void onUpdate() - { - /// The title of the edit team GUI. {0} = team display name. - setTitle(I.t("Teams » {black}{0}", team.getDisplayName())); - setSize(36); - - if (!exists()) - { - action("", 13, getDeletedItem()); - return; - } - - // Banner - action("banner", 9, new ItemStackBuilder(team.getBanner()) - .title(team.getDisplayName()) - /// Members count in the banner description, in the team edit GUI. - .lore(GuiUtils.generateLore(I.tn("{white}{0} {gray}member", "{white}{0} {gray}members", team.getSize(), team.getSize()))) - .lore(" ") - .lore(GuiUtils.generateLore(I.t("{white}Click with a banner {gray}to update this team's banner"))) - .hideAttributes() - ); - - // Color - action("color", 11, GuiUtils.makeItem( - new ItemStack(Material.WOOL, 1, ColorsUtils.chat2Dye(team.getColorOrWhite().toChatColor()).getWoolData()), - /// Update team color button in edit GUI. - I.t("{green}Update the color"), - /// Current team color in edit GUI. {0} = formatted color name. - GuiUtils.generateLore(I.tc("current_team_color", "{gray}Current: {white}{0}", team.getColorOrWhite().toChatColor() + TextUtils.friendlyEnumName(team.getColorOrWhite()))) - )); - - // Name - action("name", 13, GuiUtils.makeItem( - Material.BOOK_AND_QUILL, - /// Rename team button in edit GUI. - I.t("{green}Rename the team"), - /// Current team name in edit GUI. {0} = raw team name. - GuiUtils.generateLore(I.tc("current_team_name", "{gray}Current: {white}{0}", team.getName())) - )); - - // Members - List<String> lore = new ArrayList<>(); - for (OfflinePlayer player : team.getPlayers()) - if (player.isOnline()) - lore.add(I.t("{green} • ") + ChatColor.RESET + player.getName()); - else - lore.add(I.t("{red} • ") + ChatColor.RESET + player.getName()); - - action("members", 15, GuiUtils.makeItem( - new ItemStack(Material.SKULL_ITEM, 1, (short) 3), - /// Update team members button in edit GUI. - I.t("{green}Add or remove players"), - lore - )); - - // Delete - action("delete", 17, GuiUtils.makeItem( - Material.BARRIER, - /// Delete team button in edit GUI. - I.t("{red}Delete this team"), - /// Warning under the "delete team" button title. - GuiUtils.generateLore(I.t("{gray}Cannot be undone")) - )); - - // Exit - action("exit", getSize() - 5, GuiUtils.makeItem( - Material.EMERALD, - /// Go back button in GUIs. - I.t("{green}« Go back") - )); - } - - - @GuiAction ("banner") - protected void banner(InventoryClickEvent ev) - { - if (ev.getCursor() != null && ev.getCursor().getType() == Material.BANNER) - { - team.setBanner(ev.getCursor()); - update(); - } - } - - @GuiAction ("color") - protected void color() - { - Gui.open(getPlayer(), new TeamEditColorGUI(team), this); - } - - @GuiAction ("name") - protected void name() - { - Gui.open(getPlayer(), new PromptGui(name -> - { - if (!name.trim().isEmpty()) team.setName(name); - }, team.getName()), this); - } - - @GuiAction ("members") - protected void members() - { - Gui.open(getPlayer(), new TeamEditMembersGUI(team), this); - } - - @GuiAction ("delete") - protected void delete() - { - Gui.open(getPlayer(), new TeamEditDeleteGUI(team), this); - } - - @GuiAction ("exit") - protected void exit() - { - close(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditMembersGUI.java b/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditMembersGUI.java deleted file mode 100644 index 68f89b7..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditMembersGUI.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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.gui.teams.editor; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.misc.OfflinePlayersLoader; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.OfflinePlayersComparator; -import fr.zcraft.zlib.components.gui.ExplorerGui; -import fr.zcraft.zlib.components.gui.GuiAction; -import fr.zcraft.zlib.components.gui.GuiUtils; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.items.ItemStackBuilder; -import org.bukkit.Material; -import org.bukkit.OfflinePlayer; -import org.bukkit.SkullType; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.SkullMeta; - -import java.util.Set; -import java.util.TreeSet; - - -public class TeamEditMembersGUI extends ExplorerGui<OfflinePlayer> -{ - private final UHTeam team; - - public TeamEditMembersGUI(UHTeam team) - { - this.team = team; - } - - - @Override - protected void onUpdate() - { - /// The title of the edit team members GUI. {0} = team name (raw). - setTitle(I.t("{0} » {black}Members", team.getName())); - setKeepHorizontalScrollingSpace(true); - - final Set<OfflinePlayer> players = new TreeSet<>(new OfflinePlayersComparator()); - players.addAll(OfflinePlayersLoader.getOfflinePlayers()); - setData(players.toArray(new OfflinePlayer[0])); - - action("back", getSize() - 5, GuiUtils.makeItem( - Material.EMERALD, - I.t("{green}« Go back") - )); - } - - @Override - protected ItemStack getViewItem(OfflinePlayer player) - { - final String displayName = player instanceof Player ? ((Player) player).getDisplayName() : player.getName(); - final UHTeam team = UHCReloaded.get().getTeamManager().getTeamForPlayer(player); - - final boolean inThisTeam = this.team.equals(team); - - final ItemStack button = new ItemStackBuilder(Material.SKULL_ITEM) - .data((short) SkullType.PLAYER.ordinal()) - .title(I.t("{reset}{0}", displayName)) - .lore(player.isOnline() ? I.t("{gray}Online") : I.t("{gray}Offline")) - .lore(team != null ? I.t("{gray}Current team: {0}", team.getDisplayName()) : I.t("{gray}Current team: none")) - .loreLine() - .lore(inThisTeam ? I.t("{darkgray}» {white}Click {gray}to remove this player") : I.t("{darkgray}» {white}Click {gray}to add this player")) - .item(); - - SkullMeta meta = (SkullMeta) button.getItemMeta(); - meta.setOwner(player.getName()); - button.setItemMeta(meta); - - return button; - } - - @Override - protected ItemStack getPickedUpItem(OfflinePlayer player) - { - if (team.containsPlayer(player.getUniqueId())) - team.removePlayer(player); - else - team.addPlayer(player); - - update(); - - return null; - } - - @GuiAction ("back") - protected void back() - { - close(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHDynmapIntegration.java b/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHDynmapIntegration.java deleted file mode 100644 index aae72ff..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHDynmapIntegration.java +++ /dev/null @@ -1,406 +0,0 @@ -/* - * 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.integration; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.teams.TeamColor; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.PluginLogger; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.dynmap.DynmapAPI; -import org.dynmap.markers.Marker; -import org.dynmap.markers.MarkerAPI; -import org.dynmap.markers.MarkerIcon; -import org.dynmap.markers.MarkerSet; - - -public class UHDynmapIntegration -{ - private DynmapAPI api = null; - private MarkerAPI markerAPI = null; - private MarkerSet markerSet = null; - - public UHDynmapIntegration() - { - Plugin apiTest = Bukkit.getServer().getPluginManager().getPlugin("dynmap"); - if (apiTest == null || !apiTest.isEnabled()) - { - PluginLogger.warning("Dynmap is not present, so the integration was disabled."); - return; - } - - this.api = (DynmapAPI) apiTest; - - markerAPI = api.getMarkerAPI(); - if (markerAPI == null) - { - PluginLogger.warning("Dynmap is available, but the markers API is not. The integration was disabled."); - return; - } - - - // All is good, let's integrate. - initDynmapIntegration(); - - PluginLogger.info("Successfully hooked into Dynmap."); - } - - private void initDynmapIntegration() - { - - markerSet = markerAPI.getMarkerSet("uhplugin.markerset"); - - if (markerSet == null) - { - markerSet = markerAPI.createMarkerSet("uhplugin.markerset", "UltraHardcore", null, false); - } - else - { - markerSet.setMarkerSetLabel("UltraHardcore"); - } - } - - public void shutdownDynmapIntegration() - { - if (isDynmapIntegrationEnabled()) - { - markerSet.deleteMarkerSet(); - } - } - - public boolean isDynmapIntegrationEnabled() - { - return !(this.api == null); - } - - public DynmapAPI getDynmapAPI() - { - return api; - } - - public MarkerAPI getDynmapMarkerAPI() - { - return markerAPI; - } - - /** Death locations **/ - - /** - * Displays the death location of the given player. - * - * @param player The player. - */ - public void showDeathLocation(Player player) - { - if (!isDynmapIntegrationEnabled()) - { - return; - } - - if (!UHConfig.DYNMAP.SHOW_DEATH_LOCATIONS.get()) - { - return; - } - - if (!UHCReloaded.get().getGameManager().hasDeathLocation(player)) - { - return; - } - - Location deathPoint = UHCReloaded.get().getGameManager().getDeathLocation(player); - - String markerID = getDeathMarkerName(player); - /// Dynmap marker label of a death point - String markerLabel = I.t("Death point of {0}", player.getName()); - MarkerIcon icon = markerAPI.getMarkerIcon("skull"); - - Marker marker = markerSet.createMarker(markerID, markerLabel, true, deathPoint.getWorld().getName(), deathPoint.getX(), deathPoint.getY(), deathPoint.getZ(), icon, false); - if (marker == null) - { - UHCReloaded.get().getLogger().warning("Unable to create marker " + markerID); - } - } - - /** - * Hides the death location of the given player. - * - * @param player The player. - */ - public void hideDeathLocation(Player player) - { - if (!isDynmapIntegrationEnabled()) - { - return; - } - - if (!UHCReloaded.get().getConfig().getBoolean("dynmap.showDeathLocations")) - { - return; - } - - Marker marker = markerSet.findMarker(getDeathMarkerName(player)); - if (marker != null) - { - marker.deleteMarker(); - } - } - - /** - * Returns the internal ID of the marker of the death point of the given player. - * - * @param player The player. - * @return The ID. - */ - private String getDeathMarkerName(Player player) - { - return "uhplugin.death." + player.getName(); - } - - - /** Spawn locations **/ - - /** - * Displays the spawn point of the given team. - * - * @param team The team. - * @param spawnPoint The location of the spawn point. - */ - public void showSpawnLocation(UHTeam team, Location spawnPoint) - { - if (!isDynmapIntegrationEnabled()) - { - return; - } - - if (!UHConfig.DYNMAP.SHOW_SPAWN_LOCATIONS.get()) - { - return; - } - - - TeamColor teamColor = team.getColor(); - if (teamColor == null) - { - teamColor = TeamColor.GREEN; // green flags for solo games without colors - } - - String markerID = getSpawnMarkerName(team); - - String markerLabel; - if (UHCReloaded.get().getGameManager().isGameWithTeams()) - { - /// Dynmap marker label of a spawn point of a team. - markerLabel = I.t("Spawn point of the team {0}", team.getName()); - } - else - { - /// Dynmap marker label of a spawn point of a player, in solo. - markerLabel = I.t("Spawn point of {0}", team.getName()); - } - - showSpawnLocation(spawnPoint, teamColor, markerLabel, markerID); - } - - /** - * Displays the spawn point of the given player. - * - * <p> - * Used when the teleportation ignores the teams. - * </p> - * - * @param player The player. - * @param spawnPoint The location of the spawn point. - */ - public void showSpawnLocation(OfflinePlayer player, Location spawnPoint) - { - if (player == null) return; - - UHTeam team = UHCReloaded.get().getTeamManager().getTeamForPlayer(player); - - showSpawnLocation(player, team != null && team.getColor() != null ? team.getColor() : null, spawnPoint); - } - - /** - * Displays the spawn point of the given player. - * - * <p> - * Used when the teleportation ignores the teams. - * </p> - * - * @param player The player. - * @param color The color of the spawn point (i.e. of the team). - * @param spawnPoint The location of the spawn point. - */ - public void showSpawnLocation(OfflinePlayer player, TeamColor color, Location spawnPoint) - { - if (!isDynmapIntegrationEnabled()) - { - return; - } - - if (!UHConfig.DYNMAP.SHOW_SPAWN_LOCATIONS.get()) - { - return; - } - - - if (color == null) - { - color = TeamColor.GREEN; - } - - String markerID = getSpawnMarkerName(player); - - /// Dynmap marker label of a spawn point of a player, when the teleportation ignores the teams. - String markerLabel = I.t("Spawn point of {0}", player.getName()); - - showSpawnLocation(spawnPoint, color, markerLabel, markerID); - } - - /** - * Displays a spawn-point marker. - * - * @param spawnPoint The location of the spawn. - * @param color The color of the team (for the flag). - * @param label The label of the marker. - * @param markerID The ID of the marker. - */ - private void showSpawnLocation(Location spawnPoint, TeamColor color, String label, String markerID) - { - /* *** Icon *** */ - - MarkerIcon icon; - - // Let's try to find the best icon - // Available flags: - // redflag, orangeflag, yellowflag, greenflag, blueflag, purpleflag, pinkflag, pirateflag (black) - // Ref. https://github.com/webbukkit/dynmap/wiki/Using-markers - - switch (color) - { - case BLUE: - case DARK_BLUE: - case AQUA: - case DARK_AQUA: - icon = markerAPI.getMarkerIcon("blueflag"); - break; - - case GREEN: - case DARK_GREEN: - icon = markerAPI.getMarkerIcon("greenflag"); - break; - - case GOLD: - icon = markerAPI.getMarkerIcon("orangeflag"); - break; - - case YELLOW: - icon = markerAPI.getMarkerIcon("yellowflag"); - break; - - case RED: - case DARK_RED: - icon = markerAPI.getMarkerIcon("redflag"); - break; - - case DARK_PURPLE: - icon = markerAPI.getMarkerIcon("purpleflag"); - break; - - case LIGHT_PURPLE: - icon = markerAPI.getMarkerIcon("pinkflag"); - break; - - case BLACK: - case DARK_GRAY: - case GRAY: - icon = markerAPI.getMarkerIcon("pirateflag"); - break; - - case WHITE: // There is nothing better than pink I think... - default: - icon = markerAPI.getMarkerIcon("pinkflag"); - break; - } - - - /* *** Registration *** */ - - Marker marker = markerSet.createMarker( - markerID, - label, - true, - spawnPoint.getWorld().getName(), - spawnPoint.getX(), spawnPoint.getY(), spawnPoint.getZ(), - icon, - false - ); - - if (marker == null) - { - PluginLogger.warning("Unable to create marker {0}", markerID); - } - } - - /** - * Returns the internal ID of the marker of the spawn point of the given team. - * - * @param team The team. - * @return The ID. - */ - private String getSpawnMarkerName(UHTeam team) - { - return "uhplugin.spawn." + team.getName(); - } - - /** - * Returns the internal ID of the marker of the spawn point of the given team. - * - * <p> - * Used if the teleportation ignores the teams. - * </p> - * - * @param player The player. - * @return The ID. - */ - private String getSpawnMarkerName(OfflinePlayer player) - { - return "uhplugin.spawn." + player.getName(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHProtocolLibIntegration.java b/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHProtocolLibIntegration.java deleted file mode 100644 index e94d114..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHProtocolLibIntegration.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.integration; - -import com.comphenix.protocol.ProtocolLibrary; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.listeners.PacketsListener; -import fr.zcraft.zlib.tools.PluginLogger; - - -public class UHProtocolLibIntegration -{ - public UHProtocolLibIntegration(UHCReloaded p) - { - PacketsListener packetsListener = new PacketsListener(p); - - if (UHConfig.HARDCORE_HEARTS.DISPLAY.get()) - { - ProtocolLibrary.getProtocolManager().addPacketListener(packetsListener); - } - - if (UHConfig.AUTO_RESPAWN.DO.get()) - { - p.getServer().getPluginManager().registerEvents(packetsListener, p); - } - - PluginLogger.info("Successfully hooked into ProtocolLib."); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHProtocolLibIntegrationWrapper.java b/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHProtocolLibIntegrationWrapper.java deleted file mode 100644 index d81a39a..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHProtocolLibIntegrationWrapper.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.integration; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import fr.zcraft.zlib.components.configuration.ConfigurationItem; -import fr.zcraft.zlib.tools.PluginLogger; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; - -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - - -public class UHProtocolLibIntegrationWrapper -{ - - private UHCReloaded p = null; - private UHProtocolLibIntegration integration = null; - - public UHProtocolLibIntegrationWrapper(UHCReloaded p) - { - this.p = p; - - // Needed to avoid a NoClassDefFoundError. - // I don't like this way of doing this, but else, the plugin will not load without ProtocolLib. - - Plugin pl = Bukkit.getServer().getPluginManager().getPlugin("ProtocolLib"); - if (pl != null && pl.isEnabled()) - { - try - { - integration = new UHProtocolLibIntegration(p); - } - catch (NoClassDefFoundError e) - { - PluginLogger.error("ProtocolLib is present but cannot be loaded (outdated?), so the integration was disabled.", e); - } - } - else - { - PluginLogger.warning("ProtocolLib is not present, so the integration was disabled."); - } - } - - /** - * Returns true if ProtocolLib is installed and integrated into the plugin. - */ - public boolean isProtocolLibIntegrationEnabled() - { - return (this.integration != null); - } - - /** - * Checks if there are some enabled option which require ProtocolLib. - * - * @return A list of enabled options which requires ProtocolLib, or null - * if there isn't any enabled option that requires ProtocolLib. - */ - public List<String> isProtocolLibNeeded() - { - final List<String> enabledOptions = Stream.of(UHConfig.HARDCORE_HEARTS.DISPLAY, UHConfig.AUTO_RESPAWN.DO) - .filter(ConfigurationItem::get) - .map(ConfigurationItem::getFieldName) - .collect(Collectors.toList()); - - return enabledOptions.size() != 0 ? enabledOptions : null; - } - - /** - * Returns the wrapped integration. - */ - public UHProtocolLibIntegration getIntegration() - { - return integration; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHWorldBorderIntegration.java b/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHWorldBorderIntegration.java deleted file mode 100644 index ac77862..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHWorldBorderIntegration.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.integration; - -import com.wimbli.WorldBorder.WorldBorder; -import fr.zcraft.zlib.tools.PluginLogger; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; - - -public class UHWorldBorderIntegration -{ - private WorldBorder wb = null; - - public UHWorldBorderIntegration() - { - Plugin wbTest = Bukkit.getServer().getPluginManager().getPlugin("WorldBorder"); - if (wbTest == null || !wbTest.isEnabled()) - { - PluginLogger.warning("WorldBorder is not present, so the integration was disabled."); - return; - } - - this.wb = (WorldBorder) wbTest; - - try - { - Class.forName("com.wimbli.WorldBorder.BorderData"); - Class.forName("com.wimbli.WorldBorder.Config"); - } - catch (ClassNotFoundException e) - { - PluginLogger.warning("WorldBorder is available, but the version you are using is too old."); - PluginLogger.warning("This plugin is tested and works with WorldBorder 1.8.0 or later."); - - this.wb = null; - return; - } - - PluginLogger.info("Successfully hooked into WorldBorder."); - } - - public boolean isWBIntegrationEnabled() - { - return !(this.wb == null); - } - - public WorldBorder getWorldBorder() - { - return wb; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/BeforeGameListener.java b/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/BeforeGameListener.java deleted file mode 100644 index a9ba7f5..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/BeforeGameListener.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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.listeners; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.events.UHGameStartsEvent; -import eu.carrade.amaury.UHCReloaded.gui.teams.TeamsSelectorGUI; -import fr.zcraft.zlib.components.gui.Gui; -import fr.zcraft.zlib.components.gui.GuiUtils; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.core.ZLib; -import fr.zcraft.zlib.tools.items.ItemStackBuilder; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryDragEvent; -import org.bukkit.event.player.PlayerDropItemEvent; -import org.bukkit.event.player.PlayerInteractAtEntityEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerPickupItemEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.permissions.Permissible; - - -public class BeforeGameListener implements Listener -{ - /** - * @param player A player - * @return True if an inventory action should not be done because he is a builder. - */ - private boolean excludeBuilder(Permissible player) - { - return UHConfig.BEFORE_START.INVENTORY.ALLOW_FOR_BUILDERS.get() && player.hasPermission("uh.build"); - } - - /** - * Opens the teams selector GUI, if needed (enabled, game not started, needed item). - * - * TODO improve selector item detection. - * - * @param player The player who right-clicked an item. - * @param item The right-clicked item. - */ - private void openTeamsGUI(Player player, ItemStack item) - { - if (UHCReloaded.get().getGameManager().isGameStarted()) return; - - if (UHConfig.BEFORE_START.TEAM_SELECTOR.ENABLED.get() - && item != null - && item.getType() == UHConfig.BEFORE_START.TEAM_SELECTOR.ITEM.get()) - { - Gui.open(player, new TeamsSelectorGUI()); - } - } - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent ev) - { - if (UHCReloaded.get().getGameManager().isGameStarted()) return; - - final boolean builder = excludeBuilder(ev.getPlayer()); - - if (!builder && UHConfig.BEFORE_START.INVENTORY.CLEAR.get()) - { - ev.getPlayer().getInventory().clear(); - ev.getPlayer().getInventory().setArmorContents(null); - } - - if (UHConfig.BEFORE_START.TEAM_SELECTOR.ENABLED.get()) - { - Material itemType = UHConfig.BEFORE_START.TEAM_SELECTOR.ITEM.get(); - - ItemStack item = new ItemStackBuilder(itemType) - /// The title of the item given before the game to select a team - .title(I.t("{green}{bold}Select a team {gray}(Right-Click)")) - /// The lore of the item given before the game to select a team - .lore(GuiUtils.generateLore(I.t("{gray}Right-click to select your team for this game"))) - .hideAttributes() - .item(); - - final ItemStack centralItem = ev.getPlayer().getInventory().getItem(4); - if (!builder || centralItem == null || centralItem.getType() == org.bukkit.Material.AIR) - ev.getPlayer().getInventory().setItem(4, item); - } - - if (UHConfig.BEFORE_START.TEAM_IN_ACTION_BAR.get()) - { - UHCReloaded.get().getTeamManager().displayTeamInActionBar(ev.getPlayer()); - } - } - - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerInteract(PlayerInteractEvent ev) - { - if (ev.getAction() != Action.PHYSICAL) - openTeamsGUI(ev.getPlayer(), ev.getItem()); - } - - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent ev) - { - openTeamsGUI(ev.getPlayer(), ev.getPlayer().getItemInHand()); - } - - @EventHandler - public void onPlayerClick(InventoryClickEvent ev) - { - if (UHConfig.BEFORE_START.INVENTORY.PREVENT_USAGE.get()) - { - if (UHCReloaded.get().getGameManager().isGameStarted()) return; - if (excludeBuilder(ev.getWhoClicked())) return; - if (!ev.getInventory().equals(ev.getWhoClicked().getInventory())) return; - - ev.setCancelled(true); - } - } - - @EventHandler - public void onPlayerDrag(InventoryDragEvent ev) - { - if (UHConfig.BEFORE_START.INVENTORY.PREVENT_USAGE.get()) - { - if (UHCReloaded.get().getGameManager().isGameStarted()) return; - if (excludeBuilder(ev.getWhoClicked())) return; - if (!ev.getInventory().equals(ev.getWhoClicked().getInventory())) return; - - ev.setCancelled(true); - } - } - - @EventHandler - public void onPlayerDrop(PlayerDropItemEvent ev) - { - if (UHConfig.BEFORE_START.INVENTORY.PREVENT_USAGE.get()) - { - if (UHCReloaded.get().getGameManager().isGameStarted()) return; - if (excludeBuilder(ev.getPlayer())) return; - - ev.setCancelled(true); - } - } - - @EventHandler - public void onPlayerPickup(PlayerPickupItemEvent ev) - { - if (UHCReloaded.get().getGameManager().isGameStarted()) return; - if (excludeBuilder(ev.getPlayer())) return; - - if (UHConfig.BEFORE_START.INVENTORY.PREVENT_USAGE.get()) - { - ev.setCancelled(true); - } - } - - @EventHandler - public void onGameStarts(UHGameStartsEvent ev) - { - ZLib.unregisterEvents(this); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/CraftingListener.java b/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/CraftingListener.java deleted file mode 100644 index f4b2fb1..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/CraftingListener.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * 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.listeners; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.protips.ProTips; -import eu.carrade.amaury.UHCReloaded.recipes.RecipesManager; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.runners.RunTask; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.block.Banner; -import org.bukkit.entity.Player; -import org.bukkit.event.Event.Result; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryDragEvent; -import org.bukkit.event.inventory.InventoryType.SlotType; -import org.bukkit.event.inventory.PrepareItemCraftEvent; -import org.bukkit.inventory.AnvilInventory; -import org.bukkit.inventory.CraftingInventory; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryView; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.Recipe; -import org.bukkit.inventory.meta.BannerMeta; -import org.bukkit.inventory.meta.BlockStateMeta; -import org.bukkit.inventory.meta.ItemMeta; - -import java.util.HashSet; -import java.util.Set; - - -public class CraftingListener implements Listener -{ - private UHCReloaded p = null; - - public CraftingListener(UHCReloaded p) - { - this.p = p; - } - - - /** - * Used to: - * - prevent items to be crafted; - * - send a ProTip containing the craft to use, if an error occurred; - * - add a lure to the golden apples crafted from a head; - * - keep the name of the item when the anti-lore craft is used. - */ - @EventHandler - public void onPreCraftEvent(PrepareItemCraftEvent ev) - { - Recipe recipe = ev.getRecipe(); - - if (recipe == null) - { - return; - } - - /* *** Prevents items to be crafted *** */ - - if (!p.getRecipesManager().isRecipeAllowed(recipe)) - { - ev.getInventory().setResult(new ItemStack(Material.AIR)); - - // ProTips - final String failedRecipe = p.getRecipesManager().getLastFailedRecipe(); - final Player player = (Player) ev.getViewers().get(0); // crafting inventory: only one viewer in all cases. - - RunTask.later(() -> - { - switch (failedRecipe) - { - case RecipesManager.RECIPE_COMPASS: - switch (p.getRecipesManager().getCompassRecipeType()) - { - case RecipesManager.COMPASS_EASY: - ProTips.CRAFT_COMPASS_EASY.sendTo(player); - break; - case RecipesManager.COMPASS_MEDIUM: - ProTips.CRAFT_COMPASS_MEDIUM.sendTo(player); - break; - case RecipesManager.COMPASS_HARD: - ProTips.CRAFT_COMPASS_HARD.sendTo(player); - break; - } - - break; - - case RecipesManager.RECIPE_GLISTERING_MELON: - ProTips.CRAFT_GLISTERING_MELON.sendTo(player); - break; - - case RecipesManager.RECIPE_ENCHANTED_GOLDEN_APPLE: - ProTips.CRAFT_NO_ENCHANTED_GOLDEN_APPLE.sendTo(player); - break; - } - }, 40L); - - return; - } - - - /* *** Adds a lore to the golden apples crafted from a head *** */ - - ItemStack loreResult = p.getRecipesManager().addLore(recipe, ev.getInventory()); - if (loreResult != null) - { - ev.getInventory().setResult(loreResult); - return; - } - - - /* *** The lore remover don't change the name of the item *** */ - - ItemStack keepNameResult = p.getRecipesManager().keepNameOnLoreRemover(recipe, ev.getInventory()); - if (keepNameResult != null) - { - ev.getInventory().setResult(keepNameResult); - return; - } - } - - - /** - * - Workaround to fix the crafting grid being not updated when the item is taken - * from the grid. - * <p> - * - Prevents an apple to be renamed to/from the name of an head apple. - * - * (In vanilla clients, it is not possible to rename an apple to that name because of the - * ChatColor.RESET before, but some modded clients allows the player to write §r.) - * - * (Thanks to Zelnehlun on BukkitDev.) - * <p> - * - Crafts the special compass (“semi-shapeless” recipe). - */ - @EventHandler (ignoreCancelled = true) - public void onInventoryClick(final InventoryClickEvent ev) - { - // Just in case - if (ev.getWhoClicked() instanceof Player) - { - final Inventory inventory = ev.getInventory(); - - // Workaround to fix the crafting grid being not updated when the item is taken - // from the grid. - if (inventory instanceof CraftingInventory && ev.getSlotType() == SlotType.RESULT) - { - RunTask.later( - () -> ev.getViewers().stream() - .filter(viewer -> viewer instanceof Player) - .forEach(viewer -> ((Player) viewer).updateInventory()), - 1L - ); - } - - - /* *** Allows any shape for the loots in the compass recipe. *** */ - - if (inventory instanceof CraftingInventory) - { - // This is ran one tick after the click because when the event is fired, the inventory - // object is not updated, and so the result of the isValidCompassResult is invalid. - - RunTask.later(() -> - { - if (p.getRecipesManager().isValidCompassRecipe(((CraftingInventory) inventory).getMatrix())) - { - - // Puts the compass in the result slot - if (ev.getSlotType() == SlotType.CRAFTING) - { - ((CraftingInventory) inventory).setResult(new ItemStack(Material.COMPASS)); - ev.setResult(Result.ALLOW); - - ((Player) ev.getWhoClicked()).updateInventory(); // deprecated but needed - } - - // Consumes the materials in the crafting grid. - // Because this is not an "official" recipe, we need to do that manually. - else if (ev.getSlotType() == SlotType.RESULT) - { - int index = 1; - for (ItemStack stack : ((CraftingInventory) inventory).getMatrix()) - { - if (stack == null) continue; - - if (stack.getAmount() != 1) - { - stack.setAmount(stack.getAmount() - 1); - inventory.setItem(index, stack); - } - else - { - inventory.setItem(index, new ItemStack(Material.AIR)); - } - - index++; - } - - ev.setCurrentItem(new ItemStack(Material.COMPASS)); - ev.setResult(Result.ALLOW); - - ((Player) ev.getWhoClicked()).updateInventory(); // deprecated but needed - } - } - }, 1L); - } - - - /* *** Prevent an apple to be renamed to/from the name of an head apple. *** */ - - else if (inventory instanceof AnvilInventory) - { - InventoryView view = ev.getView(); - int rawSlot = ev.getRawSlot(); - - // ensure we are talking about the upper inventory - if (rawSlot == view.convertSlot(rawSlot)) - { - // "result" slot - if (rawSlot == 2) - { - ItemStack item = ev.getCurrentItem(); - - // result slot non empty - if (item != null) - { - final ItemMeta meta = item.getItemMeta(); - - final Set<String> prohibited = new HashSet<>(); - - prohibited.add(I.t("Golden head")); - prohibited.add(ChatColor.RESET + I.t("{aqua}Golden head")); - prohibited.add(ChatColor.RESET + I.t("{lightpurple}Golden head")); - - // It is possible that the client filters the name of the golden apple in the anvil UI, - // removing all §. - new HashSet<>(prohibited).stream() - .map(prohibition -> prohibition.replace("§", "")) - .forEach(prohibited::add); - - - // An item can't be renamed to the name of a golden head - if (meta != null && meta.hasDisplayName()) - { - if (prohibited.contains(meta.getDisplayName())) - { - ev.setCancelled(true); // nope nope nope - } - } - - // A golden head can't be renamed to any other name - if (view.getItem(0) != null) // slot 0 = first slot - { - ItemMeta metaOriginal = view.getItem(0).getItemMeta(); - - if (metaOriginal != null && metaOriginal.hasDisplayName()) - { - if (prohibited.contains(metaOriginal.getDisplayName())) - { - ev.setCancelled(true); - } - } - } - } - } - } - } - } - } - - - /** - * Used to craft the special compass (“semi-shapeless” recipe). - */ - @EventHandler (ignoreCancelled = true) - public void onInventoryDrag(final InventoryDragEvent ev) - { - if (ev.getInventory() instanceof CraftingInventory) - { - RunTask.later(() -> - { - if (p.getRecipesManager().isValidCompassRecipe(((CraftingInventory) ev.getInventory()).getMatrix())) - { - ((CraftingInventory) ev.getInventory()).setResult(new ItemStack(Material.COMPASS)); - ((Player) ev.getWhoClicked()).updateInventory(); // deprecated but needed - } - }, 1L); - } - } - - - /** - * Adds the team banner on crafted shields. - * - * Done indirectly because the plugin must be able to run - * on Minecraft 1.8. - */ - @EventHandler (ignoreCancelled = true) - public void onShieldPreCraft(PrepareItemCraftEvent ev) - { - if (!UHConfig.TEAMS_OPTIONS.BANNER.SHIELDS.ADD_ON_SHIELDS.get()) return; - - final Player player = (Player) ev.getViewers().get(0); - final UHTeam team = UHCReloaded.get().getTeamManager().getTeamForPlayer(player); - - if (team == null || team.getBanner() == null) return; - - final ItemStack result = ev.getRecipe().getResult(); - - final Material MATERIAL_SHIELD = Material.getMaterial("SHIELD"); - if (MATERIAL_SHIELD == null) return; // MC 1.8 - - if (result != null && result.getType() == MATERIAL_SHIELD) - { - try - { - final BannerMeta banner = (BannerMeta) team.getBanner().getItemMeta(); - - final BlockStateMeta bsMeta = (BlockStateMeta) result.getItemMeta(); - final Banner shieldBanner = (Banner) bsMeta.getBlockState(); - - shieldBanner.setBaseColor(banner.getBaseColor()); - shieldBanner.setPatterns(banner.getPatterns()); - - shieldBanner.update(); - - bsMeta.setBlockState(shieldBanner); - result.setItemMeta(bsMeta); - - ev.getInventory().setResult(result); - } - catch (ClassCastException | NullPointerException ignored) - { - // Bad Minecraft version (1.8) - } - } - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java b/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java deleted file mode 100644 index 9c7862a..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java +++ /dev/null @@ -1,787 +0,0 @@ -/* - * 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.listeners; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.events.EpisodeChangedCause; -import eu.carrade.amaury.UHCReloaded.events.TimerEndsEvent; -import eu.carrade.amaury.UHCReloaded.events.TimerStartsEvent; -import eu.carrade.amaury.UHCReloaded.events.UHEpisodeChangedEvent; -import eu.carrade.amaury.UHCReloaded.events.UHGameEndsEvent; -import eu.carrade.amaury.UHCReloaded.events.UHGameStartsEvent; -import eu.carrade.amaury.UHCReloaded.events.UHPlayerDeathEvent; -import eu.carrade.amaury.UHCReloaded.events.UHPlayerResurrectedEvent; -import eu.carrade.amaury.UHCReloaded.events.UHTeamDeathEvent; -import eu.carrade.amaury.UHCReloaded.misc.RuntimeCommandsExecutor; -import eu.carrade.amaury.UHCReloaded.protips.ProTips; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.UHSound; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.components.rawtext.RawText; -import fr.zcraft.zlib.tools.runners.RunTask; -import fr.zcraft.zlib.tools.text.RawMessage; -import fr.zcraft.zlib.tools.text.Titles; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.SkullType; -import org.bukkit.block.Banner; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.entity.FoodLevelChangeEvent; -import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.PlayerAchievementAwardedEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerLoginEvent; -import org.bukkit.event.player.PlayerLoginEvent.Result; -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.BannerMeta; -import org.bukkit.inventory.meta.SkullMeta; - -import java.net.URISyntaxException; -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 Set<UUID> enableSpectatorModeOnRespawn = new HashSet<>(); - - - public GameListener() - { - this.p = UHCReloaded.get(); - } - - - /** - * Used to: - * - call events (UHPlayerDeathEvent, UHTeamDeathEvent, UHGameEndsEvent); - * - play the death sound; - * - update the scoreboard; - * - kick the player (if needed); - * - broadcast a team-death message (if needed); - * - highlight the death message in the console; - * - increase visibility of the death message (if needed); - * - drop the skull of the dead player (if needed); - * - send a ProTip to the killer about the "golden heads" (if needed); - * - update the number of alive players/teams; - * - save the location of the death of the player, to allow a teleportation later; - * - show the death location on the dynmap (if needed); - * - give XP to the killer (if needed); - * - notify the player about the possibility of respawn if hardcore hearts are enabled; - * - update the MOTD if needed; - * - disable the team-chat-lock if needed. - */ - @EventHandler - public void onPlayerDeath(final PlayerDeathEvent ev) - { - // This needs to be executed only if the player die as a player, not a spectator. - // Also, the game needs to be started. - if (p.getGameManager().isPlayerDead(ev.getEntity()) || !p.getGameManager().isGameStarted()) - { - return; - } - - p.getServer().getPluginManager().callEvent(new UHPlayerDeathEvent(ev.getEntity(), ev)); - - // Plays sound. - p.getGameManager().getDeathSound().broadcast(); - - // Send lightning strike if needed. - if (UHConfig.DEATH.ANNOUNCEMENTS.LIGHTNING_STRIKE.get()) - { - ev.getEntity().getLocation().getWorld().strikeLightningEffect(ev.getEntity().getLocation()); - } - - // 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 (UHConfig.DEATH.KICK.DO.get()) - { - RunTask.later(() -> - { - /// The kick message of a player when death.kick.do = true in config - ev.getEntity().kickPlayer(I.t("jayjay")); - }, 20L * UHConfig.DEATH.KICK.TIME.get()); - } - - // Drops the skull of the player. - if (UHConfig.DEATH.HEAD.DROP.get()) - { - if (!UHConfig.DEATH.HEAD.PVP_ONLY.get() || (UHConfig.DEATH.HEAD.PVP_ONLY.get() && ev.getEntity().getKiller() != null)) - { - Location l = ev.getEntity().getLocation(); - ItemStack skull = new ItemStack(Material.SKULL_ITEM, 1, (short) SkullType.PLAYER.ordinal()); - SkullMeta skullMeta = (SkullMeta) skull.getItemMeta(); - skullMeta.setOwner(ev.getEntity().getName()); - skullMeta.setDisplayName(ChatColor.RESET + ev.getEntity().getDisplayName()); - skull.setItemMeta(skullMeta); - l.getWorld().dropItem(l, skull); - - // Protip - if (ev.getEntity().getKiller() != null) - { - final Player killer = ev.getEntity().getKiller(); - RunTask.later(() -> ProTips.CRAFT_GOLDEN_HEAD.sendTo(killer), 200L); - } - } - } - - // Give XP to the killer (if needed) - if (UHConfig.DEATH.GIVE_XP_TO_KILLER.LEVELS.get() > 0) - { - Player killer = ev.getEntity().getKiller(); - if (killer != null) - { - boolean inSameTeam = p.getTeamManager().inSameTeam(ev.getEntity(), killer); - boolean onlyOtherTeam = UHConfig.DEATH.GIVE_XP_TO_KILLER.ONLY_OTHER_TEAM.get(); - - if (!onlyOtherTeam || !inSameTeam) - { - killer.giveExpLevels(UHConfig.DEATH.GIVE_XP_TO_KILLER.LEVELS.get()); - } - } - } - - // Sends a team-death message & event if needed. - final UHTeam team = p.getTeamManager().getTeamForPlayer(ev.getEntity()); - if (team != null) - { - boolean isAliveTeam = false; - - for (UUID playerID : team.getPlayersUUID()) - { - if (!p.getGameManager().isPlayerDead(playerID)) - { - isAliveTeam = true; - break; - } - } - - if (!isAliveTeam) - { - p.getServer().getPluginManager().callEvent(new UHTeamDeathEvent(team)); - - if (UHConfig.DEATH.MESSAGES.NOTIFY_IF_TEAM_HAS_FALLEN.get()) - { - // Used to display this message after the death message. - RunTask.later(() -> { - String format = ChatColor.translateAlternateColorCodes('&', UHConfig.DEATH.MESSAGES.TEAM_DEATH_MESSAGES_FORMAT.get()); - p.getServer().broadcastMessage(I.t("{0}The team {1} has fallen!", format, team.getDisplayName() + format)); - }, 1L); - } - } - } - - // Highlights the death message in the console - p.getServer().getConsoleSender().sendMessage(ChatColor.GOLD + "-- Death of " + ev.getEntity().getDisplayName() + ChatColor.GOLD + " (" + ev.getDeathMessage() + ") --"); - - // Customizes the death message - String dmFormat = ChatColor.translateAlternateColorCodes('&', UHConfig.DEATH.MESSAGES.DEATH_MESSAGES_FORMAT.get()); - String deathMessage = dmFormat + ev.getDeathMessage(); - deathMessage = deathMessage.replace(ev.getEntity().getName(), ev.getEntity().getDisplayName() + dmFormat); - if (ev.getEntity().getKiller() != null) - { - deathMessage = deathMessage.replace(ev.getEntity().getKiller().getName(), ev.getEntity().getKiller().getDisplayName() + dmFormat); - } - ev.setDeathMessage(deathMessage); - - // Saves the location of the death - p.getGameManager().addDeathLocation(ev.getEntity(), ev.getEntity().getLocation()); - - // Shows the death location on the dynmap - p.getDynmapIntegration().showDeathLocation(ev.getEntity()); - - // Is the game ended? If so, we need to call an event. - if (p.getGameManager().isGameRunning() && p.getGameManager().getAliveTeamsCount() == 1) - { - p.getGameManager().setGameFinished(true); - - // There's only one team alive, so the winner team is the first one. - p.getServer().getPluginManager().callEvent(new UHGameEndsEvent(p.getGameManager().getAliveTeams().iterator().next())); - } - - // Notifies the player about the possibility of respawn if hardcore hearts are enabled - if (UHConfig.HARDCORE_HEARTS.DISPLAY.get() && p.getProtocolLibIntegrationWrapper().isProtocolLibIntegrationEnabled() && UHConfig.HARDCORE_HEARTS.RESPAWN_MESSAGE.get()) - { - RunTask.later(() -> { - /// A message displayed to the players under the death screen, about the respawn possibility even if the death screen says the opposite (in hardcore mode) - ev.getEntity().sendMessage(I.t("{darkpurple}{obfuscated}----{lightpurple}{italic} YOU CAN RESPAWN{lightpurple}, just click {italic}Respawn {lightpurple}on the next screen.")); - }, 2L); - } - - // Disables the team-chat-lock if needed - if (UHConfig.TEAMS_OPTIONS.TEAM_CHAT.DISABLE_LOCK_ON_DEATH.get()) - { - if (p.getTeamChatManager().isTeamChatEnabled(ev.getEntity())) - { - p.getTeamChatManager().toggleChatForPlayer(ev.getEntity()); - } - } - - // Updates the list headers & footers. - p.getPlayerListHeaderFooterManager().updateHeadersFooters(); - } - - - /** - * 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(() -> p.getSpectatorsManager().setSpectating(ev.getPlayer(), true)); - } - } - - - /** - * Used to disable all damages if the game is not started. - * - * @param ev - */ - @EventHandler - public void onEntityDamage(final EntityDamageEvent ev) - { - if (ev.getEntity() instanceof Player) - { - if (p.getGameManager().isSlowStartInProgress() || (!p.getGameManager().isGameRunning() && !UHConfig.BEFORE_START.ENABLE_PVP.get()) || (p.getGameManager().isGameRunning() && !p.getGameManager().isTakingDamage())) - { - ev.setCancelled(true); - } - } - } - - - /** - * Used to prevent the food level from dropping if the game has not started. - * - * @param ev - */ - @EventHandler - public void onFoodUpdate(final FoodLevelChangeEvent ev) - { - if (!p.getGameManager().isGameRunning()) - { - if (ev.getEntity() instanceof Player) - { - ((Player) ev.getEntity()).setFoodLevel(20); - ((Player) ev.getEntity()).setSaturation(20f); - } - - ev.setCancelled(true); - } - } - - - /** - * Used to display our custom state-based MOTD (if needed). - */ - @EventHandler - public void onServerListPing(final ServerListPingEvent ev) - { - if (p.getMOTDManager().isEnabled()) - { - ev.setMotd(p.getMOTDManager().getCurrentMOTD()); - } - } - - - /** - * Used to prevent the player to login after his death (if needed). - */ - @EventHandler - public void onPlayerLogin(final PlayerLoginEvent ev) - { - if (p.getGameManager().isGameStarted() - && p.getGameManager().isPlayerDead(ev.getPlayer()) - && !p.getGameManager().isDeadPlayersToBeResurrected(ev.getPlayer()) - && !p.getGameManager().getStartupSpectators().contains(ev.getPlayer().getName()) - && !UHConfig.DEATH.KICK.ALLOW_RECONNECT.get()) - { - - ev.setResult(Result.KICK_OTHER); - /// The kick message displayed if a player tries to relog after his death and it's forbidden by the config. - ev.setKickMessage(I.t("You are dead!")); - } - } - - - /** - * Used to: - * - change the gamemode of the player, if the game is not running; - * - teleport the player to the spawn, if the game is not running; - * - update the scoreboard; - * - put a new player in spectator mode if the game is started (following the config); - * - resurrect a player (if the player was offline). - */ - @EventHandler (priority = EventPriority.HIGHEST) - public void onPlayerJoin(final PlayerJoinEvent ev) - { - if (!this.p.getGameManager().isGameStarted()) - { - if (!p.getGameManager().isSlowStartInProgress()) - { - // Initialization of the player (teleportation, life, health objective score...). - p.getGameManager().initPlayer(ev.getPlayer()); - - // Teams selector. - if (UHConfig.TEAMS_OPTIONS.GUI.AUTO_DISPLAY.get() && p.getTeamManager().getTeams().size() != 0) - { - RunTask.later(() -> { - if (p.getTeamManager().getTeamForPlayer(ev.getPlayer()) == null) - { - p.getTeamManager().displayTeamChooserChatGUI(ev.getPlayer()); - } - }, 20L * UHConfig.TEAMS_OPTIONS.GUI.DELAY.get()); - } - - // Rules - if (p.getRulesManager().displayOnJoin()) - { - RunTask.later(() -> p.getRulesManager().displayRulesTo(ev.getPlayer()), 15 * 20L); - } - } - else - { - // Without that the player will be kicked for flying. - ev.getPlayer().setAllowFlight(true); - ev.getPlayer().setFlying(true); - } - } - - // Mainly useful on the first join. - p.getScoreboardManager().setScoreboardForPlayer(ev.getPlayer()); - - // The headers & footers needs to be (re)sent. - p.getPlayerListHeaderFooterManager().sendTo(ev.getPlayer()); - - // The display name is reset when the player logs off. - p.getTeamManager().colorizePlayer(ev.getPlayer()); - - if (!p.getGameManager().isGameStarted() && ev.getPlayer().hasPermission("uh.*")) - { - // A warning to the administrators if ProtocolLib is not present. - if (!p.getProtocolLibIntegrationWrapper().isProtocolLibIntegrationEnabled()) - { - final List<String> enabledOptionsWithProtocolLibNeeded = p.getProtocolLibIntegrationWrapper().isProtocolLibNeeded(); - - if (enabledOptionsWithProtocolLibNeeded != null) - { - ev.getPlayer().sendMessage(I.t("{darkred}[UHC] {ce}ProtocolLib is needed but not installed!")); - ev.getPlayer().sendMessage(I.t("{gray}The following options require the presence of ProtocolLib:")); - - for (String option : enabledOptionsWithProtocolLibNeeded) - { - /// An option requiring ProtocolLib, in the “missing PLib” message. {0} = option path. - ev.getPlayer().sendMessage(I.tc("protocollib_option", "{darkgray} - {gray}{0}", option)); - } - - String pLibDownloadURL; - if (p.getServer().getBukkitVersion().contains("1.7")) // 1.7.9 or 1.7.10 - { - pLibDownloadURL = "http://dev.bukkit.org/bukkit-plugins/protocollib/"; - } - else // 1.8+ - { - pLibDownloadURL = "http://www.spigotmc.org/resources/protocollib.1997/"; - } - - try - { - RawMessage.send(ev.getPlayer(), - new RawText(I.t("{gray}You can download ProtocolLib by clicking here.")) - .uri(pLibDownloadURL) - .hover(ChatColor.GRAY + pLibDownloadURL) - .build() - ); - } - catch (URISyntaxException e) - { - e.printStackTrace(); - - /// {0} = ProtocolLib download URL for the current Minecraft version. - ev.getPlayer().sendMessage(I.t("{gray}ProtocolLib is available here: {0}", pLibDownloadURL)); - } - } - } - } - - // If the player needs to be resurrected... - if (p.getGameManager().isDeadPlayersToBeResurrected(ev.getPlayer())) - { - p.getGameManager().resurrectPlayerOnlineTask(ev.getPlayer()); - p.getGameManager().markPlayerAsResurrected(ev.getPlayer()); - } - - // If the player is a new one, the game is started, and the option is set to true... - if (p.getGameManager().isGameRunning() && UHConfig.SPECTATOR_MODE_WHEN_NEW_PLAYER_JOIN_AFTER_START.get() - && !p.getGameManager().getAlivePlayers().contains(ev.getPlayer())) - { - p.getSpectatorsManager().setSpectating(ev.getPlayer(), true); - } - } - - /** - * Used to disable the achievements before the game. - */ - @EventHandler - public void onPlayerAchievementAwarded(final PlayerAchievementAwardedEvent ev) - { - if (!p.getGameManager().isGameStarted() && UHConfig.ACHIEVEMENTS.DISABLE_ACHIEVEMENTS_BEFORE_START.get()) - { - ev.setCancelled(true); - } - } - - /** - * Used to disable the statistics before the game. - */ - @EventHandler - public void onPlayerStatisticIncrement(final PlayerStatisticIncrementEvent ev) - { - if (!p.getGameManager().isGameStarted() && UHConfig.STATISTICS.DISABLE_STATISTICS_BEFORE_START.get()) - { - ev.setCancelled(true); - } - } - - - /** - * Used to prevent players from breaking blocks if the game is not currently running. - */ - @EventHandler - public void onBlockBreakEvent(final BlockBreakEvent ev) - { - if (!this.p.getGameManager().isGameStarted() && !ev.getPlayer().hasPermission("uh.build")) - { - ev.setCancelled(true); - } - } - - /** - * Used to prevent players from placing blocks if the game is not currently running. - */ - @EventHandler - public void onBlockPlaceEvent(final BlockPlaceEvent ev) - { - if (!this.p.getGameManager().isGameStarted() && !ev.getPlayer().hasPermission("uh.build")) - { - ev.setCancelled(true); - } - } - - - /** - * Used to send the chat to the team-chat if this team-chat is enabled. - */ - // Priority LOWEST to be able to cancel the event before all other plugins - @EventHandler (priority = EventPriority.LOWEST) - public void onAsyncPlayerChat(final AsyncPlayerChatEvent ev) - { - // If the event is asynchronous, the message was sent by a "real" player. - // Else, the message was sent by a plugin (like our /g command, or another plugin), and - // the event is ignored. - if (ev.isAsynchronous()) - { - if (p.getTeamChatManager().isTeamChatEnabled(ev.getPlayer())) - { - ev.setCancelled(true); - p.getTeamChatManager().sendTeamMessage(ev.getPlayer(), ev.getMessage()); - } - else if (p.getTeamChatManager().isOtherTeamChatEnabled(ev.getPlayer())) - { - ev.setCancelled(true); - p.getTeamChatManager().sendTeamMessage(ev.getPlayer(), ev.getMessage(), p.getTeamChatManager().getOtherTeamEnabled(ev.getPlayer())); - } - } - } - - /** - * Used to: - * - update the internal list of running timers; - * - shift the episode if the main timer is up (and restart this main timer); - * - hide an other timer when it is up. - */ - @EventHandler - public void onTimerEnds(final TimerEndsEvent ev) - { - p.getTimerManager().updateStartedTimersList(); - - if (ev.getTimer().equals(p.getTimerManager().getMainTimer())) - { - // If this timer is the main one, we shifts an episode. - p.getGameManager().shiftEpisode(); - ev.setRestart(true); - } - else - { - ev.getTimer().setDisplayed(false); - } - - if (ev.getTimer().equals(p.getBorderManager().getWarningTimer()) && ev.wasTimerUp()) - { - p.getBorderManager().getWarningSender().sendMessage(I.t("{cs}The timer before the new border is up!")); - p.getBorderManager().sendCheckMessage(p.getBorderManager().getWarningSender(), p.getBorderManager().getWarningSize()); - } - } - - /** - * Used to: - * - update the internal list of running timers; - * - display a timer when it is started. - */ - @EventHandler - public void onTimerStarts(final TimerStartsEvent ev) - { - p.getTimerManager().updateStartedTimersList(); - - if (!ev.getTimer().equals(p.getTimerManager().getMainTimer())) - { - ev.getTimer().setDisplayed(true); - } - } - - - /** - * Used to broadcast the episode change. - */ - @EventHandler - public void onEpisodeChange(final UHEpisodeChangedEvent ev) - { - String message; - - if (ev.getCause() == EpisodeChangedCause.SHIFTED) - { - message = I.t("{aqua}-------- End of episode {0} [forced by {1}] --------", String.valueOf(ev.getNewEpisode() - 1), ev.getShifter()); - } - else - { - message = I.t("{aqua}-------- End of episode {0} --------", String.valueOf(ev.getNewEpisode() - 1)); - } - - p.getServer().broadcastMessage(message); - - - // Broadcasts title - if (UHConfig.EPISODES.TITLE.get()) - { - Titles.broadcastTitle( - 5, 32, 8, - /// The title displayed when the episode change. {0} = new episode number; {1} = old. - I.t("{darkaqua}Episode {aqua}{0}", ev.getNewEpisode(), ev.getNewEpisode() - 1), - "" - ); - } - - - // Updates the list headers & footers. - p.getPlayerListHeaderFooterManager().updateHeadersFooters(); - } - - - /** - * Used to: - * - broadcast the beginning of a game, with sound & message; - * - schedule the commands executed after the beginning of the game. - */ - @EventHandler - public void onGameStarts(final UHGameStartsEvent ev) - { - // Start sound - new UHSound(UHConfig.START.SOUND).broadcast(); - - // Broadcast - /// Start message broadcasted in chat - Bukkit.getServer().broadcastMessage(I.t("{green}--- GO ---")); - - // Title - if (UHConfig.START.DISPLAY_TITLE.get()) - { - Titles.broadcastTitle( - 5, 40, 8, - /// Title of title displayed when the game starts. - I.t("{darkgreen}Let's go!"), - /// Subtitle of title displayed when the game starts. - I.t("{green}Good luck, and have fun") - ); - } - - // Commands - p.getRuntimeCommandsExecutor().registerCommandsInScheduler(RuntimeCommandsExecutor.AFTER_GAME_START); - - // Border shrinking - p.getBorderManager().scheduleBorderReduction(); - - // MOTD - p.getMOTDManager().updateMOTDDuringGame(); - - // List headers & footers. - p.getPlayerListHeaderFooterManager().updateHeadersFooters(); - - // Rules - if (p.getRulesManager().displayOnStart()) - { - RunTask.later(() -> p.getRulesManager().broadcastRules(), 15 * 20L); - } - - // Banners - if (p.getGameManager().START_GIVE_BANNER || p.getGameManager().START_PLACE_BANNER_HEAD || p.getGameManager().START_PLACE_BANNER_SPAWN) - { - RunTask.later(() -> - { - for (UHTeam team : p.getTeamManager().getTeams()) - { - if (!team.isEmpty()) - { - final ItemStack banner = team.getBanner(); - for (Player player : team.getOnlinePlayers()) - { - if (p.getGameManager().START_GIVE_BANNER) - player.getInventory().setItem(8, banner); - - if (p.getGameManager().START_PLACE_BANNER_HEAD) - player.getInventory().setHelmet(banner); - - if (p.getGameManager().START_PLACE_BANNER_SPAWN) - { - final Block place = player.getWorld().getHighestBlockAt(player.getLocation()); - final Block under = place.getRelative(BlockFace.DOWN); - - // We don't want a stack of banners - if (under.getType() != Material.STANDING_BANNER) - { - if (!under.getType().isSolid()) - under.setType(Material.WOOD); - - place.setType(Material.STANDING_BANNER); - - Banner bannerBlock = (Banner) place.getState(); - BannerMeta bannerMeta = (BannerMeta) banner.getItemMeta(); - - bannerBlock.setBaseColor(bannerMeta.getBaseColor()); - bannerBlock.setPatterns(bannerMeta.getPatterns()); - - bannerBlock.update(); - } - } - } - } - } - }, 5L); - } - } - - /** - * Used to: - * - broadcast the winner(s) and launch some fireworks if needed, a few seconds later; - * - schedule the commands executed after the end of the game. - */ - @EventHandler (priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onGameEnd(final UHGameEndsEvent ev) - { - if (UHConfig.FINISH.AUTO.DO.get()) - { - RunTask.later(() -> - { - try - { - p.getGameManager().finishGame(); - } - catch (IllegalStateException e) - { - // The game is not finished (...what?). - e.printStackTrace(); - } - }, UHConfig.FINISH.AUTO.TIME_AFTER_LAST_DEATH.get() * 20L); - } - - // Commands - p.getRuntimeCommandsExecutor().registerCommandsInScheduler(RuntimeCommandsExecutor.AFTER_GAME_END); - - // Updates the MOTD. - p.getMOTDManager().updateMOTDAfterGame(ev.getWinnerTeam()); - } - - - /** - * Used to: - * - disable the spectator mode; - * - hide the death point from the dynmap; - * - broadcast this resurrection to all players; - * - update the MOTD. - */ - @EventHandler - public void onPlayerResurrected(final UHPlayerResurrectedEvent ev) - { - // Spectator mode disabled - p.getSpectatorsManager().setSpectating(ev.getPlayer(), false); - - // Death point removed on the dynmap - p.getDynmapIntegration().hideDeathLocation(ev.getPlayer()); - - // All players are notified - /// Resurrection notification. {0} = raw resurrected player name. - p.getServer().broadcastMessage(I.t("{gold}{0} returned from the dead!", ev.getPlayer().getName())); - - // Updates the MOTD. - p.getMOTDManager().updateMOTDDuringGame(); - - // Updates the list headers & footers. - p.getPlayerListHeaderFooterManager().updateHeadersFooters(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java b/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java deleted file mode 100644 index 4aecb0b..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * 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.listeners; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.task.CancelBrewTask; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.runners.RunTask; -import org.bukkit.ChatColor; -import org.bukkit.GameMode; -import org.bukkit.Material; -import org.bukkit.Sound; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Ghast; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; -import org.bukkit.event.entity.EntityDeathEvent; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryDragEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerItemConsumeEvent; -import org.bukkit.event.player.PlayerPickupItemEvent; -import org.bukkit.event.player.PlayerTeleportEvent; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; -import org.bukkit.event.weather.WeatherChangeEvent; -import org.bukkit.inventory.BrewerInventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; - -import java.util.ArrayList; -import java.util.List; - - -public class GameplayListener implements Listener -{ - private final UHCReloaded p; - - public GameplayListener() - { - this.p = UHCReloaded.get(); - } - - - /** - * Used to replace ghast tears with gold (if needed). - */ - @EventHandler (ignoreCancelled = true) - public void onEntityDeath(EntityDeathEvent ev) - { - if (ev.getEntity() instanceof Ghast && UHConfig.GAMEPLAY_CHANGES.REPLACE_GHAST_TEARS_WITH_GOLD.get()) - { - final List<ItemStack> drops = new ArrayList<ItemStack>(ev.getDrops()); - ev.getDrops().clear(); - - for (final ItemStack i : drops) - { - if (i.getType() == Material.GHAST_TEAR) - { - ev.getDrops().add(new ItemStack(Material.GOLD_INGOT, i.getAmount())); - } - else - { - ev.getDrops().add(i); - } - } - } - } - - /** - * Used to prevent the user to get a ghast tear, if forbidden by the config. - */ - @EventHandler (ignoreCancelled = true) - public void onPlayerPickupItem(PlayerPickupItemEvent ev) - { - if (ev.getItem().getItemStack().getType() == Material.GHAST_TEAR - && ev.getPlayer().getGameMode().equals(GameMode.SURVIVAL) - && UHConfig.GAMEPLAY_CHANGES.REPLACE_GHAST_TEARS_WITH_GOLD.get()) - { - ev.setCancelled(true); - } - } - - - /** - * Used to disable power-II potions. - */ - @EventHandler - public void onInventoryDrag(InventoryDragEvent ev) - { - if (UHConfig.GAMEPLAY_CHANGES.DISABLE_LEVEL_II_POTIONS.get() && ev.getInventory() instanceof BrewerInventory) - { - RunTask.later(new CancelBrewTask((BrewerInventory) ev.getInventory(), ev.getWhoClicked()), 1L); - } - } - - /** - * Used to disable power-II potions. - */ - @EventHandler - public void onInventoryClick(InventoryClickEvent ev) - { - if (UHConfig.GAMEPLAY_CHANGES.DISABLE_LEVEL_II_POTIONS.get() && ev.getInventory() instanceof BrewerInventory) - { - RunTask.later(new CancelBrewTask((BrewerInventory) ev.getInventory(), ev.getWhoClicked()), 1L); - } - } - - - /** - * Used to disable ender pearl damages (if needed). - */ - @EventHandler (ignoreCancelled = true) - public void onPlayerTeleport(final PlayerTeleportEvent ev) - { - if (UHConfig.GAMEPLAY_CHANGES.DISABLE_ENDERPEARLS_DAMAGES.get()) - { - if (ev.getCause() == TeleportCause.ENDER_PEARL) - { - ev.setCancelled(true); - ev.getPlayer().teleport(ev.getTo(), TeleportCause.PLUGIN); // Technically its an ender pearl teleportation, but - // if we use that, an infinite loop will occur due to - // the event being re-captured and re-emitted. - } - } - } - - - /** - * Used to disable witch spawn (if needed). - */ - @EventHandler - public void onCreatureSpawn(CreatureSpawnEvent ev) - { - if (ev.getEntityType().equals(EntityType.WITCH)) - { - if (UHConfig.GAMEPLAY_CHANGES.WITCH.DISABLE_NATURAL_SPAWN.get() && ev.getSpawnReason().equals(SpawnReason.NATURAL)) - { - ev.setCancelled(true); - } - if (UHConfig.GAMEPLAY_CHANGES.WITCH.DISABLE_LIGHTNING_SPAWN.get() && ev.getSpawnReason().equals(SpawnReason.LIGHTNING)) - { - ev.setCancelled(true); - } - } - } - - - /** - * Used to change the amount of regenerated hearts from a golden apple. - */ - @EventHandler - public void onPlayerItemConsume(final PlayerItemConsumeEvent ev) - { - final int TICKS_BETWEEN_EACH_REGENERATION = 50; - final int DEFAULT_NUMBER_OF_HEARTS_REGEN = 4; - final int DEFAULT_NUMBER_OF_HEARTS_REGEN_NOTCH = 180; - final int REGENERATION_LEVEL_GOLDEN_APPLE = 2; - final int REGENERATION_LEVEL_NOTCH_GOLDEN_APPLE = 5; - - if (ev.getItem().getType() == Material.GOLDEN_APPLE) - { - ItemMeta meta = ev.getItem().getItemMeta(); - short dataValue = ev.getItem().getDurability(); - int halfHearts; - int level; - - if (meta.hasDisplayName() - && (meta.getDisplayName().equals(ChatColor.RESET + I.t("{aqua}Golden head")) - || meta.getDisplayName().equals(ChatColor.RESET + I.t("{lightpurple}Golden head")))) - { - // Normal golden apple from a head - if (dataValue == 0) - { - halfHearts = UHConfig.GAMEPLAY_CHANGES.GOLDEN_APPLE.REGENERATION.FROM_NORMAL_HEAD.get(); - level = REGENERATION_LEVEL_GOLDEN_APPLE; - } - // Notch golden apple from a head - else - { - halfHearts = UHConfig.GAMEPLAY_CHANGES.GOLDEN_APPLE.REGENERATION.FROM_NOTCH_HEAD.get(); - level = REGENERATION_LEVEL_NOTCH_GOLDEN_APPLE; - } - } - // Normal golden apple from an apple - else if (dataValue == 0) - { - halfHearts = UHConfig.GAMEPLAY_CHANGES.GOLDEN_APPLE.REGENERATION.NORMAL.get(); - level = REGENERATION_LEVEL_GOLDEN_APPLE; - } - // Notch golden apple from an apple - else - { - halfHearts = UHConfig.GAMEPLAY_CHANGES.GOLDEN_APPLE.REGENERATION.NOTCH.get(); - level = REGENERATION_LEVEL_NOTCH_GOLDEN_APPLE; - } - - // Technically, a level-I effect is « level 0 ». - final int realLevel = level - 1; - - - // What is needed to do? - if ((dataValue == 0 && halfHearts == DEFAULT_NUMBER_OF_HEARTS_REGEN) - || (dataValue == 1 && halfHearts == DEFAULT_NUMBER_OF_HEARTS_REGEN_NOTCH)) - { - // Default behavior, nothing to do. - } - else if ((dataValue == 0 && halfHearts > DEFAULT_NUMBER_OF_HEARTS_REGEN) - || (dataValue == 1 && halfHearts > DEFAULT_NUMBER_OF_HEARTS_REGEN_NOTCH)) - { - // If the heal needs to be increased, the effect can be applied immediately. - - int duration = ((int) Math.floor(TICKS_BETWEEN_EACH_REGENERATION / (Math.pow(2, realLevel)))) * halfHearts; - - new PotionEffect(PotionEffectType.REGENERATION, duration, realLevel).apply(ev.getPlayer()); - } - else - { - // The heal needs to be decreased. - // We can't apply the effect immediately, because the server will just ignore it. - // So, we apply it two ticks later, with one half-heart less (because in two ticks, - // one half-heart is given to the player). - final int healthApplied = halfHearts - 1; - - RunTask.later(() -> - { - // The original, vanilla, effect is removed - ev.getPlayer().removePotionEffect(PotionEffectType.REGENERATION); - - int duration = ((int) Math.floor(TICKS_BETWEEN_EACH_REGENERATION / (Math.pow(2, realLevel)))) * healthApplied; - new PotionEffect(PotionEffectType.REGENERATION, duration, realLevel).apply(ev.getPlayer()); - }, 2L); - } - } - } - - - /** - * Used to update the compass. - */ - @SuppressWarnings ("deprecation") - @EventHandler - public void onPlayerInteract(PlayerInteractEvent ev) - { - if ((ev.getAction() == Action.RIGHT_CLICK_AIR || ev.getAction() == Action.RIGHT_CLICK_BLOCK) - && ev.getPlayer().getItemInHand().getType() == Material.COMPASS - && p.getConfig().getBoolean("gameplay-changes.compass.enabled") - && !p.getGameManager().isPlayerDead(ev.getPlayer())) - { - Player player1 = ev.getPlayer(); - - boolean foundRottenFlesh = false; - for (ItemStack item : player1.getInventory().getContents()) - { - if (item != null && item.getType() == Material.ROTTEN_FLESH) - { - if (item.getAmount() != 1) - { - item.setAmount(item.getAmount() - 1); - } - else - { - player1.getInventory().removeItem(item); - } - - player1.updateInventory(); - foundRottenFlesh = true; - break; - } - } - - if (!foundRottenFlesh) - { - /// Error message if a player tries to use his pointing compass without rotten flesh. - player1.sendMessage(I.t("{gray}{italic}You do not have rotten flesh.")); - player1.playSound(player1.getLocation(), Sound.STEP_WOOD, 1F, 1F); - return; - } - - Player nearest = null; - Double distance = 99999D; - for (Player player2 : p.getGameManager().getOnlineAlivePlayers()) - { - try - { - Double calc = player1.getLocation().distanceSquared(player2.getLocation()); - - if (calc > 1 && calc < distance) - { - distance = calc; - if (!player2.getUniqueId().equals(player1.getUniqueId()) && !p.getTeamManager().inSameTeam(player1, player2)) - { - nearest = player2.getPlayer(); - } - } - } - catch (Exception ignored) - { - - } - } - - if (nearest == null) - { - /// Error message if a player tries to use his pointing compass without a player nearby. - player1.sendMessage(I.t("{gray}{italic}Only silence answers your request.")); - - player1.playSound(player1.getLocation(), Sound.STEP_WOOD, 1F, 1F); - return; - } - - /// Success message when a player uses his pointing compass. - player1.sendMessage(I.t("{gray}The compass now points to the closest player.")); - player1.setCompassTarget(nearest.getLocation()); - - player1.playSound(player1.getLocation(), Sound.ENDERMAN_TELEPORT, 1F, 1F); - } - } - - - /** - * Used to disable the "bad" weather (aka non-clear weather). - * The weather is initially clear. - */ - @EventHandler - public void onWeatherChange(WeatherChangeEvent ev) - { - if (!UHConfig.GAMEPLAY_CHANGES.WEATHER.get()) - { - ev.setCancelled(true); - } - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/SpawnsListener.java b/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/SpawnsListener.java deleted file mode 100644 index 31dcc05..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/SpawnsListener.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * 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.listeners; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Ghast; -import org.bukkit.entity.Monster; -import org.bukkit.entity.Rabbit; -import org.bukkit.entity.Slime; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import java.util.Random; - - -public class SpawnsListener implements Listener -{ - private final Random random = new Random(); - - private final boolean RABBIT_SPAWN_ENABLED; - private final double RABBIT_SPAWN_PROBABILITY; - private final String RABBIT_NAME; - - public SpawnsListener() - { - RABBIT_SPAWN_ENABLED = UHConfig.GAMEPLAY_CHANGES.RABBIT.KILLER_RABBIT_SPAWN.get(); - RABBIT_SPAWN_PROBABILITY = UHConfig.GAMEPLAY_CHANGES.RABBIT.KILLER_RABBIT_SPAWN_PROBABILITY.get(); - - RABBIT_NAME = UHConfig.GAMEPLAY_CHANGES.RABBIT.KILLER_RABBIT_NAME.get().trim(); - } - - @EventHandler (priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onRabbitSpawn(CreatureSpawnEvent ev) - { - if (!RABBIT_SPAWN_ENABLED) - return; - - if (ev.getEntity().getType() != EntityType.RABBIT) - return; - - if (random.nextDouble() >= RABBIT_SPAWN_PROBABILITY) - return; - - Rabbit rabbit = (Rabbit) ev.getEntity(); - rabbit.setRabbitType(Rabbit.Type.THE_KILLER_BUNNY); - - if (!RABBIT_NAME.isEmpty()) - { - rabbit.setCustomName(RABBIT_NAME); - rabbit.setCustomNameVisible(true); - } - } - - - /** - * Used to cancel the spawn of the creatures if the game is not started. - * <p> - * We don't use the peaceful difficulty for that because it causes bugs with Minecraft 1.8 - * (the difficulty is not correctly updated client-side when the game starts). - */ - @EventHandler - public void onCreatureSpawn(CreatureSpawnEvent ev) - { - if (!UHCReloaded.get().getGameManager().isGameStarted() - && isNaturalSpawn(ev.getSpawnReason()) - && isHostile(ev.getEntityType())) - { - ev.setCancelled(true); - } - } - - /** - * Used to cancel the spawn of hostile entities on the surface only, at the beginning of the game. - */ - @EventHandler - public void onSurfaceCreatureSpawn(CreatureSpawnEvent ev) - { - if (UHCReloaded.get().getGameManager().isGameStarted() - && !UHCReloaded.get().getGameManager().isSurfaceSpawnEnabled() - && isNaturalSpawn(ev.getSpawnReason()) - && isHostile(ev.getEntityType())) - { - // We check the blocs above the entity to see if we only find surface blocks. - final Location spawnLocation = ev.getLocation(); - final World world = spawnLocation.getWorld(); - final int highestBlockY = world.getHighestBlockYAt(spawnLocation); - - final int x = spawnLocation.getBlockX(); - final int z = spawnLocation.getBlockZ(); - - boolean surface = true; - - for (int y = spawnLocation.getBlockY(); y <= highestBlockY; y++) - { - switch (world.getBlockAt(x, y, z).getType()) - { - // Air - case AIR: - - // Trees - case LOG: - case LOG_2: - case LEAVES: - case LEAVES_2: - case HUGE_MUSHROOM_1: - case HUGE_MUSHROOM_2: - - // Vegetation - case DEAD_BUSH: - case CROPS: - case GRASS: - case LONG_GRASS: - case DOUBLE_PLANT: - case YELLOW_FLOWER: - case VINE: - case SUGAR_CANE_BLOCK: - case BROWN_MUSHROOM: - case RED_MUSHROOM: - - // Nature - case SNOW: - - // Igloos - case SNOW_BLOCK: - - // Villages - case WOOD: - case WOOD_STAIRS: - case SANDSTONE_STAIRS: - case BOOKSHELF: - - // Redstone - case REDSTONE_WIRE: - case REDSTONE_COMPARATOR: - case REDSTONE_COMPARATOR_OFF: - case REDSTONE_COMPARATOR_ON: - case REDSTONE_TORCH_OFF: - case REDSTONE_TORCH_ON: - - // Other blocs frequently used on surface on custom maps - case TORCH: - case RAILS: - case ACTIVATOR_RAIL: - case DETECTOR_RAIL: - case POWERED_RAIL: - break; - - default: - surface = false; - } - - if (!surface) break; - } - - if (surface) ev.setCancelled(true); - } - } - - - /** - * Checks if a spawn is natural. - * - * @param reason The spawn reason. - * @return {@code true} if it's a natural spawn (not from a player or an interaction - * with another entity, as example). - */ - private boolean isNaturalSpawn(CreatureSpawnEvent.SpawnReason reason) - { - switch (reason) - { - case NATURAL: - case NETHER_PORTAL: - case LIGHTNING: - case SPAWNER: - return true; - - default: - return false; - } - } - - /** - * Checks if the given mod is hostile. - * @param entity The entity. - * @return {@code true} if hostile. - */ - private boolean isHostile(EntityType entity) - { - Class<? extends Entity> entityClass = entity.getEntityClass(); - - return Monster.class.isAssignableFrom(entityClass) - || Slime.class.isAssignableFrom(entityClass) - || Ghast.class.isAssignableFrom(entityClass); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/misc/MOTDManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/misc/MOTDManager.java deleted file mode 100644 index 4e194dc..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/misc/MOTDManager.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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.misc; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.ChatColor; - - -public class MOTDManager -{ - private UHCReloaded p; - - private boolean enabled; - private String matchName = ""; - - private String currentMOTD; - - public MOTDManager(UHCReloaded plugin) - { - p = plugin; - - enabled = UHConfig.MOTD.ENABLED.get(); - - if (enabled && UHConfig.MOTD.DISPLAY_MATCH_NAME.get()) - { - matchName = ChatColor.translateAlternateColorCodes('&', UHConfig.MOTD.MATCH_NAME_PREFIX.get()) - + p.getScoreboardManager().getScoreboardName() - + ChatColor.RESET + "\n"; - } - } - - /** - * Returns the current MOTD. - * - * @return The MOTD. - */ - public String getCurrentMOTD() - { - return currentMOTD; - } - - /** - * Returns true if the state-based MOTDs are enabled. - * - * @return true if enabled. - */ - public boolean isEnabled() - { - return enabled; - } - - - /** - * Updates the MOTD to the one displayed before the game start. - */ - public void updateMOTDBeforeStart() - { - /// MOTD when the game is not started. - if (enabled) currentMOTD = matchName + I.t("Waiting for players..."); - } - - /** - * Updates the MOTD to the one displayed during the start. - */ - public void updateMOTDDuringStart() - { - /// MOTD when the game is starting (slow TP in progress). - if (enabled) currentMOTD = matchName + I.t("Starting in progress..."); - } - - /** - * Updates the MOTD to the one displayed during the game (includes alive counts). - * <p> - * This need to be called on each death, to update alive counts. - */ - public void updateMOTDDuringGame() - { - if (enabled) - { - if (!p.getGameManager().isGameWithTeams()) - { - /// Solo game running MOTD. {0} = players alive count. - currentMOTD = matchName + I.tn("Game running! {0} player alive.", "Game running! {0} players alive.", p.getGameManager().getAlivePlayersCount(), p.getGameManager().getAlivePlayersCount()); - } - else - { - /// Teams game running MOTD. {0} = players alive count. {1} = teams alive count. Plural based on players count. - currentMOTD = matchName + I.tn("Game running! {0} player alive in {1} team.", "Game running! {0} players alive in {1} teams.", p.getGameManager().getAlivePlayersCount(), p.getGameManager().getAlivePlayersCount(), p.getGameManager().getAliveTeamsCount()); - } - } - } - - /** - * Updates the MOTD after the game. - * - * @param winner The winner. - */ - public void updateMOTDAfterGame(UHTeam winner) - { - if (enabled) - { - if (!p.getGameManager().isGameWithTeams()) - { - /// Game finished MOTD with solo winner ({0} = winner raw name). - currentMOTD = matchName + I.t("Game finished; congratulation to {0} for his victory!", winner.getName()); - } - else - { - /// Game finished MOTD with team winner ({0} = team display name). - currentMOTD = matchName + I.t("Game finished; the team {0} wins this match!", winner.getDisplayName()); - } - } - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/misc/PlayerListHeaderFooterManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/misc/PlayerListHeaderFooterManager.java deleted file mode 100644 index f2b1b3c..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/misc/PlayerListHeaderFooterManager.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.misc; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.text.ListHeaderFooter; -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; - - -public class PlayerListHeaderFooterManager -{ - private final String WAITING_HEADER_PATTERN; - private final String WAITING_FOOTER_PATTERN; - private final String IN_GAME_HEADER_PATTERN; - private final String IN_GAME_FOOTER_PATTERN; - - private String currentHeader = ""; - private String currentFooter = ""; - - - public PlayerListHeaderFooterManager() - { - WAITING_HEADER_PATTERN = UHConfig.PLAYERS_LIST.WAITING_TIME.HEADER.get(); - WAITING_FOOTER_PATTERN = UHConfig.PLAYERS_LIST.WAITING_TIME.FOOTER.get(); - IN_GAME_HEADER_PATTERN = UHConfig.PLAYERS_LIST.IN_GAME_TIME.HEADER.get(); - IN_GAME_FOOTER_PATTERN = UHConfig.PLAYERS_LIST.IN_GAME_TIME.FOOTER.get(); - - updateHeadersFooters(); - } - - - public void updateHeadersFooters() - { - computeHeadersFooter(); - send(); - } - - public void sendTo(Player player) - { - if (!currentHeader.isEmpty() || !currentFooter.isEmpty()) - ListHeaderFooter.sendListHeaderFooter(player, currentHeader, currentFooter); - } - - - private void computeHeadersFooter() - { - if (UHCReloaded.get().getGameManager().isGameStarted()) - { - currentHeader = computeText(IN_GAME_HEADER_PATTERN); - currentFooter = computeText(IN_GAME_FOOTER_PATTERN); - } - else - { - currentHeader = computeText(WAITING_HEADER_PATTERN); - currentFooter = computeText(WAITING_FOOTER_PATTERN); - } - } - - private String computeText(String pattern) - { - return pattern.isEmpty() ? "" : ChatColor.translateAlternateColorCodes('&', replaceTags(pattern)); - } - - /** - * Tags: - * - {title}: contains the scoreboard title (key scoreboard.title). - * - {episodeText}: contains the localized “Episode x” text. - * - {playersText}: contains the localized “x players left” text. - * - {teamsText}: contains the localized “x teams left” text. - * - {episodeNumber}: contains the raw episode number (e.g. “2”). - * - {playersCount}: contains the raw alive players count (e.g. “18”). - * - {teamsCount}: contains the raw alive teams count (e.g. “6”). - * - * @param raw The raw text. - * @return The text, with tags replaced. - */ - private String replaceTags(String raw) - { - return raw - .replace("{title}", UHConfig.SCOREBOARD.TITLE.get()) - - /// Episode in the player list ({episodeText} replacement). {0} = current episode number. - .replace("{episodeText}", I.t("Episode {0}", String.valueOf(UHCReloaded.get().getGameManager().getEpisode()))) - /// Players in the player list ({playersText} replacement). {0} = current alive players count. - .replace("{playersText}", I.tn("{0} player", "{0} players", UHCReloaded.get().getGameManager().getAlivePlayersCount(), UHCReloaded.get().getGameManager().getAlivePlayersCount())) - /// Teams in the player list ({teamsText} replacement). {0} = current alive teams count. - .replace("{teamsText}", I.tn("{0} team", "{0} teams", UHCReloaded.get().getGameManager().getAliveTeamsCount(), UHCReloaded.get().getGameManager().getAliveTeamsCount())) - - .replace("{episodeNumber}", String.valueOf(UHCReloaded.get().getGameManager().getEpisode())) - .replace("{playersCount}", String.valueOf(UHCReloaded.get().getGameManager().getAlivePlayersCount())) - .replace("{teamsCount}", String.valueOf(UHCReloaded.get().getGameManager().getAliveTeamsCount())) - ; - } - - private void send() - { - if (!currentHeader.isEmpty() || !currentFooter.isEmpty()) - ListHeaderFooter.sendListHeaderFooter(currentHeader, currentFooter); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/misc/RuntimeCommandsExecutor.java b/src/main/java/eu/carrade/amaury/UHCReloaded/misc/RuntimeCommandsExecutor.java deleted file mode 100644 index 4b4a3e3..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/misc/RuntimeCommandsExecutor.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * 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.misc; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.task.ScheduledCommandsExecutorTask; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.tools.runners.RunTask; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - - -/** - * This will execute the commands to be executed during runtime, as configured in the config.yml file - * or added through the API. - */ -public class RuntimeCommandsExecutor -{ - private final UHCReloaded p; - - /** - * Stores the commands to be executed later. - * <p> - * The first map (String->HashMap) associates a key to a group of commands launched at the same time.<br> - * The sub-map (Integer->HashSet) associates a delay, in seconds, with a set containing the commands to be - * executed this number of seconds after the call of the {@link #registerCommandsInScheduler(String)} - * method. - */ - private final Map<String, HashMap<Integer, HashSet<String>>> scheduled = new HashMap<>(); - - - /** - * The key for the commands executed when the server starts. - */ - public final static String AFTER_SERVER_START = "internal.server-start"; - - /** - * The key for the commands executed after the beginning of the game. - */ - public final static String AFTER_GAME_START = "internal.game-start"; - - /** - * The key for the commands executed after the end of the game. - */ - public final static String AFTER_GAME_END = "internal.game-end"; - - - public RuntimeCommandsExecutor() - { - p = UHCReloaded.get(); - - importFromConfig("commands.execute-server-start", AFTER_SERVER_START); - importFromConfig("commands.execute-start", AFTER_GAME_START); - importFromConfig("commands.execute-end", AFTER_GAME_END); - } - - /** - * Register the commands registered under the given key in the Bukkit' scheduler. - * <p> - * Delays are from the execution of this method. - * - * @param key The key to schedule. All commands previously registered under this key will be executed. - */ - public void registerCommandsInScheduler(String key) - { - registerCommandsInScheduler(scheduled.get(key)); - } - - /** - * Register the given commands in the Bukkit' scheduler. - * - * Delays are from the execution of this method. - * @param scheduledCommands - */ - private void registerCommandsInScheduler(Map<Integer, HashSet<String>> scheduledCommands) - { - if (scheduledCommands != null) - { - for (Entry<Integer, HashSet<String>> scheduledCommandsStack : scheduledCommands.entrySet()) - { - RunTask.later( - new ScheduledCommandsExecutorTask(scheduledCommandsStack.getValue()), - scheduledCommandsStack.getKey() * 20L - ); - } - } - } - - - /** - * Schedules a command. - * <p> - * To schedule a command executed by the plugin, like in the configuration file, you will have - * to use the keys defined as static attributes of this class: - * {@link #AFTER_SERVER_START}, {@link #AFTER_GAME_END} and {@link #AFTER_GAME_START}. - * - * @param key The command will be stored under this key. - * The keys internally used by the plugin start by "{@code internal.}". - * @param command The command to add. - * @param delay The delay (seconds). - */ - public void scheduleCommand(String key, String command, Integer delay) - { - final Map<Integer, HashSet<String>> commandsMap = scheduled.computeIfAbsent(key, k -> new HashMap<>()); - scheduleCommand(commandsMap, command, delay); - } - - /** - * Schedules a command. - * - * @param scheduledCommands A map containing the scheduled commands, sorted by delay. - * @param command The command to add. - * @param delay The delay (seconds). - */ - private void scheduleCommand(Map<Integer, HashSet<String>> scheduledCommands, String command, Integer delay) - { - final Set<String> list = scheduledCommands.computeIfAbsent(delay, k -> new HashSet<>()); - list.add(clearCommandName(command)); - } - - - /** - * Removes the given command from everywhere. - * - * @param key The command will be stored under this key. - * The keys internally used by the plugin start by "{@code internal.}". - * @param command The command. Not case-sensitive. - */ - public void removeScheduledCommand(String key, String command) - { - removeScheduledCommand(scheduled.get(key), command); - } - - /** - * Removes the given command from everywhere. - * - * @param scheduledCommands A map containing the scheduled commands, sorted by delay. - * @param command The command. Not case-sensitive. - */ - private void removeScheduledCommand(Map<Integer, HashSet<String>> scheduledCommands, String command) - { - for (HashSet<String> commands : scheduledCommands.values()) - { - for (String scheduledCommand : new HashSet<>(commands)) - { - if (scheduledCommand.equalsIgnoreCase(clearCommandName(command))) - { - commands.remove(scheduledCommand); - } - } - } - } - - - /** - * Removes the given command from everywhere. - * - * @param key The command will be stored under this key. - * The keys internally used by the plugin start by "{@code internal.}". - * @param command The command. Not case-sensitive. - */ - public void removeScheduledCommand(String key, String command, Integer delay) - { - removeScheduledCommand(scheduled.get(key), command, delay); - } - - /** - * Removes the given command from everywhere. - * - * @param scheduledCommands A map containing the scheduled commands, sorted by delay. - * @param command The command. Not case-sensitive. - */ - private void removeScheduledCommand(Map<Integer, HashSet<String>> scheduledCommands, String command, Integer delay) - { - HashSet<String> commands = scheduledCommands.get(delay); - - if (commands != null) - { - commands.stream() - .filter(scheduledCommand -> scheduledCommand.equalsIgnoreCase(clearCommandName(command))) - .forEach(commands::remove); - } - } - - - /* Utilities */ - - /** - * Imports the commands stored in the configuration. - * - * @param path The path in the config file. - * @param key The command will be stored under this key. - * The keys internally used by the plugin start by "{@code internal.}". - */ - private void importFromConfig(String path, String key) - { - List<Map<?, ?>> rawCommands = p.getConfig().getMapList(path); - - if (rawCommands != null) - { - for (Map<?, ?> rawCommand : rawCommands) - { - String cmd = String.valueOf(rawCommand.get("exec")); - Integer delay; - - if (cmd == null || cmd.isEmpty()) continue; - - try - { - delay = UHUtils.string2Time(String.valueOf(rawCommand.get("delay"))); - } - catch (IllegalArgumentException e) - { - delay = 0; - } - - scheduleCommand(key, cmd, delay); - } - } - } - - - private String clearCommandName(String command) - { - if (command.startsWith("/")) - { - command = command.substring(1); - } - - return command; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTip.java b/src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTip.java deleted file mode 100644 index 94f1f25..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTip.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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.protips; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.utils.UHSound; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; - -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CopyOnWriteArraySet; - - -/** - * A ProTip, sent to a player only once. - */ -public class ProTip -{ - private static final UHSound proTipsSound = new UHSound(UHConfig.PROTIPS.SOUND); - - private String text; - private Boolean enabled; - - private Set<UUID> sentTo = new CopyOnWriteArraySet<>(); - - - /** - * @param enabled {@code false} to avoid this ProTip from being sent when {@link #sendTo(Player)} is called. - * @param text The ProTip text. - */ - public ProTip(Boolean enabled, String text) - { - this.text = text; - this.enabled = enabled; - } - - /** - * @param name A name registered in the UHCReloaded config file, used to disable the powerup if needed, following the configuration. - * @param text The ProTip text. - */ - public ProTip(String name, String text) - { - this(UHCReloaded.get().getConfig().getBoolean("protips." + name), text); - } - - - public void setEnabled(Boolean enabled) - { - this.enabled = enabled; - } - - public String getText() - { - return text; - } - - public Boolean isEnabled() - { - return enabled; - } - - - /** - * Checks if this ProTip was sent to this player. - * - * @param id The player's UUID. - * @return {@code true} if already sent. - */ - public Boolean wasSentTo(UUID id) - { - return sentTo.contains(id); - } - - /** - * Checks if this ProTip was sent to this player. - * - * @param player The player. - * @return {@code true} if already sent. - */ - public Boolean wasSentTo(Player player) - { - return wasSentTo(player.getUniqueId()); - } - - - /** - * Sends a ProTip, if this ProTip wasn't sent before to this player. - * - * @param player The receiver of this ProTip. - */ - public void sendTo(Player player) - { - if (!isEnabled() || wasSentTo(player)) - return; - - sentTo.add(player.getUniqueId()); - - /// ProTip invite, displayed before a ProTip. - player.sendMessage(I.t("{darkpurple}ProTip!") + " " + ChatColor.RESET + text); - proTipsSound.play(player); - } - - /** - * Sends a ProTip, if this ProTip wasn't sent before to this player and this player is online. - * - * @param id The receiver of this ProTip. - */ - public void sendTo(UUID id) - { - Player player = Bukkit.getPlayer(id); - if (player != null && player.isOnline()) - sendTo(player); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java b/src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java deleted file mode 100644 index 602ed75..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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.protips; - -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.entity.Player; - -import java.util.UUID; - - -public enum ProTips -{ - LOCK_CHAT(new ProTip("teamchat.lock", I.tc("protip", "{gray}You can lock and unlock the team chat with {cc}/togglechat{gray}."))), - USE_G_COMMAND(new ProTip("teamchat.useGCommand", I.tc("protip", "{gray}You can send a global message using {cc}/g <message>{gray}."))), - USE_T_COMMAND(new ProTip("teamchat.useTCommand", I.tc("protip", "{gray}You can send a team-chat message with {cc}/t <message>{gray}."))), - - CRAFT_GOLDEN_HEAD(new ProTip("crafts.goldenHead", I.tc("protip", "{gray}You can craft golden apples with heads (same recipe with a head instead of an apple)."))), - CRAFT_COMPASS_EASY(new ProTip("crafts.compassEasy", I.tc("protip", "{gray}The compass is crafted with, in the corners, a bone, a rotten flesh, a spider eye and a gunpowder."))), - CRAFT_COMPASS_MEDIUM(new ProTip("crafts.compassMedium", I.tc("protip", "{gray}The compass is crafted with, in the corners, a bone, a rotten flesh, a spider eye and a gunpowder; in the center, an ender pearl."))), - CRAFT_COMPASS_HARD(new ProTip("crafts.compassHard", I.tc("protip", "{gray}The compass is crafted with, in the corners, a bone, a rotten flesh, a spider eye and a gunpowder; in the center, an Eye of Ender."))), - CRAFT_GLISTERING_MELON(new ProTip("crafts.glisteringMelon", I.tc("protip", "{gray}The glistering melon is crafted with a melon and a gold block."))), - - CRAFT_NO_ENCHANTED_GOLDEN_APPLE(new ProTip("crafts.noEnchGoldenApple", I.tc("protip", "{gray}The enchanted golden apple is disabled for this game."))), - - STARTUP_INVINCIBILITY(new ProTip("start.invincibility", I.tc("protip", "{gray}Fallen on a tree? Jump, you have a few seconds left to remain invincible."))); - - - private final ProTip proTip; - - ProTips(ProTip proTip) - { - this.proTip = proTip; - } - - public ProTip get() - { - return proTip; - } - - - /** - * Sends this ProTip, if it wasn't sent before to this player. - * - * @param player The receiver of this ProTip. - */ - public void sendTo(Player player) - { - proTip.sendTo(player); - } - - /** - * Sends this ProTip, if it wasn't sent before to this player and this player is online. - * - * @param id The receiver of this ProTip. - */ - public void sendTo(UUID id) - { - proTip.sendTo(id); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java deleted file mode 100644 index ef25aa9..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java +++ /dev/null @@ -1,532 +0,0 @@ -/* - * 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.recipes; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import fr.zcraft.zlib.components.gui.GuiUtils; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.SkullType; -import org.bukkit.inventory.CraftingInventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.Recipe; -import org.bukkit.inventory.ShapedRecipe; -import org.bukkit.inventory.ShapelessRecipe; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.SkullMeta; - -import java.util.ArrayList; - - -public class RecipesManager -{ - private UHCReloaded p = null; - - private Material compassCentralIngredient = null; - private int compassRecipeType = -1; - - public static final String RECIPE_COMPASS = "compass"; - public static final String RECIPE_GLISTERING_MELON = "glistering"; - public static final String RECIPE_ENCHANTED_GOLDEN_APPLE = "EGA"; - - public static final int COMPASS_DISABLED = 0; - public static final int COMPASS_EASY = 1; - public static final int COMPASS_MEDIUM = 2; - public static final int COMPASS_HARD = 3; - - private String lastFailedRecipe = null; - - - public RecipesManager(UHCReloaded plugin) - { - this.p = plugin; - } - - - /** - * Registers the recipes needed, following the configuration. - */ - public void registerRecipes() - { - - if (UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_HUMAN.DO.get()) - { - p.getServer().addRecipe(getGoldenHeadHumanRecipe()); - } - - if (UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_WITHER.DO.get()) - { - p.getServer().addRecipe(getGoldenHeadMonsterRecipe()); - } - - if (UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_HUMAN.ADD_LORE.get() || UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_WITHER.ADD_LORE.get()) - { - p.getServer().addRecipe(getLoreRemoverNormalRecipe()); - p.getServer().addRecipe(getLoreRemoverNotchRecipe()); - } - - if (UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_MELON_WITH_GOLD_BLOCK.get()) - { - p.getServer().addRecipe(getGoldenMelonRecipe()); - } - - // Because the compass recipe is "semi-shapeless" (the central part is fixed, but the - // loots can be placed into any configuration), there isn't a registered recipe for it - // (I don't want to register 16 recipes for each difficulty). - // Instead, using the inventoryClickEvent/inventoryDragEvent, we checks manually if the - // recipe is valid. - switch (this.getCompassRecipeType()) - { - case COMPASS_EASY: - compassCentralIngredient = Material.REDSTONE; - break; - case COMPASS_MEDIUM: - compassCentralIngredient = Material.ENDER_PEARL; - break; - case COMPASS_HARD: - compassCentralIngredient = Material.EYE_OF_ENDER; - break; - case COMPASS_DISABLED: - break; - } - } - - /** - * Checks if a recipe is allowed. - * - * @param recipe The recipe to be checked. - * @return True if the recipe is allowed, false else. - */ - public boolean isRecipeAllowed(Recipe recipe) - { - // Vanilla compass recipe is disabled if the special compass is used. - if (UHConfig.GAMEPLAY_CHANGES.COMPASS.ENABLED.get() && RecipeUtil.areSimilar(recipe, getVanillaCompassRecipe())) - { - this.lastFailedRecipe = RECIPE_COMPASS; - return false; - } - - // Vanilla golden melon recipe is disabled if the craft with a gold block is enabled. - if (UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_MELON_WITH_GOLD_BLOCK.get() && RecipeUtil.areSimilar(recipe, getVanillaGoldenMelonRecipe())) - { - this.lastFailedRecipe = RECIPE_GLISTERING_MELON; - return false; - } - - // If enchanted golden apples are disabled... - // The same technique does not work, this is a workaround - if (UHConfig.GAMEPLAY_CHANGES.GOLDEN_APPLE.DISABLE_NOTCH_APPLES.get()) - { - if (recipe.getResult().getType() == Material.GOLDEN_APPLE) - { - for (ItemStack item : RecipeUtil.getListOfIngredients(recipe)) - { - if (item.getType() == Material.GOLD_BLOCK) - { - // There is a gold block in a recipe for a golden apple - NOPE NOPE NOPE - this.lastFailedRecipe = RECIPE_ENCHANTED_GOLDEN_APPLE; - return false; - } - } - } - } - - // The recipe is allowed. - return true; - } - - /** - * Checks if the recipe is a valid compass recipe. - * <p> - * A valid compass recipe is a recipe with: - * <ul> - * <li> - * in the center, the valid ingredient for the current compass craft - * (redstone, ender pearl or eye of ender); - * </li> - * <li> - * four iron ingots placed like the vanilla compass recipe; - * </li> - * <li> - * in the four corners, a bone, a rotten flesh, a spider eye and a gunpowder, - * placed in any shape. - * </li> - * </ul> - * <p> - * Executed in the {@code onInventoryClick} and {@code onInventoryDrag} events, to allow this to be recognized even if - * the recipe is not registered. - * - * @param matrix The content of the crafting inventory. - * @return true if the recipe is an alternate recipe for the compass. - */ - public boolean isValidCompassRecipe(ItemStack[] matrix) - { - if (matrix.length <= 5) - { - return false; // Small crafting grid - } - - if (this.getCompassRecipeType() == COMPASS_DISABLED) - { - return false; - } - - - // 1: check of the static part (central ingredient + iron) - - Material iron1 = matrix[1].getType(); - Material iron2 = matrix[3].getType(); - Material iron3 = matrix[5].getType(); - Material iron4 = matrix[7].getType(); - Material centralIngredient = matrix[4].getType(); - - if (!(iron1.equals(Material.IRON_INGOT) - && iron2.equals(Material.IRON_INGOT) - && iron3.equals(Material.IRON_INGOT) - && iron4.equals(Material.IRON_INGOT) - && centralIngredient.equals(compassCentralIngredient))) - { - return false; - } - - // 2: check of the dynamic part (loots) - - ArrayList<Material> corners = new ArrayList<>(); - corners.add(matrix[0].getType()); - corners.add(matrix[2].getType()); - corners.add(matrix[6].getType()); - corners.add(matrix[8].getType()); - - return corners.contains(Material.BONE) - && corners.contains(Material.ROTTEN_FLESH) - && corners.contains(Material.SPIDER_EYE) - && corners.contains(Material.SULPHUR); - } - - - /** - * Adds the lore to the golden apples, if needed. - * - * @param recipe The recipe to change. - * @param inventory The crafting inventory (used to access the skull owner) - * @return The modified result (ItemStack) if a change was needed. Null if no change is needed. - */ - public ItemStack addLore(Recipe recipe, CraftingInventory inventory) - { - if ((UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_HUMAN.DO.get() || UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_WITHER.DO.get()) - && (UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_HUMAN.ADD_LORE.get() || UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_WITHER.ADD_LORE.get()) - && (RecipeUtil.areSimilar(recipe, getGoldenHeadHumanRecipe()) || RecipeUtil.areSimilar(recipe, getGoldenHeadMonsterRecipe()))) - { - ItemStack result = recipe.getResult(); - ItemMeta meta = result.getItemMeta(); - - // Lookup for the head in the recipe - String name = ""; - Boolean wither = true; - - for (ItemStack item : inventory.getContents()) - { - // An human head - if (item.getType() == Material.SKULL_ITEM && item.getDurability() == (short) SkullType.PLAYER.ordinal()) - { - SkullMeta sm = (SkullMeta) item.getItemMeta(); - if (sm.hasOwner()) // An human head - { - name = sm.getOwner(); - wither = false; - } - break; - } - } - - if ((wither && UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_WITHER.ADD_LORE.get()) - || (!wither && UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_HUMAN.ADD_LORE.get())) - { - if (wither) - { - /// Golden head lore for withers - meta.setLore(GuiUtils.generateLore(I.t("Made from the fallen head of a malignant monster"))); - } - else - { - /// Golden head lore for players. {0} = player name. - meta.setLore(GuiUtils.generateLore(I.t("Made from the fallen head of {0}", name))); - } - } - - result.setItemMeta(meta); - return result; - } - - return null; - } - - /** - * Changes the name of the result item of the anti-lore recipe, - * to keep the same name than the original. - * - * @param recipe The recipe. - * @param inventory The crafting inventory. Used to get the name of the item placed in the inventory grid. - * @return The ItemStack if a change was needed; null else. - */ - public ItemStack keepNameOnLoreRemover(Recipe recipe, CraftingInventory inventory) - { - if ((UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_HUMAN.ADD_LORE.get() || UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_WITHER.ADD_LORE.get()) - && (RecipeUtil.areSimilar(recipe, getLoreRemoverNormalRecipe()) || RecipeUtil.areSimilar(recipe, getLoreRemoverNotchRecipe()))) - { - - ItemStack original = null; - for (int slot = 0; slot <= 9; slot++) - { - original = inventory.getMatrix()[slot]; - if (original.getType() != Material.AIR) - { - break; // Found (because there is only one item in the craft). - } - } - - ItemMeta metaOriginal = original.getItemMeta(); - - if (metaOriginal != null && metaOriginal.hasDisplayName()) - { - ItemStack result = recipe.getResult(); - ItemMeta metaResult = result.getItemMeta(); - - metaResult.setDisplayName(metaOriginal.getDisplayName()); - result.setItemMeta(metaResult); - - return result; - } - - return null; - } - - return null; - } - - - /** - * Returns the current compass recipe. - * - * @return {@link RecipesManager#COMPASS_DISABLED}, {@link RecipesManager#COMPASS_EASY}, - * {@link RecipesManager#COMPASS_MEDIUM} or {@link RecipesManager#COMPASS_HARD}. - */ - public int getCompassRecipeType() - { - if (compassRecipeType != -1) - { - return compassRecipeType; - } - - if (UHConfig.GAMEPLAY_CHANGES.COMPASS.ENABLED.get()) - { - switch (UHConfig.GAMEPLAY_CHANGES.COMPASS.RECIPE.get().toLowerCase()) - { - case "easy": - compassRecipeType = COMPASS_EASY; - break; - - case "hard": - compassRecipeType = COMPASS_HARD; - break; - - default: - compassRecipeType = COMPASS_MEDIUM; - break; - } - } - else - { - compassRecipeType = COMPASS_DISABLED; - } - - return compassRecipeType; - } - - /** - * Returns the recipe that transforms 8 gold ingots and 1 human head into - * a golden apple. - * - * @return The shaped recipe. - */ - public ShapedRecipe getGoldenHeadHumanRecipe() - { - short damage = 0; - /// Item name of a golden head (from a player) - String name = I.tc("player_head", "{aqua}Golden head"); - - if (UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_HUMAN.CRAFT_NOTCH_APPLE.get()) - { - damage = 1; - /// Item name of an enchanted golden head (from a player) - name = I.tc("player_head", "{lightpurple}Golden head"); - } - - final ItemStack goldenAppleStack = new ItemStack(Material.GOLDEN_APPLE, UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_HUMAN.NUMBER_CRAFTED.get(), damage); - final ItemMeta goldenAppleMeta = goldenAppleStack.getItemMeta(); - goldenAppleMeta.setDisplayName(ChatColor.RESET + name); - goldenAppleStack.setItemMeta(goldenAppleMeta); - - final ShapedRecipe goldenAppleFromHeadRecipe = new ShapedRecipe(goldenAppleStack); - - goldenAppleFromHeadRecipe.shape("GGG", "GHG", "GGG"); - goldenAppleFromHeadRecipe.setIngredient('G', Material.GOLD_INGOT); - goldenAppleFromHeadRecipe.setIngredient('H', Material.SKULL_ITEM, SkullType.PLAYER.ordinal()); // TODO: deprecated, but no alternative found... - - return goldenAppleFromHeadRecipe; - } - - /** - * Returns the recipe that transforms 8 gold ingots and 1 wither head into - * a golden apple. - * - * @return The shaped recipe. - */ - public ShapedRecipe getGoldenHeadMonsterRecipe() - { - short damage = 0; - /// Item name of a golden head (from a monster) - String name = I.tc("monster_head", "{aqua}Golden head"); - - if (UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_WITHER.CRAFT_NOTCH_APPLE.get()) - { - damage = 1; - /// Item name of an enchanted golden head (from a monster) - name = I.tc("monster_head", "{lightpurple}Golden head"); - } - - final ItemStack goldenAppleStack = new ItemStack(Material.GOLDEN_APPLE, UHConfig.GAMEPLAY_CHANGES.CRAFT_GOLDEN_APPLE_FROM_HEAD.FROM_WITHER.NUMBER_CRAFTED.get(), damage); - final ItemMeta goldenAppleMeta = goldenAppleStack.getItemMeta(); - goldenAppleMeta.setDisplayName(ChatColor.RESET + name); - goldenAppleStack.setItemMeta(goldenAppleMeta); - - final ShapedRecipe goldenAppleFromWitherHeadRecipe = new ShapedRecipe(goldenAppleStack); - - goldenAppleFromWitherHeadRecipe.shape("GGG", "GHG", "GGG"); - goldenAppleFromWitherHeadRecipe.setIngredient('G', Material.GOLD_INGOT); - goldenAppleFromWitherHeadRecipe.setIngredient('H', Material.SKULL_ITEM, SkullType.WITHER.ordinal()); // TODO: deprecated, but no alternative found... - - return goldenAppleFromWitherHeadRecipe; - } - - /** - * Returns the recipe that transforms one golden apple into one golden apple. - * Used to remove the lore, so two apples from a different head are stackable. - * - * @return The shapeless recipe. - */ - public ShapelessRecipe getLoreRemoverNormalRecipe() - { - final ShapelessRecipe goldenAppleLoreRemoverRecipe = new ShapelessRecipe(new ItemStack(Material.GOLDEN_APPLE, 1, (short) 0)); - goldenAppleLoreRemoverRecipe.addIngredient(Material.GOLDEN_APPLE); - - return goldenAppleLoreRemoverRecipe; - } - - /** - * Returns the recipe that transforms one enchanted golden apple into one enchanted - * golden apple. - * Used to remove the lore, so two apples from a different head are stackable. - * - * @return The shapeless recipe. - */ - public ShapelessRecipe getLoreRemoverNotchRecipe() - { - final ShapelessRecipe goldenAppleLoreRemoverNotchRecipe = new ShapelessRecipe(new ItemStack(Material.GOLDEN_APPLE, 1, (short) 1)); - goldenAppleLoreRemoverNotchRecipe.addIngredient(Material.GOLDEN_APPLE, 1); - - return goldenAppleLoreRemoverNotchRecipe; - } - - /** - * Returns the recipe that transforms one melon and one gold block into a golden melon. - * - * @return The shapeless recipe. - */ - public ShapelessRecipe getGoldenMelonRecipe() - { - final ShapelessRecipe goldenMelonRecipe = new ShapelessRecipe(new ItemStack(Material.SPECKLED_MELON)); - goldenMelonRecipe.addIngredient(1, Material.GOLD_BLOCK); - goldenMelonRecipe.addIngredient(1, Material.MELON); - - return goldenMelonRecipe; - } - - /** - * Returns the vanilla recipe for the compass. - * - * @return The shaped recipe. - */ - public ShapedRecipe getVanillaCompassRecipe() - { - final ShapedRecipe vanillaCompassRecipe = new ShapedRecipe(new ItemStack(Material.COMPASS)); - vanillaCompassRecipe.shape(" I ", "IRI", " I "); - - vanillaCompassRecipe.setIngredient('I', Material.IRON_INGOT); - vanillaCompassRecipe.setIngredient('R', Material.REDSTONE); - - return vanillaCompassRecipe; - } - - /** - * Returns the vanilla recipe for the golden melon. - * - * @return The shaped recipe. - */ - public ShapedRecipe getVanillaGoldenMelonRecipe() - { - ShapedRecipe vanillaGoldenMelonRecipe = new ShapedRecipe(new ItemStack(Material.SPECKLED_MELON)); - vanillaGoldenMelonRecipe.shape("GGG", "GMG", "GGG"); - - vanillaGoldenMelonRecipe.setIngredient('G', Material.GOLD_NUGGET); - vanillaGoldenMelonRecipe.setIngredient('M', Material.MELON); - - return vanillaGoldenMelonRecipe; - } - - - /** - * Returns the last failed recipe. - * - * Use {@link RecipesManager#RECIPE_COMPASS}, {@link RecipesManager#RECIPE_GLISTERING_MELON} and - * {@link RecipesManager#RECIPE_ENCHANTED_GOLDEN_APPLE} to get the type of the failed recipe. - * - * @return the lastFailedRecipe - */ - public String getLastFailedRecipe() - { - return lastFailedRecipe; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java b/src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java deleted file mode 100644 index 4512d5e..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java +++ /dev/null @@ -1,384 +0,0 @@ -/* - * 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.scoreboard; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.borders.MapShape; -import eu.carrade.amaury.UHCReloaded.borders.worldborders.WorldBorder; -import eu.carrade.amaury.UHCReloaded.game.UHGameManager; -import eu.carrade.amaury.UHCReloaded.misc.Freezer; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.components.scoreboard.Sidebar; -import fr.zcraft.zlib.components.scoreboard.SidebarMode; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - - -public class GameSidebar extends Sidebar -{ - private final UHGameManager gameManager; - private final WorldBorder border; - - private final boolean EPISODES_ENABLED; - private final boolean EPISODES_IN_SIDEBAR; - private final boolean PLAYERS_IN_SIDEBAR; - private final boolean TEAMS_IN_SIDEBAR; - private final boolean BORDER_IN_SIDEBAR; - private final boolean KILLS_IN_SIDEBAR; - private final boolean TIMER_IN_SIDEBAR; - private final boolean FREEZE_STATUS_IN_SIDEBAR; - - private final boolean OWN_TEAM_IN_SIDEBAR; - private final String OWN_TEAM_TITLE_COLOR; - private final boolean OWN_TEAM_TITLE_IS_NAME; - private final boolean OWN_TEAM_DISPLAY_HEARTS; - private final boolean OWN_TEAM_COLOR_WHOLE_NAME; - private final boolean OWN_TEAM_STRIKE_DEAD_PLAYERS; - private final boolean OWN_TEAM_DISPLAY_LOGIN_STATE_ITALIC; - private final String OWN_TEAM_DISPLAY_LOGIN_STATE_SUFFIX; - private final boolean OWN_TEAM_DISPLAY_MET_PLAYERS_ONLY; - private final double OWN_TEAM_DISPLAY_MET_PLAYERS_MIN_DISTANCE_SQUARED; - - private final boolean BORDER_DISPLAY_DIAMETER; - - private final String FROOZEN_NULL_TIMER_TEXT; - private final String HEART = "\u2764"; - - private final String sidebarTitle; - private final List<String> sidebarTop = new ArrayList<>(); - private final List<String> sidebarBorder = new ArrayList<>(); - private final List<String> sidebarTimers = new ArrayList<>(); - - - public GameSidebar() - { - gameManager = UHCReloaded.get().getGameManager(); - border = UHCReloaded.get().getBorderManager().getBorderProxy(); - - EPISODES_ENABLED = UHConfig.EPISODES.ENABLED.get(); - EPISODES_IN_SIDEBAR = UHConfig.SCOREBOARD.EPISODE.get(); - PLAYERS_IN_SIDEBAR = UHConfig.SCOREBOARD.PLAYERS.get(); - TEAMS_IN_SIDEBAR = UHConfig.SCOREBOARD.TEAMS.get(); - BORDER_IN_SIDEBAR = UHConfig.SCOREBOARD.BORDER.DISPLAYED.get(); - KILLS_IN_SIDEBAR = UHConfig.SCOREBOARD.KILLS.get(); - TIMER_IN_SIDEBAR = UHConfig.SCOREBOARD.TIMER.get(); - FREEZE_STATUS_IN_SIDEBAR = UHConfig.SCOREBOARD.FREEZE_STATUS.get(); - - OWN_TEAM_IN_SIDEBAR = UHConfig.SCOREBOARD.OWN_TEAM.ENABLED.get(); - OWN_TEAM_TITLE_COLOR = ChatColor.translateAlternateColorCodes('&', UHConfig.SCOREBOARD.OWN_TEAM.TITLE.COLOR.get()); - OWN_TEAM_TITLE_IS_NAME = UHConfig.SCOREBOARD.OWN_TEAM.TITLE.USE_TEAM_NAME.get(); - OWN_TEAM_DISPLAY_HEARTS = UHConfig.SCOREBOARD.OWN_TEAM.CONTENT.DISPLAY_HEARTS.get(); - OWN_TEAM_COLOR_WHOLE_NAME = UHConfig.SCOREBOARD.OWN_TEAM.CONTENT.COLOR_NAME.get(); - OWN_TEAM_STRIKE_DEAD_PLAYERS = UHConfig.SCOREBOARD.OWN_TEAM.CONTENT.STRIKE_DEAD_PLAYERS.get(); - OWN_TEAM_DISPLAY_LOGIN_STATE_ITALIC = UHConfig.SCOREBOARD.OWN_TEAM.CONTENT.LOGIN_STATE.ITALIC.get(); - OWN_TEAM_DISPLAY_LOGIN_STATE_SUFFIX = ChatColor.translateAlternateColorCodes('&', UHConfig.SCOREBOARD.OWN_TEAM.CONTENT.LOGIN_STATE.SUFFIX.get()); - OWN_TEAM_DISPLAY_MET_PLAYERS_ONLY = UHConfig.SCOREBOARD.OWN_TEAM.CONTENT.DISPLAY_MET_PLAYERS_ONLY.ENABLED.get(); - OWN_TEAM_DISPLAY_MET_PLAYERS_MIN_DISTANCE_SQUARED = Math.pow(UHConfig.SCOREBOARD.OWN_TEAM.CONTENT.DISPLAY_MET_PLAYERS_ONLY.DISPLAYED_WHEN_CLOSER_THAN.get(), 2); - - BORDER_DISPLAY_DIAMETER = UHConfig.SCOREBOARD.BORDER.DISPLAY_DIAMETER.get(); - - FROOZEN_NULL_TIMER_TEXT = new UHTimer("").toString(); - - setAsync(true); - setAutoRefreshDelay(20); - setContentMode(SidebarMode.PER_PLAYER); - - sidebarTitle = ChatColor.translateAlternateColorCodes('&', UHConfig.SCOREBOARD.TITLE.get()); - } - - @Override - public void preRender() - { - sidebarTop.clear(); - sidebarBorder.clear(); - sidebarTimers.clear(); - - // Top sidebar - - if (EPISODES_ENABLED && EPISODES_IN_SIDEBAR) - { - /// Current episode in the sidebar - sidebarTop.add(I.t("{gray}Episode {white}{0}", - String.valueOf(gameManager.isGameStarted() ? gameManager.getEpisode() : 0) - )); - } - - if (!gameManager.isGameStarted()) - { - if (PLAYERS_IN_SIDEBAR) - /// Players alive in the sidebar - sidebarTop.add(I.tn("{white}{0}{gray} player", "{white}{0}{gray} players", Bukkit.getOnlinePlayers().size(), Bukkit.getOnlinePlayers().size())); - } - else - { - if (gameManager.isGameWithTeams() && EPISODES_ENABLED && EPISODES_IN_SIDEBAR) - sidebarTop.add(""); - - if (PLAYERS_IN_SIDEBAR) - /// Players alive in the sidebar - sidebarTop.add(I.tn("{white}{0}{gray} player", "{white}{0}{gray} players", gameManager.getAlivePlayersCount(), gameManager.getAlivePlayersCount())); - - if (gameManager.isGameWithTeams() && TEAMS_IN_SIDEBAR) - /// Teams alive in the sidebar - sidebarTop.add(I.tn("{white}{0}{gray} team", "{white}{0}{gray} teams", gameManager.getAliveTeamsCount(), gameManager.getAliveTeamsCount())); - } - - - // Border part of the sidebar - - if (gameManager.isGameStarted()) - { - insertBorder(sidebarBorder); - } - - - // Timers part of the sidebar - - insertTimers(sidebarTimers); - - if (TIMER_IN_SIDEBAR) - { - if (!gameManager.isGameStarted()) - sidebarTimers.add(FROOZEN_NULL_TIMER_TEXT); - else - { - final UHTimer mainTimer = UHCReloaded.get().getTimerManager().getMainTimer(); - if (mainTimer != null) sidebarTimers.add(mainTimer.toString()); - } - } - } - - @Override - public List<String> getContent(Player player) - { - - List<String> sidebar = new ArrayList<>(sidebarTop); - sidebar.add(""); - - if (OWN_TEAM_IN_SIDEBAR && gameManager.isGameStarted() && gameManager.isGameWithTeams()) - { - UHTeam team = UHCReloaded.get().getTeamManager().getTeamForPlayer(player); - - if (team != null) - { - sidebar.add( - (OWN_TEAM_TITLE_COLOR.isEmpty() ? team.getColorOrWhite().toChatColor() : OWN_TEAM_TITLE_COLOR) - /// Title of the team section in the sidebar - + (OWN_TEAM_TITLE_IS_NAME ? ChatColor.BOLD + team.getName() : I.t("{bold}Your team")) - ); - - Location playerLocation = player.getLocation(); - - for (UUID teamMember : team.getPlayersUUID()) - { - SidebarPlayerCache cache = UHCReloaded.get().getScoreboardManager().getSidebarPlayerCache(teamMember); - - // If enabled, we check if the player was already met or is close to this player. - // Only if the damages are on (= 30 seconds after the game start) to avoid false close while - // teleporting. - if(OWN_TEAM_DISPLAY_MET_PLAYERS_ONLY) - { - if(!(teamMember.equals(player.getUniqueId()) || cache.getTeammatesDisplayed().contains(teamMember))) - { - if (gameManager.isGameStarted() && gameManager.isTakingDamage()) - { - if (gameManager.isPlayerDead(teamMember)) - continue; // dead (spectators don't have to be displayed in the sidebar). - - Player teammate = Sidebar.getPlayerAsync(teamMember); - if (teammate == null) - continue; // offline - - - Location teammateLocation = teammate.getLocation(); - - // Check if the players are close - if (teammateLocation.getWorld().equals(playerLocation.getWorld())) - { - final double distanceSquared = teammateLocation.distanceSquared(playerLocation); - if (distanceSquared <= OWN_TEAM_DISPLAY_MET_PLAYERS_MIN_DISTANCE_SQUARED) - cache.getTeammatesDisplayed().add(teamMember); - else - continue; // Too far, skipped - } - else - { - continue; // Too far, skipped - } - } - else - { - continue; - } - } - } - - final String strike = OWN_TEAM_STRIKE_DEAD_PLAYERS && !cache.isAlive() ? ChatColor.STRIKETHROUGH.toString() : ""; - final ChatColor aliveColor = cache.isAlive() ? ChatColor.WHITE : ChatColor.GRAY; - - final String heart = OWN_TEAM_DISPLAY_HEARTS ? cache.getHealthColor() + strike + HEART + " " : ""; - final String name = (OWN_TEAM_COLOR_WHOLE_NAME ? cache.getHealthColor() : aliveColor) - + strike - + (OWN_TEAM_DISPLAY_LOGIN_STATE_ITALIC && !cache.isOnline() ? ChatColor.ITALIC : "") - + cache.getPlayerName() - + (!cache.isOnline() ? ChatColor.RESET + "" + (OWN_TEAM_COLOR_WHOLE_NAME ? cache.getHealthColor() : aliveColor) + " " + OWN_TEAM_DISPLAY_LOGIN_STATE_SUFFIX : ""); - - sidebar.add(heart + name); - } - - sidebar.add(""); - } - } - - sidebar.addAll(sidebarBorder); - - if (KILLS_IN_SIDEBAR && gameManager.isGameStarted()) - { - SidebarPlayerCache cache = UHCReloaded.get().getScoreboardManager().getSidebarPlayerCache(player.getUniqueId()); - - /// Kills count in the sidebar - sidebar.add(I.tn("{white}{0}{gray} player killed", "{white}{0}{gray} players killed", cache.getPlayersKilled().size(), cache.getPlayersKilled().size())); - sidebar.add(""); - } - - sidebar.addAll(sidebarTimers); - - if (FREEZE_STATUS_IN_SIDEBAR) - { - insertFreezeStatus(sidebar, player); - } - - return sidebar; - } - - @Override - public String getTitle(Player player) - { - return sidebarTitle; - } - - - /** - * Inserts the border status in the given list, to be displayed in the sidebar. - * - * @param sidebar The list representing the sidebar's content. - */ - private void insertBorder(List<String> sidebar) - { - if (BORDER_IN_SIDEBAR) - { - /// Title of the border section in the sidebar - sidebar.add(I.t("{blue}{bold}Border")); - - int diameter = (int) Math.ceil(border.getDiameter()); - - if (BORDER_DISPLAY_DIAMETER || border.getShape() == MapShape.CIRCULAR) - { - if (border.getShape() == MapShape.SQUARED) - /// Border diameter for a squared map in the sidebar - sidebar.add(I.tn("{white}{0} block wide", "{white}{0} blocks wide", diameter, diameter)); - else - /// Border diameter for a circular map in the sidebar - sidebar.add(I.tn("{gray}Diameter: {white}{0} block", "{gray}Diameter: {white}{0} blocks", diameter, diameter)); - } - else - { - Location center = border.getCenter(); - int radius = (int) Math.ceil(diameter / 2); - - int minX = center.getBlockX() - radius; - int maxX = center.getBlockX() + radius; - int minZ = center.getBlockZ() - radius; - int maxZ = center.getBlockZ() + radius; - - // Same min & max, we can display both at once - if (minX == minZ && maxX == maxZ) - { - /// Min & max coordinates in the sidebar, to locate the border. Ex: "-500 +500". {0} = minimal coord, {1} = maximal coord. - sidebar.add(I.t("{white}{0} {1}", UHUtils.integerToStringWithSign(minX), UHUtils.integerToStringWithSign(maxZ))); - } - else - { - /// Min & max X coordinates in the sidebar, to locate the border. Ex: "X: -500 +500". {0} = minimal coord, {1} = maximal coord. - sidebar.add(I.t("{gray}X: {white}{0} {1}", UHUtils.integerToStringWithSign(minX), UHUtils.integerToStringWithSign(maxX))); - /// Min & max Z coordinates in the sidebar, to locate the border. Ex: "Z: -500 +500". {0} = minimal coord, {1} = maximal coord. - sidebar.add(I.t("{gray}Z: {white}{0} {1}", UHUtils.integerToStringWithSign(minZ), UHUtils.integerToStringWithSign(maxZ))); - } - } - - sidebar.add(""); - } - } - - /** - * Inserts the timers in the given list, to be displayed in the sidebar, at the bottom of the - * list. - * - * @param sidebar The list representing the sidebar's content. - */ - private void insertTimers(List<String> sidebar) - { - UHCReloaded.get().getTimerManager().getTimers().stream().filter(UHTimer::isDisplayed).forEach(timer -> { - sidebar.add(timer.getDisplayName()); - sidebar.add(timer.toString()); - sidebar.add(""); - }); - } - - /** - * Inserts the « frozen » text at the bottom of the list, if active globally or for the given - * player. - * - * @param sidebar The list representing the sidebar's content. - */ - private void insertFreezeStatus(List<String> sidebar, Player player) - { - final Freezer freezer = UHCReloaded.get().getFreezer(); - - if ((freezer.getGlobalFreezeState() && !freezer.isHiddenFreeze()) || freezer.isPlayerFrozen(player)) - { - sidebar.add(""); - /// Notice displayed at the bottom of the sidebar if the game is paused (/uh freeze all). - sidebar.add(I.t("{darkaqua}Game frozen")); - } - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/ScoreboardManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/ScoreboardManager.java deleted file mode 100644 index 03d80f0..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/ScoreboardManager.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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.scoreboard; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import fr.zcraft.zlib.components.scoreboard.Sidebar; -import fr.zcraft.zlib.tools.runners.RunTask; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.scoreboard.Criterias; -import org.bukkit.scoreboard.DisplaySlot; -import org.bukkit.scoreboard.Objective; -import org.bukkit.scoreboard.Scoreboard; - -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - - -public class ScoreboardManager -{ - private UHCReloaded p; - - private Map<UUID, SidebarPlayerCache> sidebarCache = new ConcurrentHashMap<>(); - - private final Scoreboard sb; - private Sidebar sidebar = null; - - - public ScoreboardManager(UHCReloaded p) - { - this.p = p; - this.sb = Bukkit.getServer().getScoreboardManager().getNewScoreboard(); - - UHCReloaded.get().getServer().getPluginManager().registerEvents(new ScoreboardListener(), UHCReloaded.get()); - - - // Initialization of the scoreboard (match info in the sidebar) - if (UHConfig.SCOREBOARD.ENABLED.get()) - { - sidebar = new GameSidebar(); - - Bukkit.getOnlinePlayers().forEach(player -> sidebar.addRecipient(player)); - - sidebar.runAutoRefresh(true); - } - - // Initialization of the scoreboard (health in players' list) - if (UHConfig.SCOREBOARD.HEALTH.get()) - { - final Objective healthObjective = sb.registerNewObjective("Health", Criterias.HEALTH); - healthObjective.setDisplayName("Health"); - healthObjective.setDisplaySlot(DisplaySlot.PLAYER_LIST); - - // Sometimes, the health is initialized to 0. This is used to fix this. - updateHealthScore(); - } - else - { - sb.clearSlot(DisplaySlot.PLAYER_LIST); // Just in case - } - - // Initialization of the sidebar cache - // Initializes the object. - Bukkit.getOnlinePlayers().stream().map(Entity::getUniqueId).forEach(this::getSidebarPlayerCache); - } - - - /** - * Updates the health score for all players. - */ - public void updateHealthScore() - { - p.getServer().getOnlinePlayers().forEach(this::updateHealthScore); - } - - /** - * Updates the health score for the given player. - * - * @param player The player to update. - */ - public void updateHealthScore(final Player player) - { - if (player.getHealth() != 1d) // Prevents killing the player - { - player.setHealth(player.getHealth() - 1); - - RunTask.later(() -> - { - if (player.getHealth() <= 19d) // Avoids an IllegalArgumentException - { - player.setHealth(player.getHealth() + 1); - } - }, 3L); - } - } - - /** - * Tells the player's client to use this scoreboard. - * - * @param p The player. - */ - public void setScoreboardForPlayer(Player p) - { - p.setScoreboard(sb); - sidebar.addRecipient(p); - } - - /** - * Returns the title of the scoreboard, truncated at 32 characters. - * - * @return The name - */ - public String getScoreboardName() - { - String s = ChatColor.translateAlternateColorCodes('&', UHConfig.SCOREBOARD.TITLE.get()); - return s.substring(0, Math.min(s.length(), 32)); - } - - /** - * Returns the internal scoreboard. - * - * @return The internal scoreboard. - */ - public Scoreboard getScoreboard() - { - return sb; - } - - /** - * Returns the cached data about the given player. - * - * @param id The player's UUID. - * @return The cached data, created on the fly if needed. - */ - public SidebarPlayerCache getSidebarPlayerCache(UUID id) - { - return sidebarCache.computeIfAbsent(id, SidebarPlayerCache::new); - } - - public Map<UUID, SidebarPlayerCache> getAllSidebarPlayerCache() - { - return sidebarCache; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/SidebarPlayerCache.java b/src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/SidebarPlayerCache.java deleted file mode 100644 index ca48c13..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/SidebarPlayerCache.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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.scoreboard; - -import eu.carrade.amaury.UHCReloaded.misc.OfflinePlayersLoader; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.components.scoreboard.Sidebar; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; - -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CopyOnWriteArraySet; - - -/** - * This class stores the data displayed in the sidebar for a player, like the color, the health, the name... - */ -public class SidebarPlayerCache -{ - private UUID playerId; - - private String playerName; - private ChatColor healthColor = ChatColor.WHITE; - - private boolean isOnline; - private boolean isAlive; - - private Set<UUID> playersKilled = new CopyOnWriteArraySet<>(); - private Set<UUID> teammatesDisplayed = new CopyOnWriteArraySet<>(); - - - public SidebarPlayerCache(UUID id) - { - playerId = id; - - Player player = Sidebar.getPlayerAsync(id); - - if (player != null) - { - playerName = player.getName(); - isOnline = true; - updateHealth(player.getHealth()); - } - else - { - playerName = null; - isOnline = false; - } - } - - public void updateName(String name) - { - playerName = name; - } - - public void updateHealth(double health) - { - if (health <= 0) - healthColor = ChatColor.GRAY; - else if (health <= 4.1) - healthColor = ChatColor.DARK_RED; - else if (health <= 8.1) - healthColor = ChatColor.RED; - else if (health <= 12.1) - healthColor = ChatColor.YELLOW; - else if (health <= 16.1) - healthColor = ChatColor.GREEN; - else - healthColor = ChatColor.DARK_GREEN; - - isAlive = (health > 0); - } - - public void updateOnlineStatus(boolean isOnline) - { - this.isOnline = isOnline; - } - - public void addKill(UUID id) - { - playersKilled.add(id); - } - - public UUID getPlayerId() - { - return playerId; - } - - public String getPlayerName() - { - if (playerName != null && !playerName.isEmpty()) - return playerName; - - OfflinePlayer player = OfflinePlayersLoader.getOfflinePlayer(playerId); - if (player != null && player.getName() != null && !player.getName().isEmpty()) - { - playerName = player.getName(); - return playerName; - } - - /// Default nick name when a player cannot be recognized. - return I.t("Unknown"); - } - - public ChatColor getHealthColor() - { - return healthColor; - } - - public boolean isOnline() - { - return isOnline; - } - - public boolean isAlive() - { - return isAlive; - } - - public Set<UUID> getTeammatesDisplayed() - { - return teammatesDisplayed; - } - - public Set<UUID> getPlayersKilled() - { - return playersKilled; - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/task/FireworksOnWinnersTask.java b/src/main/java/eu/carrade/amaury/UHCReloaded/task/FireworksOnWinnersTask.java deleted file mode 100644 index 1c4d428..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/task/FireworksOnWinnersTask.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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.task; - -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; - -import java.util.Random; -import java.util.Set; - - -public class FireworksOnWinnersTask extends BukkitRunnable -{ - private final Set<OfflinePlayer> winners; - - private Double areaSize; - private Random rand; - - private long startTime; - - public FireworksOnWinnersTask(final Set<OfflinePlayer> listWinners) - { - this.winners = listWinners; - - this.areaSize = UHConfig.FINISH.FIREWORKS.AREA_SIZE.get(); - this.rand = new Random(); - - this.startTime = System.currentTimeMillis(); - } - - @Override - public void run() - { - // The fireworks are launched in a square centered on the player. - final double halfAreaSize = areaSize / 2; - - for (final OfflinePlayer winner : winners) - { - if (winner.isOnline()) - { - Location fireworkLocation = ((Player) winner).getLocation(); - - fireworkLocation.add(rand.nextDouble() * areaSize - halfAreaSize, // a number between -halfAreaSize and halfAreaSize - 2, // y+2 for a clean vision of the winner. - rand.nextDouble() * areaSize - halfAreaSize); - - UHUtils.generateRandomFirework(fireworkLocation.add(0.2, 0d, 0.2), 5, 15); - UHUtils.generateRandomFirework(fireworkLocation.add(-0.2, 0d, 0.2), 5, 15); - } - } - - if ((System.currentTimeMillis() - startTime) / 1000 > UHConfig.FINISH.FIREWORKS.DURATION.get()) - { - this.cancel(); - } - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamChatManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamChatManager.java deleted file mode 100644 index 922d33f..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamChatManager.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * 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.teams; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.protips.ProTips; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.runners.RunTask; -import fr.zcraft.zlib.tools.text.MessageSender; -import org.bukkit.entity.Player; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - - -public class TeamChatManager -{ - private final UHCReloaded p; - - private final Set<UUID> teamChatLocked = new HashSet<>(); - private final Map<UUID, UHTeam> otherTeamChatLocked = new HashMap<>(); - private final Set<UUID> globalSpies = new HashSet<>(); - - public TeamChatManager(UHCReloaded p) - { - this.p = p; - } - - /** - * Sends a team-message from the given sender. - * - * @param sender The sender. - * @param message The message to send. - */ - public void sendTeamMessage(Player sender, String message) - { - sendTeamMessage(sender, message, null); - } - - /** - * Sends a team-message from the given sender. - * - * @param sender The sender. - * @param message The message to send. - * @param team If not null, this message will be considered as an external message from another player to this team. - */ - public void sendTeamMessage(Player sender, String message, UHTeam team) - { - // Permission check - if (team == null && !sender.hasPermission("uh.teamchat.self")) - { - sender.sendMessage(I.t("{ce}You are not allowed to send a private message to your team.")); - return; - } - if (team != null && !sender.hasPermission("uh.teamchat.others")) - { - sender.sendMessage(I.t("{ce}You are not allowed to enter in the private chat of another team.")); - return; - } - - final String rawMessage; - final UHTeam recipient; - - if (team == null) - { - /// Format of a private team message from a team member. {0} = sender display name, {1} = message. - rawMessage = I.t("{gold}[{0}{gold} -> his team] {reset}{1}", sender.getDisplayName(), message); - recipient = p.getTeamManager().getTeamForPlayer(sender); - - if (recipient == null) - { - /// Error message if someone try to send a team private message out of any team - sender.sendMessage(I.t("{ce}You are not in a team!")); - return; - } - } - else - { - /// Format of a private team message from a non-team-member. {0} = sender display name, {1} = team display name, {2} = message. - rawMessage = I.t("{gold}[{0}{gold} -> team {1}{gold}] {reset}{2}", sender.getDisplayName(), team.getDisplayName(), message); - recipient = team; - } - - sendRawTeamMessage(sender, rawMessage, recipient); - } - - /** - * Sends a raw team-message from the given player. - * - * @param sender The sender of this message. - * @param rawMessage The raw message to be sent. - * @param team The recipient of this message. - */ - private void sendRawTeamMessage(final Player sender, String rawMessage, UHTeam team) - { - // The message is sent to the players of the team... - team.getOnlinePlayers().forEach(player -> MessageSender.sendChatMessage(player, rawMessage)); - - // ... to the spies ... - if (otherTeamChatLocked.containsValue(team)) - { - // The message is only sent to the spies not in the team, to avoid double messages - otherTeamChatLocked.keySet().stream() - .filter(playerId -> otherTeamChatLocked.get(playerId).equals(team)) - .filter(playerId -> !team.containsPlayer(playerId)) - .forEach(playerId -> MessageSender.sendChatMessage(p.getServer().getPlayer(playerId), rawMessage)); - } - - // ... to the global spies ... - globalSpies.stream() - .filter(playerId -> !team.containsPlayer(playerId)) - .forEach(playerId -> p.getServer().getPlayer(playerId).sendMessage(rawMessage)); - - // ... and to the console. - if (UHConfig.TEAMS_OPTIONS.TEAM_CHAT.LOG.get()) - { - p.getServer().getConsoleSender().sendMessage(rawMessage); - } - - RunTask.later(() -> ProTips.LOCK_CHAT.sendTo(sender), 30L); - } - - /** - * Sends a global message from the given player. - * - * @param sender The sender of this message. - * @param message The message to be sent. - */ - public void sendGlobalMessage(Player sender, String message) - { - // This message will be sent synchronously. - // The players' messages are sent asynchronously. - // That's how we differentiates the messages sent through /g and the messages sent using - // the normal chat. - sender.chat(message); - } - - - /** - * Toggles the chat between the global chat and the team chat. - * - * @param player The chat of this player will be toggled. - * @return {@code true} if the chat is now the team chat; false else. - */ - public boolean toggleChatForPlayer(Player player) - { - return toggleChatForPlayer(player, null); - } - - /** - * Toggles the chat between the global chat and the team chat. - * - * @param player The chat of this player will be toggled. - * @param team The team to chat with. If null, the player's team will be used. - * @return {@code true} if the chat is now the team chat; false else. - */ - public boolean toggleChatForPlayer(final Player player, UHTeam team) - { - // Permission check - if (team == null && !player.hasPermission("uh.teamchat.self")) - { - player.sendMessage(I.t("{ce}You are not allowed to send a private message to your team.")); - return false; - } - if (team != null && !player.hasPermission("uh.teamchat.others")) - { - player.sendMessage(I.t("{ce}You are not allowed to enter in the private chat of another team.")); - return false; - } - - - // If the team is not null, we will always go to the team chat - // Else, normal toggle - - if (team != null) - { - // if the player was in another team chat before, we removes it. - teamChatLocked.remove(player.getUniqueId()); - otherTeamChatLocked.put(player.getUniqueId(), team); - - return true; - } - - else - { - if (isAnyTeamChatEnabled(player)) - { - teamChatLocked.remove(player.getUniqueId()); - otherTeamChatLocked.remove(player.getUniqueId()); - - return false; - } - else - { - teamChatLocked.add(player.getUniqueId()); - RunTask.later(() -> ProTips.USE_G_COMMAND.sendTo(player), 10L); - - return true; - } - } - } - - /** - * Returns true if the team chat is enabled for the given player. - * - * @param player The player. - * @param team If non-null, this will check if the given player is spying the current team. - * @return {@code true} if the team chat is enabled for the given player. - */ - public boolean isTeamChatEnabled(Player player, UHTeam team) - { - if (team == null) - { - return teamChatLocked.contains(player.getUniqueId()); - } - else - { - final UHTeam lockedTeam = this.otherTeamChatLocked.get(player.getUniqueId()); - final UHTeam playerTeam = p.getTeamManager().getTeamForPlayer(player); - - return (lockedTeam != null && lockedTeam.equals(team)) || (playerTeam != null && playerTeam.equals(team)); - } - } - - /** - * Returns true if the team chat is enabled for the given player. - * - * @param player The player. - * @return {@code true} if the team chat is enabled for the given player. - */ - public boolean isTeamChatEnabled(Player player) - { - return this.isTeamChatEnabled(player, null); - } - - /** - * Returns true if the given player is in the team chat of another team. - * - * @param player The player. - * @return {@code true} if the given player is in the team chat of another team. - */ - public boolean isOtherTeamChatEnabled(Player player) - { - return otherTeamChatLocked.containsKey(player.getUniqueId()); - } - - /** - * Returns true if a team chat is enabled for the given player. - * - * @param player The player. - * @return {@code true} if a team chat is enabled for the given player. - */ - public boolean isAnyTeamChatEnabled(Player player) - { - return (teamChatLocked.contains(player.getUniqueId()) || otherTeamChatLocked.containsKey(player.getUniqueId())); - } - - /** - * Returns the other team viewed by the given player, or null if the player is not in - * the chat of another team. - * - * @param player The player. - * @return The other team viewed by the given player. - */ - public UHTeam getOtherTeamEnabled(Player player) - { - return otherTeamChatLocked.get(player.getUniqueId()); - } - - - /** - * Registers a player receiving ALL the teams chats. - * - * @param id The spy's UUID. - */ - public void addGlobalSpy(UUID id) - { - globalSpies.add(id); - } - - /** - * Stops a player from receiving ALL the teams chats. - * - * @param id The spy's UUID. - */ - public void removeGlobalSpy(UUID id) - { - globalSpies.remove(id); - } - - /** - * Checks if the given player receives all the teams chats. - * - * @param id The spy's UUID. - * @return {@code true} if spying. - */ - public boolean isGlobalSpy(UUID id) - { - return globalSpies.contains(id); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamColor.java b/src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamColor.java deleted file mode 100644 index e27a178..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamColor.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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.teams; - -import org.bukkit.ChatColor; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - - -/** - * Represents a team color. - * - * Also used to convert a string to a ChatColor object. - */ -public enum TeamColor -{ - AQUA("Aqua", ChatColor.AQUA), - BLACK("Black", ChatColor.BLACK), - BLUE("Blue", ChatColor.BLUE), - DARK_AQUA("Darkaqua", ChatColor.DARK_AQUA), - DARK_BLUE("Darkblue", ChatColor.DARK_BLUE), - DARK_GRAY("Darkgray", ChatColor.DARK_GRAY), - DARK_GREEN("Darkgreen", ChatColor.DARK_GREEN), - DARK_PURPLE("Darkpurple", ChatColor.DARK_PURPLE), - DARK_RED("Darkred", ChatColor.DARK_RED), - GOLD("Gold", ChatColor.GOLD), - GRAY("Gray", ChatColor.GRAY), - GREEN("Green", ChatColor.GREEN), - LIGHT_PURPLE("Lightpurple", ChatColor.LIGHT_PURPLE), - RED("Red", ChatColor.RED), - WHITE("White", ChatColor.WHITE), - YELLOW("Yellow", ChatColor.YELLOW), - - RANDOM("?", null); // Must be the last one. - - - private static Map<ChatColor, TeamColor> BY_CHAT_COLOR = new HashMap<>(); - - static - { - Arrays.stream(values()) - .filter(color -> color.toChatColor() != null) - .forEach(color -> BY_CHAT_COLOR.put(color.toChatColor(), color)); - } - - - private String name; - private ChatColor color; - - TeamColor(String name, ChatColor color) - { - this.name = name; - this.color = color; - } - - public ChatColor toChatColor() - { - return this.color; - } - - /** - * Returns a ChatColor object from a string. - * - * @param name The name of the color. - * @return The ChatColor object (null if RANDOM or not found). - */ - public static ChatColor getChatColorByName(String name) - { - return Arrays.stream(values()) - .filter(color -> color.name.equalsIgnoreCase(name)) - .findFirst() - .map(color -> color.color) - .orElse(null); - } - - /** - * Case&trim-insensitive version of {@link #valueOf(String)}. - * - * @param name The name to get. - * @return A TeamColor value, or null if no value found. - */ - public static TeamColor fromString(String name) - { - if (name.equals("?")) - { - return RANDOM; - } - - try - { - return valueOf(name.trim().toUpperCase()); - } - catch (IllegalArgumentException e) - { - // Maybe a color without underscore - return Arrays.stream(values()) - .filter(color -> color.name.equalsIgnoreCase(name)) - .findFirst().orElse(null); - } - } - - /** - * Returns the TeamColor enum member associated to the given ChatColor. - * - * @param color The ChatColor. - * @return The corresponding TeamColor. - */ - public static TeamColor fromChatColor(ChatColor color) - { - return BY_CHAT_COLOR.get(color); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java deleted file mode 100644 index 2b84fe5..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java +++ /dev/null @@ -1,648 +0,0 @@ -/* - * 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.teams; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.gui.teams.TeamsSelectorGUI; -import eu.carrade.amaury.UHCReloaded.gui.teams.editor.TeamEditDeleteGUI; -import eu.carrade.amaury.UHCReloaded.gui.teams.editor.TeamEditGUI; -import eu.carrade.amaury.UHCReloaded.gui.teams.editor.TeamEditMembersGUI; -import fr.zcraft.zlib.components.configuration.ConfigurationParseException; -import fr.zcraft.zlib.components.configuration.ConfigurationValueHandler; -import fr.zcraft.zlib.components.gui.Gui; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.components.rawtext.RawText; -import fr.zcraft.zlib.tools.PluginLogger; -import fr.zcraft.zlib.tools.text.ActionBar; -import fr.zcraft.zlib.tools.text.RawMessage; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; -import org.bukkit.inventory.meta.BannerMeta; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Random; -import java.util.Set; - - -public class TeamManager -{ - private final int MAX_PLAYERS_PER_TEAM; - - private final UHCReloaded p; - private final HashSet<UHTeam> teams = new HashSet<>(); - - - public TeamManager() - { - p = UHCReloaded.get(); - - MAX_PLAYERS_PER_TEAM = UHConfig.TEAMS_OPTIONS.MAX_PLAYERS_PER_TEAM.get(); - } - - /** - * Is the given team registered? - * - * @param team The team. - * @return {@code true} if the team is registered. - */ - public boolean isTeamRegistered(UHTeam team) - { - return teams.contains(team); - } - - /** - * Is the given team registered? - * - * @param name The name of the team. - * @return {@code true} if the team is registered. - */ - public boolean isTeamRegistered(String name) - { - return getTeam(name) != null; - } - - - /** - * Adds a team. - * - * @param color The color. - * @param name The name of the team. - * - * @return The new team. - * - * @throws IllegalArgumentException if a team with the same name already exists. - */ - public UHTeam addTeam(TeamColor color, String name) - { - if (isTeamRegistered(name)) - { - throw new IllegalArgumentException("There is already a team named " + name + " registered!"); - } - - final UHTeam team = new UHTeam(name, generateColor(color)); - teams.add(team); - - updateGUIs(); - - return team; - } - - /** - * Adds a team. A name is generated based on the color. - * - * @param color The color. - * - * @return The new team. - * - * @throws IllegalArgumentException if a team with the same name already exists. - */ - public UHTeam addTeam(TeamColor color) - { - color = generateColor(color); - String teamName = color.toString().toLowerCase(); - - if (isTeamRegistered(teamName)) // Taken! - { - Random rand = new Random(); - do - { - teamName = color.toString().toLowerCase() + rand.nextInt(1000); - } while (isTeamRegistered(teamName)); - } - - final UHTeam team = new UHTeam(teamName, color); - teams.add(team); - - updateGUIs(); - - return team; - } - - /** - * Adds a team from an UHTeam object. - * - * @param team The team. - * @return The new team. - * - * @throws IllegalArgumentException if a team with the same name already exists. - */ - public UHTeam addTeam(final UHTeam team) - { - if (isTeamRegistered(team)) - { - throw new IllegalArgumentException("There is already a team named " + team.getName() + " registered!"); - } - - teams.add(team); - - updateGUIs(); - - return team; - } - - /** - * Deletes a team. - * - * @param team The team to delete. - * @param dontNotify If true, the player will not be notified about the leave. - * @return boolean True if a team was removed. - */ - public boolean removeTeam(UHTeam team, boolean dontNotify) - { - if (team != null) - { - if (dontNotify) - { - team.getPlayers().forEach(player -> this.removePlayerFromTeam(player, true)); - } - - team.deleteTeam(); - } - - final boolean removed = teams.remove(team); - - updateGUIs(); - - return removed; - } - - /** - * Deletes a team. - * - * @param team The team to delete. - * @return boolean True if a team was removed. - */ - public boolean removeTeam(UHTeam team) - { - return removeTeam(team, false); - } - - /** - * Deletes a team. - * - * @param name The name of the team to delete. - * @return boolean True if a team was removed. - */ - public boolean removeTeam(String name) - { - return removeTeam(getTeam(name), false); - } - - /** - * Deletes a team. - * - * @param name The name of the team to delete. - * @param dontNotify If true, the player will not be notified about the leave. - * @return boolean True if a team was removed. - */ - public boolean removeTeam(String name, boolean dontNotify) - { - return removeTeam(getTeam(name), dontNotify); - } - - /** - * Adds a player to a team. - * - * @param teamName The team in which we adds the player. - * @param player The player to add. - * @throws IllegalArgumentException if the team does not exists. - */ - public void addPlayerToTeam(String teamName, OfflinePlayer player) - { - UHTeam team = getTeam(teamName); - - if (team == null) - { - throw new IllegalArgumentException("There isn't any team named" + teamName + " registered!"); - } - - team.addPlayer(player); - } - - /** - * Removes a player from his team. - * - * @param player The player to remove. - * @param dontNotify If true, the player will not be notified about the leave. - */ - public void removePlayerFromTeam(OfflinePlayer player, boolean dontNotify) - { - UHTeam team = getTeamForPlayer(player); - if (team != null) - { - team.removePlayer(player, dontNotify); - } - } - - /** - * Removes a player from his team. - * - * @param player The player to remove. - */ - public void removePlayerFromTeam(OfflinePlayer player) - { - removePlayerFromTeam(player, false); - } - - - /** - * Removes all teams. - * - * @param dontNotify If true, the player will not be notified when they leave the destroyed team. - */ - public void reset(boolean dontNotify) - { - // 1: scoreboard reset - new HashSet<>(teams).forEach(team -> this.removeTeam(team, dontNotify)); - - // 2: internal list reset - teams.clear(); - - updateGUIs(); - } - - /** - * Removes all teams. - */ - public void reset() - { - reset(false); - } - - /** - * Sets the correct display name of a player, according to his team. - * - * @param offlinePlayer The player to colorize. - */ - public void colorizePlayer(OfflinePlayer offlinePlayer) - { - if (!UHConfig.COLORIZE_CHAT.get()) - { - return; - } - - if (!offlinePlayer.isOnline()) - { - return; - } - - Player player = (Player) offlinePlayer; - - UHTeam team = getTeamForPlayer(player); - - if (team == null) - { - player.setDisplayName(player.getName()); - } - else - { - player.setDisplayName(team.getColorOrWhite().toChatColor() + player.getName() + ChatColor.RESET); - } - } - - /** - * Returns all the teams. - * - * @return The teams. - */ - public Set<UHTeam> getTeams() - { - return teams; - } - - /** - * Returns the maximal number of players in each team. - * - * @return The max. - */ - public int getMaxPlayersPerTeam() - { - return MAX_PLAYERS_PER_TEAM; - } - - /** - * Returns the UHTeam object of the team with the given name. - * - * @param name The name of the team. - * @return The team, or null if the team does not exists. - */ - public UHTeam getTeam(String name) - { - return teams.stream().filter(t -> t.getName().equalsIgnoreCase(name)).findFirst().orElse(null); - } - - /** - * Gets a player's team. - * - * @param player The player. - * @return The team of this player. - */ - public UHTeam getTeamForPlayer(OfflinePlayer player) - { - return teams.stream().filter(t -> t.containsPlayer(player.getUniqueId())).findFirst().orElse(null); - } - - /** - * Checks if two players are in the same team. - * - * @param player1 The first player. - * @param player2 The second player - * @return True if the players are in the same team, false else. - */ - public boolean inSameTeam(Player player1, Player player2) - { - return (getTeamForPlayer(player1).equals(getTeamForPlayer(player2))); - } - - /** - * Generates a color from the given color. - * <p> - * If the color is neither {@link TeamColor#RANDOM} nor {@code null}, returns the given color.<br /> - * Else, generates a random unused (if possible) color. - * - * @param color The color to be generated. - * @return A non-random color. - */ - public TeamColor generateColor(TeamColor color) - { - if (color != null && color != TeamColor.RANDOM) - { - return color; - } - - // A list of the currently used colors. - final HashSet<TeamColor> availableColors = new HashSet<TeamColor>(Arrays.asList(TeamColor.values())); - availableColors.remove(TeamColor.RANDOM); - - getTeams().stream().map(UHTeam::getColorOrWhite).forEach(availableColors::remove); - - if (availableColors.size() != 0) - { - return (TeamColor) availableColors.toArray()[(new Random()).nextInt(availableColors.size())]; - } - else - { - // length-1 so the RANDOM option is never selected. - return TeamColor.values()[(new Random()).nextInt(TeamColor.values().length - 1)]; - } - } - - /** - * Imports the teams from the configuration. - * - * @return The number of teams imported. - */ - public int importTeamsFromConfig() - { - int teamsCount = 0; - for (String teamDescription : UHConfig.TEAMS) - { - try - { //TODO: Sanitize UHTeam to allow it being loaded directly by the configuration. - addTeam(handleTeamValue(teamDescription)); - } - catch (ConfigurationParseException ex) - { - PluginLogger.warning("Invalid team value : ''{0}''.", ex.getValue()); - PluginLogger.warning("\tReason : {0}", ex.getMessage()); - } - } - - for(Entry<String, BannerMeta> bannerEntry : UHConfig.TEAM_BANNERS) - { - UHTeam team = getTeam(bannerEntry.getKey()); - if(team == null) continue; - team.setBanner(bannerEntry.getValue()); - } - - return teamsCount; - } - - /** - * Displays a chat-based GUI (using tellraw formatting) to player to select a team. - * <p> - * Nothing is displayed if the player cannot use the /join command. - * - * @param player The receiver of the chat-GUI. - */ - public void displayTeamChooserChatGUI(Player player) - { - if (!player.hasPermission("uh.player.join.self")) return; - - if (p.getGameManager().isGameRunning()) - { - if (!p.getGameManager().isGameWithTeams()) - { - return; - } - } - - player.sendMessage(ChatColor.GRAY + "⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅"); - - if (p.getTeamManager().getTeams().size() != 0) - { - /// Invite displayed in the chat team selector - player.sendMessage(I.t("{gold}Click on the names below to join a team")); - - boolean displayPlayers = UHConfig.TEAMS_OPTIONS.GUI.DISPLAY_PLAYERS_IN_TEAMS.get(); - - for (UHTeam team : p.getTeamManager().getTeams()) - { - StringBuilder players = new StringBuilder(); - if (displayPlayers) - { - String bullet = "\n - "; - for (OfflinePlayer opl : team.getPlayers()) - { - if (!p.getGameManager().isGameRunning()) - { - players.append(bullet).append(opl.getName()); - } - else - { - if (p.getGameManager().isPlayerDead(opl.getUniqueId())) - { - /// Displayed in team tooltip of the chat team selector for a dead player - players.append(bullet).append(I.t("{0} ({red}dead{reset})", opl.getName())); - } - else - { - /// Displayed in team tooltip of the chat team selector for an alive player - players.append(bullet).append(I.t("{0} ({green}alive{reset})", opl.getName())); - } - } - } - } - - RawMessage.send(player, new RawText("") - .then( - MAX_PLAYERS_PER_TEAM != 0 - /// Team count with max players (ex. [3/5]) followed in-game by the team name. {0} = current count, {1} = max. - ? I.t("{gray}[{white}{0}{gray}/{white}{1}{gray}]", String.valueOf(team.getSize()), String.valueOf(MAX_PLAYERS_PER_TEAM)) - /// Team count without max players (ex. [3]) followed in-game by the team name. {0} = current count. - : I.t("{gray}[{white}{0}{gray}]", String.valueOf(team.getSize())) - ) - .hover(new RawText(I.tn("{0} player in this team", "{0} players in this team", team.getPlayers().size(), team.getPlayers().size()) + players)) - - .then(" ") - - .then(team.getName()) - .color(team.getColorOrWhite().toChatColor()) - .command("/join " + team.getName()) - .style(team.containsPlayer(player) ? ChatColor.BOLD : null) - .hover(new RawText( - team.containsPlayer(player) - /// Tooltip on the chat team selector GUI when the player is in the team. {0} = team display name. - ? I.t("You are in the team {0}", team.getDisplayName()) - /// Tooltip on the chat team selector GUI when the player is not in the team. {0} = team display name. - : I.t("Click here to join the team {0}", team.getDisplayName()) - )) - - .build() - ); - } - - if (p.getTeamManager().getTeamForPlayer(player) != null && player.hasPermission("uh.player.leave.self")) - { - RawMessage.send(player, - new RawText(I.t("{darkred}[×] {red}Click here to leave your team")).command("/leave") - ); - } - else - { - player.sendMessage(I.t("{gray}Run /join to display this again")); - } - } - else - { - // No teams. - player.sendMessage(I.t("{ce}There isn't any team available.")); - } - - player.sendMessage(ChatColor.GRAY + "⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅"); - } - - - /** - * Displays the team of the given player in his action bar. - * If the player is not in a team, or the game is started, does nothing. - * - * @param player The player. - */ - public void displayTeamInActionBar(Player player) - { - UHTeam team = getTeamForPlayer(player); - if (team == null) return; - - displayTeamInActionBar(player, team); - } - - /** - * Displays the team of the given player in his action bar. - * If the player is not in a team, or the game is started, does nothing. - * - * Internal use when an instance of the team is accessible (avoids lookup). - * - * @param player The player. - * @param team The team. - */ - void displayTeamInActionBar(Player player, UHTeam team) - { - if (!UHCReloaded.get().getGameManager().isGameStarted()) - ActionBar.sendPermanentMessage(player, I.t("{gold}Your team: {0}", team.getDisplayName())); - } - - /** - * Updates the teams GUIs. Called when a team is created, deleted, or updated, - * so the GUIs update in real time. - */ - void updateGUIs() - { - Gui.update(TeamsSelectorGUI.class); - Gui.update(TeamEditGUI.class); - Gui.update(TeamEditMembersGUI.class); - Gui.update(TeamEditDeleteGUI.class); - } - - - @ConfigurationValueHandler - static public TeamColor handleTeamColorValue(String value) throws ConfigurationParseException - { - TeamColor color = TeamColor.fromString(value); - if (color == null) - throw new ConfigurationParseException("Invalid team color name.", value); - - return color; - } - - @ConfigurationValueHandler - static public UHTeam handleTeamValue(String str) throws ConfigurationParseException - { - return handleTeamValue(Arrays.asList(str.split(","))); - } - - @ConfigurationValueHandler - static public UHTeam handleTeamValue(List list) throws ConfigurationParseException - { - if (list.size() < 1) - throw new ConfigurationParseException("Not enough values, at least 1 required.", list); - if (list.size() > 2) - throw new ConfigurationParseException("Too many values, at most 2 (color, name) can be used.", list); - - if (list.size() == 1) - { - return new UHTeam(list.get(0).toString().trim(), handleTeamColorValue(list.get(0).toString())); - } - else - { - return new UHTeam(list.get(1).toString().trim(), handleTeamColorValue(list.get(0).toString())); - } - } - - @ConfigurationValueHandler - static public UHTeam handleTeamValue(Map map) throws ConfigurationParseException - { - TeamColor color = map.containsKey("color") ? handleTeamColorValue(map.get("color").toString()) : TeamColor.RANDOM; - Object name = map.containsKey("name") ? map.get("name") : map.get("color"); - - if (name == null) - throw new ConfigurationParseException("Either color or name must be specified", map); - - return new UHTeam(name.toString(), color); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/teams/UHTeam.java b/src/main/java/eu/carrade/amaury/UHCReloaded/teams/UHTeam.java deleted file mode 100644 index ccb0edd..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/teams/UHTeam.java +++ /dev/null @@ -1,624 +0,0 @@ -/* - * 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.teams; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.utils.ColorsUtils; -import eu.carrade.amaury.UHCReloaded.utils.TextUtils; -import fr.zcraft.zlib.components.i18n.I; -import fr.zcraft.zlib.tools.items.ItemStackBuilder; -import fr.zcraft.zlib.tools.items.TextualBanners; -import fr.zcraft.zlib.tools.text.ActionBar; -import org.apache.commons.lang.Validate; -import org.bukkit.ChatColor; -import org.bukkit.DyeColor; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.BannerMeta; -import org.bukkit.scoreboard.Scoreboard; -import org.bukkit.scoreboard.Team; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Objects; -import java.util.Random; -import java.util.Set; -import java.util.UUID; - - -public class UHTeam -{ - private static final boolean BANNER_SHAPE_WRITE_LETTER = UHConfig.TEAMS_OPTIONS.BANNER.SHAPE.WRITE_LETTER.get(); - private static final boolean BANNER_SHAPE_ADD_BORDER = UHConfig.TEAMS_OPTIONS.BANNER.SHAPE.ADD_BORDER.get(); - - private static final Random random = new Random(); - - private UHCReloaded plugin = UHCReloaded.get(); - - private String name = null; - private String internalName; - private String displayName = null; - private TeamColor color = null; - private ItemStack defaultBanner = null; - private ItemStack banner = null; - - private HashSet<UUID> players = new HashSet<>(); - - - public UHTeam(String name, TeamColor color) - { - Validate.notNull(name, "The name cannot be null."); - - // We use a random internal name because the name of a team, in Minecraft vanilla, is limited - // (16 characters max). - this.internalName = String.valueOf(random.nextInt(99999999)) + String.valueOf(random.nextInt(99999999)); - - final Scoreboard sb = this.plugin.getScoreboardManager().getScoreboard(); - final Team t = sb.registerNewTeam(this.internalName); - - t.setSuffix(ChatColor.RESET.toString()); - t.setCanSeeFriendlyInvisibles(UHConfig.TEAMS_OPTIONS.CAN_SEE_FRIENDLY_INVISIBLES.get()); - t.setAllowFriendlyFire(UHConfig.TEAMS_OPTIONS.ALLOW_FRIENDLY_FIRE.get()); - - setName(name, true); - setColor(color); - updateDefaultBanner(); - } - - /** - * @deprecated Use {@link #UHTeam(String, TeamColor)} instead. - */ - @Deprecated - public UHTeam(String name, TeamColor color, UHCReloaded plugin) - { - this(name, color); - } - - /** - * Returns the name of the team. - * - * Can include spaces. - * - * @return The name. - */ - public String getName() - { - return name; - } - - public void setName(String name) - { - setName(name, false); - } - - /** - * Changes the name of this team. - * - * @param name The new name. - * @param silent if {@code true}, the players will not be notified. - */ - public void setName(String name, boolean silent) - { - if (name == null || (this.name != null && this.name.equals(name))) - return; - - this.name = name; - - updateDisplayName(); - updateDefaultBanner(); - - plugin.getTeamManager().updateGUIs(); - - for (Player player : getOnlinePlayers()) - { - if (!silent) - player.sendMessage(I.t("{cs}Your team is now called {0}{cs}.", displayName)); - - if (UHConfig.BEFORE_START.TEAM_IN_ACTION_BAR.get()) - plugin.getTeamManager().displayTeamInActionBar(player, this); - } - } - - /** - * Returns the display name of the team. - * - * This name is: - * - if the team is uncolored, the name of the team; - * - else, the name of the team with: - * - before, the color of the team; - * - after, the "reset" formatting mark (§r). - * - * @return The display name. - */ - public String getDisplayName() - { - return displayName; - } - - private void updateDisplayName() - { - displayName = (color != null) ? color.toChatColor() + name + ChatColor.RESET : name; - - final Team t = plugin.getScoreboardManager().getScoreboard().getTeam(internalName); - if (t != null) - t.setDisplayName(displayName.substring(0, Math.min(displayName.length(), 32))); - } - - /** - * Returns the players inside this team. - * - * @return The players. - */ - public Set<OfflinePlayer> getPlayers() - { - final Set<OfflinePlayer> playersList = new HashSet<>(); - - for (UUID id : players) - { - final Player player = plugin.getServer().getPlayer(id); - if (player != null) - { - playersList.add(player); - } - else - { - playersList.add(plugin.getServer().getOfflinePlayer(id)); - } - } - - return playersList; - } - - /** - * Returns the online players inside this team. - * - * @return The online players. - */ - public Set<Player> getOnlinePlayers() - { - HashSet<Player> playersList = new HashSet<>(); - - for (UUID id : players) - { - Player player = plugin.getServer().getPlayer(id); - if (player != null && player.isOnline()) - { - playersList.add(player); - } - } - - return playersList; - } - - /** - * Returns the UUIDs of the players inside this team. - * - * @return The UUIDs of the players. - */ - @SuppressWarnings ("unchecked") - public Set<UUID> getPlayersUUID() - { - return Collections.unmodifiableSet(players); - } - - /** - * Returns the UUIDs of the online players inside this team. - * - * @return The UUID of the online players. - */ - public Set<UUID> getOnlinePlayersUUID() - { - HashSet<UUID> playersList = new HashSet<>(); - - for (UUID id : players) - { - Player player = plugin.getServer().getPlayer(id); - if (player != null && player.isOnline()) - { - playersList.add(id); - } - } - - return playersList; - } - - /** - * Returns the size of this team. - * - * @return The size. - */ - public int getSize() - { - return players.size(); - } - - /** - * Returns true if the team is empty. - * - * @return The emptiness. - */ - public boolean isEmpty() - { - return getSize() == 0; - } - - /** - * Returns true if the team is full. - * - * @return The fullness. - */ - public boolean isFull() - { - return plugin.getTeamManager().getMaxPlayersPerTeam() != 0 && getSize() >= plugin.getTeamManager().getMaxPlayersPerTeam(); - } - - /** - * Adds a player inside this team. - * - * @param player The player to add. - */ - public void addPlayer(OfflinePlayer player) - { - addPlayer(player, false); - } - - /** - * Adds a player inside this team. - * - * @param player The player to add. - * @param silent If true, the player will not be notified about this. - */ - public void addPlayer(OfflinePlayer player, boolean silent) - { - Validate.notNull(player, "The player cannot be null."); - - if (plugin.getTeamManager().getMaxPlayersPerTeam() != 0 - && this.players.size() >= plugin.getTeamManager().getMaxPlayersPerTeam()) - { - throw new RuntimeException("The team " + getName() + " is full"); - } - - plugin.getTeamManager().removePlayerFromTeam(player, true); - - players.add(player.getUniqueId()); - plugin.getScoreboardManager().getScoreboard().getTeam(this.internalName).addPlayer(player); - - plugin.getTeamManager().colorizePlayer(player); - - plugin.getTeamManager().updateGUIs(); - - if (player.isOnline()) - { - if (!silent) - ((Player) player).sendMessage(I.t("{aqua}You are now in the {0}{aqua} team.", getDisplayName())); - - if (UHConfig.BEFORE_START.TEAM_IN_ACTION_BAR.get()) - plugin.getTeamManager().displayTeamInActionBar((Player) player, this); - } - } - - /** - * Removes a player from this team. - * - * Nothing is done if the player wasn't in this team. - * - * @param player The player to remove. - */ - public void removePlayer(OfflinePlayer player) - { - removePlayer(player, false); - } - - /** - * Removes a player from this team. - * - * Nothing is done if the player wasn't in this team. - * - * @param player The player to remove. - * @param silent If true, the player will not be notified. - */ - public void removePlayer(OfflinePlayer player, boolean silent) - { - Validate.notNull(player, "The player cannot be null."); - - players.remove(player.getUniqueId()); - unregisterPlayer(player, silent); - - plugin.getTeamManager().updateGUIs(); - } - - /** - * Unregisters a player from the scoreboard and uncolorizes the pseudo. - * - * Internal use, avoids a ConcurrentModificationException in this.deleteTeam() - * (this.players is listed and emptied simultaneously, else). - */ - private void unregisterPlayer(OfflinePlayer player, boolean silent) - { - if (player == null) return; - - plugin.getScoreboardManager().getScoreboard().getTeam(this.internalName).removePlayer(player); - plugin.getTeamManager().colorizePlayer(player); - - if (player.isOnline()) - { - if (!silent) - ((Player) player).sendMessage(I.t("{darkaqua}You are no longer part of the {0}{darkaqua} team.", getDisplayName())); - - if (UHConfig.BEFORE_START.TEAM_IN_ACTION_BAR.get()) - ActionBar.removeMessage((Player) player, true); - } - } - - /** - * Deletes this team. - * - * The players inside the team are left without any team. - */ - public void deleteTeam() - { - // We removes the players from the team (scoreboard team too) - players.forEach(id -> unregisterPlayer(plugin.getServer().getOfflinePlayer(id), false)); - - players.clear(); - - // Then the scoreboard team is deleted. - plugin.getScoreboardManager().getScoreboard().getTeam(this.internalName).unregister(); - } - - /** - * Returns true if the given player is in this team. - * - * @param player The player to check. - * @return true if the given player is in this team. - */ - public boolean containsPlayer(Player player) - { - Validate.notNull(player, "The player cannot be null."); - - return players.contains(player.getUniqueId()); - } - - /** - * Returns true if the player with the given UUID is in this team. - * - * @param id The UUID of the player to check. - * @return true if the given player is in this team. - */ - public boolean containsPlayer(UUID id) - { - Validate.notNull(id, "The player cannot be null."); - - return players.contains(id); - } - - /** - * Teleports the entire team to the given location. - * - * @param location The location. - */ - public void teleportTo(Location location) - { - Validate.notNull(location, "The location cannot be null."); - - players.stream() - .map(id -> plugin.getServer().getPlayer(id)) - .filter(Objects::nonNull) - .filter(Player::isOnline) - .forEach(player -> player.teleport(location, TeleportCause.PLUGIN)); - } - - /** - * @return the color of the team. - */ - public TeamColor getColor() - { - return color; - } - - /** - * @return the color of the team, or white if the color is set to null. Never returns {@code null}. - */ - public TeamColor getColorOrWhite() - { - return color != null ? color : TeamColor.WHITE; - } - - /** - * Updates the team color. - * - * @param color The new color. - */ - public void setColor(TeamColor color) - { - // We don't use generateColor directly because we want to keep the "null" color. - if (color == TeamColor.RANDOM) this.color = plugin.getTeamManager().generateColor(color); - else this.color = color; - - updateDisplayName(); - - // The team color needs to be updated - if (this.color != null) - { - Team t = plugin.getScoreboardManager().getScoreboard().getTeam(internalName); - if (t != null) - t.setPrefix(this.color.toChatColor().toString()); - } - - // The players names too - for (Player player : getOnlinePlayers()) - { - plugin.getTeamManager().colorizePlayer(player); - - // Also we update the action bar if needed - if (UHConfig.BEFORE_START.TEAM_IN_ACTION_BAR.get()) - plugin.getTeamManager().displayTeamInActionBar(player, this); - } - - // The default banner too - updateDefaultBanner(); - - plugin.getTeamManager().updateGUIs(); - } - - - /** - * Generates and return the default banner for this team, following the - * banners options in the configuration file. - * - * @return the generated banner. - */ - public ItemStack getDefaultBanner() - { - final ItemStack banner; - final DyeColor dye = ColorsUtils.chat2Dye(getColorOrWhite().toChatColor()); - - if (BANNER_SHAPE_WRITE_LETTER) - { - banner = TextualBanners.getCharBanner(Character.toUpperCase(TextUtils.getInitialLetter(name)), dye, BANNER_SHAPE_ADD_BORDER); - } - else - { - banner = new ItemStack(Material.BANNER); - BannerMeta meta = (BannerMeta) banner.getItemMeta(); - meta.setBaseColor(dye); - banner.setItemMeta(meta); - } - - return banner; - } - - /** - * Regenerates the default banner. - */ - private void updateDefaultBanner() - { - // Avoid updating in the constructor before all the object is populated. - if (name != null) - defaultBanner = getDefaultBanner(); - else - defaultBanner = new ItemStack(Material.BANNER); - } - - /** - * Updates this team's banner. - * - * @param banner The new banner. {@code null} to use the default banner. - */ - public void setBanner(ItemStack banner) - { - if (banner == null) - { - this.banner = null; - return; - } - - if (banner.getType() != Material.BANNER) - throw new IllegalArgumentException("A banner is required"); - - this.banner = new ItemStackBuilder(banner.clone()) - .title(displayName) - .amount(1) - .hideAttributes() - .item(); - - if (banner.hasItemMeta()) - { - BannerMeta meta = (BannerMeta) this.banner.getItemMeta(); - meta.setBaseColor(((BannerMeta) banner.getItemMeta()).getBaseColor()); - this.banner.setItemMeta(meta); - } - - plugin.getTeamManager().updateGUIs(); - } - - /** - * Updates this team's banner. - * - * @param banner The new banner. {@code null} to use the default banner. - */ - public void setBanner(BannerMeta banner) - { - if (banner == null) - { - this.banner = null; - return; - } - - this.banner = new ItemStackBuilder(Material.BANNER) - .title(displayName) - .amount(1) - .hideAttributes() - .item(); - - this.banner.setItemMeta(banner.clone()); - - plugin.getTeamManager().updateGUIs(); - } - - /** - * Returns this team's banner. - * - * @return the banner. - */ - public ItemStack getBanner() - { - return banner == null ? defaultBanner : banner; - } - - - @Override - public int hashCode() - { - return ((name == null) ? 0 : name.hashCode()); - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof UHTeam)) - return false; - - final UHTeam other = (UHTeam) obj; - return name == null ? other.name == null : name.equals(other.name); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/timers/TimerManager.java b/src/main/java/eu/carrade/amaury/UHCReloaded/timers/TimerManager.java deleted file mode 100644 index 878052a..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/timers/TimerManager.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * 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.timers; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArraySet; - - -public class TimerManager -{ - private Map<String, UHTimer> timers = new ConcurrentHashMap<>(); - private UHTimer mainTimer = null; - - /** - * Cached list of the running timers - */ - private Map<String, UHTimer> runningTimers = new ConcurrentHashMap<>(); - - /** - * List of the timers to resume if running timers are paused. - * - * @see {@link #pauseAllRunning(boolean)}. - */ - private Set<UHTimer> timersToResume = new CopyOnWriteArraySet<>(); - - - /** - * Registers the main timer, used to display the episodes countdown. - * - * @param timer The timer. - */ - public void registerMainTimer(UHTimer timer) - { - this.mainTimer = timer; - timer.setRegistered(true); - } - - /** - * Returns the main timer, used to display the episodes countdown. - * - * @return The main timer. - */ - public UHTimer getMainTimer() - { - return this.mainTimer; - } - - /** - * Registers a timer. - * - * @param timer The timer to register. - * @throws IllegalArgumentException if a timer with the same name is already registered. - */ - public void registerTimer(UHTimer timer) - { - if (timers.get(timer.getName()) != null) - { - throw new IllegalArgumentException("A timer with the name " + timer.getName() + " is already registered."); - } - - timers.put(timer.getName(), timer); - - timer.setRegistered(true); - } - - /** - * Unregisters a timer. - * <p> - * If the timer was not registered, nothing is done. - * - * @param timer The timer to unregister. - */ - public void unregisterTimer(UHTimer timer) - { - timers.remove(timer.getName()); - runningTimers.remove(timer.getName()); - - timer.setRegistered(false); - } - - /** - * Updates the internal list of started timers. - */ - public void updateStartedTimersList() - { - runningTimers = new HashMap<>(); - - if (getMainTimer() != null && getMainTimer().isRunning()) - { - runningTimers.put(getMainTimer().getName(), getMainTimer()); - } - - timers.values().stream() - .filter(UHTimer::isRunning) - .forEach(timer -> runningTimers.put(timer.getName(), timer)); - } - - /** - * Returns a timer by his name. - * - * @param name The name of the timer. - * - * @return The timer, or null if there isn't any timer with this name. - */ - public UHTimer getTimer(String name) - { - return timers.get(name); - } - - /** - * Returns a collection containing the registered timers. - * - * @return The collection. - */ - public Collection<UHTimer> getTimers() - { - return timers.values(); - } - - /** - * Returns a collection containing the running timers. - * - * @return The collection. - */ - public Collection<UHTimer> getRunningTimers() - { - return runningTimers.values(); - } - - /** - * Pauses (or resumes) all the running timers. - * - * @param paused If true, all the timers will be paused. Else, resumed. - */ - public void pauseAll(boolean paused) - { - getRunningTimers().forEach(timer -> timer.setPaused(paused)); - - if (!paused) - { - // If we restart all the timers regardless to their previous state, - // this data is meaningless. - timersToResume.clear(); - } - } - - /** - * Pauses (or resumes) all the running timers. - * <p> - * This method will only resume the previously-running timers. - * - * @param paused If true, all the timers will be paused. Else, resumed. - */ - public void pauseAllRunning(boolean paused) - { - if (paused) - { - getRunningTimers().stream().filter(timer -> !timer.isPaused()).forEach(timer -> { - timer.setPaused(true); - timersToResume.add(timer); - }); - } - else - { - timersToResume.forEach(timer -> timer.setPaused(false)); - timersToResume.clear(); - } - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/timers/UHTimer.java b/src/main/java/eu/carrade/amaury/UHCReloaded/timers/UHTimer.java deleted file mode 100644 index 3e30e06..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/timers/UHTimer.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * 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.timers; - -import eu.carrade.amaury.UHCReloaded.events.TimerEndsEvent; -import eu.carrade.amaury.UHCReloaded.events.TimerStartsEvent; -import fr.zcraft.zlib.components.i18n.I; -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; - -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.UUID; - - -/** - * Represents a timer. - * - * @author Amaury Carrade - */ -public class UHTimer -{ - private static final NumberFormat formatter = new DecimalFormat("00"); - - private UUID id; - private String name; - private Boolean registered = false; - private Boolean running = false; - private Boolean displayed = false; - - private Long startTime = 0L; - private Integer duration = 0; // seconds - - // Cached values - private Integer hoursLeft = 0; - private Integer minutesLeft = 0; - private Integer secondsLeft = 0; - - // Old values, used by the scoreboard to reset the scores. - private Integer oldHoursLeft = -1; - private Integer oldMinutesLeft = -1; - private Integer oldSecondsLeft = -1; - - // Pause - private Boolean paused = false; - private Long pauseTime = 0L; - - // Display this timer following the format "hh:mm:ss"? - private Boolean displayHoursInTimer = false; - - - public UHTimer(String name) - { - Validate.notNull(name, "The name cannot be null"); - - this.id = UUID.randomUUID(); // only used as a hashCode. - this.name = name; - } - - /** - * Sets the duration of the timer, in seconds. - * - * @param seconds The duration. - */ - public void setDuration(int seconds) - { - this.duration = seconds; - - this.hoursLeft = (int) Math.floor(this.duration / 3600); - this.minutesLeft = (int) (Math.floor(this.duration / 60) - (this.hoursLeft * 60)); - this.secondsLeft = this.duration - (this.minutesLeft * 60 + this.hoursLeft * 3600); - - this.displayHoursInTimer = (this.hoursLeft != 0); - } - - /** - * Starts this timer. - * - * If this is called while the timer is running, the timer is restarted. - */ - public void start() - { - this.running = true; - this.startTime = System.currentTimeMillis(); - - Bukkit.getServer().getPluginManager().callEvent(new TimerStartsEvent(this)); - } - - /** - * Stops this timer. - */ - public void stop() - { - stop(false); - } - - /** - * Stops this timer. - * - * @param wasUp If true, the timer was stopped because the timer was up. - */ - private void stop(boolean wasUp) - { - final TimerEndsEvent event = new TimerEndsEvent(this, wasUp); - Bukkit.getServer().getPluginManager().callEvent(event); - - if (isRegistered()) - { - if (event.getRestart()) - { - start(); - } - else - { - this.running = false; - this.startTime = 0L; - - this.hoursLeft = 0; - this.minutesLeft = 0; - this.secondsLeft = 0; - - this.oldHoursLeft = 0; - this.oldMinutesLeft = 0; - this.oldSecondsLeft = 0; - } - } - } - - /** - * Updates the timer. - */ - public void update() - { - if (running && !paused) - { - oldHoursLeft = hoursLeft; - oldMinutesLeft = minutesLeft; - oldSecondsLeft = secondsLeft; - - long timeSinceStart = System.currentTimeMillis() - this.startTime; // ms - - if (timeSinceStart >= getDuration() * 1000) - { - stop(true); - } - else - { - int countSecondsLeft = (int) (getDuration() - Math.floor(timeSinceStart / 1000)); - - secondsLeft = countSecondsLeft % 60; - minutesLeft = (countSecondsLeft % 3600) / 60; - hoursLeft = (int) Math.floor(countSecondsLeft / 3600); - } - } - } - - /** - * Pauses (or restarts after a pause) the timer. - * <p> - * If the timer is not running, nothing is done. - * - * @param pause If true the timer will be paused. - */ - public void setPaused(boolean pause) - { - if (this.running) - { - // The pause is only set once (as example if the user executes /uh freeze all twice). - if (pause && !this.paused) - { - this.paused = true; - this.pauseTime = System.currentTimeMillis(); - } - - if (!pause && this.paused) - { - // We have to add to the time of the start of the episode the elapsed time - // during the pause. - this.startTime += (System.currentTimeMillis() - this.pauseTime); - this.pauseTime = 0l; - - this.paused = false; - } - } - } - - /** - * Checks if the timer is registered in the TimerManager. - * - * @return true if the timer is registered. - */ - public Boolean isRegistered() - { - return registered; - } - - /** - * Marks a timer as registered, or not. - * - * @param registered true if the timer is now registered. - */ - protected void setRegistered(Boolean registered) - { - this.registered = registered; - } - - /** - * Returns the name of the timer. - * - * @return The name. - */ - public String getName() - { - return name; - } - - /** - * Returns the display name of the timer. - * <p> - * The display name is the name with all &-based color codes replaced by §-based ones. - * - * @return The name. - */ - public String getDisplayName() - { - return ChatColor.translateAlternateColorCodes('&', name); - } - - - /** - * Checks if the timer is currently running. - * - * @return true if the timer is running. - */ - public Boolean isRunning() - { - return running; - } - - /** - * Checks if the timer is currently displayed in the scoreboard. - * - * @return {@code true} if displayed. - */ - public Boolean isDisplayed() - { - return displayed; - } - - /** - * Display or hide this timer in/from the scoreboard. - * - * @param displayed {@code true} to display, and {@code false} to hide. - */ - public void setDisplayed(Boolean displayed) - { - this.displayed = displayed; - } - - /** - * Returns the duration of the timer, in seconds. - * - * @return The duration. - */ - public Integer getDuration() - { - return duration; - } - - /** - * Returns the number of hours left until the end of this countdown. - * - * @return The number of hours left. - */ - public Integer getHoursLeft() - { - return hoursLeft; - } - - /** - * Returns the number of minutes left until the end of this countdown. - * - * @return The number of minutes left. - */ - public Integer getMinutesLeft() - { - return minutesLeft; - } - - /** - * Returns the number of seconds left until the end of this countdown. - * - * @return The number of seconds left. - */ - public Integer getSecondsLeft() - { - return secondsLeft; - } - - /** - * Returns the number of hours left until the end of this countdown, before the last update. - * <p> - * Used by the scoreboard, to remove the old score. - * - * @return The old number of hours left, or -1 if the timer was never updated. - */ - public Integer getOldHoursLeft() - { - return oldHoursLeft; - } - - /** - * Returns the number of minutes left until the end of this countdown, before the last update. - * <p> - * Used by the scoreboard, to remove the old score. - * - * @return The old number of minutes left, or -1 if the timer was never updated. - */ - public Integer getOldMinutesLeft() - { - return oldMinutesLeft; - } - - /** - * Returns the number of seconds left until the end of this countdown, before the last update. - * <p> - * Used by the scoreboard, to remove the old score. - * - * @return The old number of seconds left, or -1 if the timer was never updated. - */ - public Integer getOldSecondsLeft() - { - return oldSecondsLeft; - } - - /** - * Checks if this timer is paused. - * - * @return true if the timer is paused. - */ - public Boolean isPaused() - { - return paused; - } - - /** - * Returns true if this timer is displayed as "hh:mm:ss" in the scoreboard. - * - * @return true if this timer is displayed as "hh:mm:ss" in the scoreboard. - */ - public Boolean getDisplayHoursInTimer() - { - return displayHoursInTimer; - } - - @Override - public boolean equals(Object other) - { - return other instanceof UHTimer && ((UHTimer) other).getName().equals(this.getName()); - } - - @Override - public String toString() - { - return toString(displayHoursInTimer); - } - - public String toString(boolean displayHours) - { - if (displayHours) - { - /// Timer. {0} = hours; {1} = minutes; {2} = seconds. - return I.t("{0}{gray}:{white}{1}{gray}:{white}{2}", formatter.format(hoursLeft), formatter.format(minutesLeft), formatter.format(secondsLeft)); - } - else - { - /// Timer. {0} = minutes; {1} = seconds. - return I.t("{white}{0}{gray}:{white}{1}", formatter.format(minutesLeft), formatter.format(secondsLeft)); - } - } - - @Override - public int hashCode() - { - return id.hashCode(); - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/utils/ColorsUtils.java b/src/main/java/eu/carrade/amaury/UHCReloaded/utils/ColorsUtils.java deleted file mode 100644 index 4b7470d..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/utils/ColorsUtils.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.utils; - -import org.bukkit.ChatColor; -import org.bukkit.DyeColor; - - -public final class ColorsUtils -{ - private ColorsUtils() {} - - public static DyeColor chat2Dye(ChatColor chatColor) - { - switch (chatColor) - { - case BLACK: - return DyeColor.BLACK; - - case BLUE: - case DARK_BLUE: - return DyeColor.BLUE; - - case DARK_GREEN: - return DyeColor.GREEN; - - case DARK_AQUA: - return DyeColor.CYAN; - - case DARK_RED: - return DyeColor.RED; - - case DARK_PURPLE: - return DyeColor.PURPLE; - - case GOLD: - case YELLOW: - return DyeColor.YELLOW; - - case GRAY: - case DARK_GRAY: - return DyeColor.SILVER; - - case GREEN: - return DyeColor.LIME; - - case AQUA: - return DyeColor.LIGHT_BLUE; - - case RED: - return DyeColor.ORANGE; - - case LIGHT_PURPLE: - return DyeColor.PINK; - - // White, reset & formatting - default: - return DyeColor.WHITE; - } - } -} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/utils/UHSound.java b/src/main/java/eu/carrade/amaury/UHCReloaded/utils/UHSound.java deleted file mode 100644 index ce123d8..0000000 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/utils/UHSound.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * 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.utils; - -import eu.carrade.amaury.UHCReloaded.UHConfig; -import fr.zcraft.zlib.components.configuration.ConfigurationValueHandler; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Sound; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; - - -/** - * Represents a sound, with volume and pitch. - * - * @author Amaury Carrade - */ -public class UHSound -{ - private Sound sound = null; - private Float volume = 1f; - private Float pitch = 1f; - - /** - * Constructs a sound with volume = 1f and pitch = 1f. - * - * @param sound The sound. - */ - public UHSound(final Sound sound) - { - this.sound = sound; - } - - public UHSound(final Sound sound, final Float volume, final Float pitch) - { - this.sound = sound; - this.volume = volume; - this.pitch = pitch; - } - - /** - * Constructs a sound from a configuration section. - * <p> - * Format: - * <pre> - * key: - * name: string parsable as a sound. If not parsable, null used (i.e. no sound played). - * volume: decimal number - * pitch: decimal number - * </pre> - * - * @param config The configuration section. - */ - public UHSound(ConfigurationSection config) - { - if (config == null) - { - return; - } - - this.sound = string2Sound(config.getString("name")); - this.volume = (float) config.getDouble("volume"); - this.pitch = (float) config.getDouble("pitch"); - } - - /** - * Constructs a sound from a zLib sound configuration section. - * <p> - * Format: - * <pre> - * key: - * name: string parsable as a sound. If not parsable, null used (i.e. no sound played). - * volume: decimal number - * pitch: decimal number - * </pre> - * - * @param config The configuration section. - */ - public UHSound(UHConfig.SoundSection config) - { - if (config == null) - { - return; - } - - this.sound = config.NAME.get(); - this.volume = (float) config.VOLUME.get(); - this.pitch = (float) config.PITCH.get(); - } - - /** - * Plays the sound for the specified player. - * <p> - * The sound is played at the current location of the player. - * <p> - * If the sound is null, fails silently. - * - * @param player The player. - */ - public void play(Player player) - { - play(player, player.getLocation()); - } - - /** - * Plays the sound for the specified player, at the specified location. - * <p> - * If the sound is null, fails silently. - * - * @param player The player. - * @param location The location of the sound. - */ - public void play(Player player, Location location) - { - player.playSound(location, sound, volume, pitch); - } - - /** - * Plays this sound for all players, at the current location of the players. - */ - public void broadcast() - { - for (Player player : Bukkit.getServer().getOnlinePlayers()) - { - play(player); - } - } - - public Sound getSound() - { - return sound; - } - - public void setSound(Sound sound) - { - this.sound = sound; - } - - public Float getVolume() - { - return volume; - } - - public void setVolume(Float volume) - { - this.volume = volume; - } - - public Float getPitch() - { - return pitch; - } - - public void setPitch(Float pitch) - { - this.pitch = pitch; - } - - @Override - public String toString() - { - return "UHSound [sound=" + sound + ", volume=" + volume + ", pitch=" + pitch + "]"; - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((pitch == null) ? 0 : pitch.hashCode()); - result = prime * result + ((sound == null) ? 0 : sound.hashCode()); - result = prime * result + ((volume == null) ? 0 : volume.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) return true; - if (!(obj instanceof UHSound)) return false; - - final UHSound other = (UHSound) obj; - if (pitch == null) - { - if (other.pitch != null) - return false; - } - else if (!pitch.equals(other.pitch)) - { - return false; - } - return sound == other.sound && (volume == null ? other.volume == null : volume.equals(other.volume)); - } - - - /** - * Converts a string to a Sound. - * <p> - * "<code>ANVIL_LAND</code>", "<code>Anvil Land</code>" and "<code>ANVIL Land</code>" are recognized as - * <code>Sound.ANVIL_LAND</code>, as example. - * - * @param soundName The text to be converted. - * @return The corresponding Sound, or null if there isn't any match. - */ - public static Sound string2Sound(String soundName) - { - if (soundName != null) - { - soundName = soundName.trim().toUpperCase().replace(" ", "_"); - try - { - return Sound.valueOf(soundName); - } - catch (IllegalArgumentException e) - { - String[] prefixes = new String[] {"BLOCK_", "ENTITY_", "ITEM_", "MUSIC_", "WEATHER_"}; - for (String prefix : prefixes) - { - try { return Sound.valueOf(prefix + soundName); } - catch(IllegalArgumentException ignored) {} - } - - // Non-existent sound - return null; - } - } - - return null; - } - - @ConfigurationValueHandler - public static Sound handleSoundValue(Object object) - { - return string2Sound(object.toString()); - } -} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/QSGConfig.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/QSGConfig.java new file mode 100644 index 0000000..06df7e8 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/QSGConfig.java @@ -0,0 +1,33 @@ +package eu.carrade.amaury.quartzsurvivalgames; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.map; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.section; + +import fr.zcraft.quartzlib.components.configuration.Configuration; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.configuration.ConfigurationMap; +import fr.zcraft.quartzlib.components.configuration.ConfigurationSection; +import java.util.Locale; +import org.bukkit.ChatColor; + + +public class QSGConfig extends Configuration { + static public final ConfigurationItem<Locale> LANG = item("lang", Locale.class); + + static public final ConfigurationItem<String> TITLE = + item("title", ChatColor.WHITE + "" + ChatColor.BOLD + "Quartz" + ChatColor.RED + "" + ChatColor.BOLD + "SurvivalGames"); + + static public final ConfigurationItem<Boolean> BUILT_IN_MODULES = item("built-in-modules", true); + static public final ConfigurationMap<String, Boolean> MODULES = map("modules", String.class, Boolean.class); + + static public final WorldsSection WORLDS = section("worlds", WorldsSection.class); + + static public class WorldsSection extends ConfigurationSection { + + public final ConfigurationItem<String> OVERWORLD = item("overworld", "world"); + public final ConfigurationItem<String> NETHER = item("nether", "world_nether"); + public final ConfigurationItem<String> THE_END = item("the-end", "world_the_end"); + + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/QuartzSurvivalGames.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/QuartzSurvivalGames.java new file mode 100644 index 0000000..87c03d6 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/QuartzSurvivalGames.java @@ -0,0 +1,283 @@ +/* + * 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.quartzsurvivalgames; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.ModulesManager; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.BorderModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.ModulesModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.SpawnsModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.SpectatorsModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.teams.TeamsModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimersModule; +import eu.carrade.amaury.quartzsurvivalgames.utils.OfflinePlayersLoader; +import fr.zcraft.quartzlib.components.commands.Commands; +import fr.zcraft.quartzlib.components.gui.Gui; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.components.i18n.I18n; +import fr.zcraft.quartzlib.components.scoreboard.SidebarScoreboard; +import fr.zcraft.quartzlib.core.QuartzLib; +import fr.zcraft.quartzlib.core.QuartzPlugin; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import java.util.Arrays; +import java.util.List; +import java.util.function.BiConsumer; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.world.WorldLoadEvent; +import org.bukkit.scoreboard.Scoreboard; + + +public class QuartzSurvivalGames extends QuartzPlugin implements Listener { + private static QuartzSurvivalGames instance; + + private ModulesManager modulesManager = null; + private Scoreboard scoreboard = null; + + private World worldNormal = null; + private World worldNether = null; + private World worldTheEnd = null; + + private boolean worldsLoaded = false; + + /** + * Returns the plugin's instance. + */ + public static QuartzSurvivalGames get() { + return instance; + } + + @Override + public void onEnable() { + instance = this; + + this.saveDefaultConfig(); + + + /* *** Required zLib base components *** */ + + loadComponents(QSGConfig.class, I18n.class, Commands.class, SidebarScoreboard.class, Gui.class, + OfflinePlayersLoader.class); + + modulesManager = loadComponent(ModulesManager.class); + + + /* *** Internationalization *** */ + + if (QSGConfig.LANG.isDefined()) { + I18n.setPrimaryLocale(QSGConfig.LANG.get()); + } + + PluginLogger.info("Using locale {0} (fallback on {1})", I18n.getPrimaryLocale(), I18n.getFallbackLocale()); + + + /* *** Core events *** */ + + QuartzLib.registerEvents(this); + + + /* *** Core modules *** */ + + modulesManager.registerModules( + ModulesModule.class, // Manages the modules from the game/commands. + + SidebarModule.class, // Manages the sidebar and provides hooks for other modules. + // Must be loaded before the game-related modules. + + TeamsModule.class, // Manages the teams (for both team & solo games). + // Must be loaded before the game-related modules. + + TimersModule.class, // Manages the time in everything. + + BorderModule.class, // Manages the border of the map. + // Must be loaded before the spawns module. + + SpawnsModule.class, // Manages the spawn points and teleportation. + // Must be loaded before the game-related modules. + + GameModule.class, // Manages the game progression. + + SpectatorsModule.class // Manages the spectators. + ); + + + /* *** Built-in modules *** */ + + if (QSGConfig.BUILT_IN_MODULES.get()) { + modulesManager.registerBuiltInModules(); + } + + + /* *** Config modules *** */ + + QSGConfig.MODULES.forEach((BiConsumer<String, Boolean>) modulesManager::registerModule); + + + /* *** Loads modules from startup time *** */ + + modulesManager.loadModules(ModuleLoadTime.STARTUP); + + + /* *** Loads modules from post-world time if worlds are loaded (server reloaded) *** */ + + if (!getServer().getWorlds().isEmpty()) { + onEnableWhenWorldsAvailable(); + } + + + /* *** Sets scoreboard for already-logged-in players (server reloaded) *** */ + + RunTask.nextTick(() -> Bukkit.getOnlinePlayers().forEach(player -> player.setScoreboard(scoreboard))); + + + /* *** Ready *** */ + + PluginLogger.info(I.t("Ultra Hardcore plugin loaded.")); + } + + /** + * Run when the worlds are available (on plugin enabled if reloaded, on worlds ready else). + */ + private void onEnableWhenWorldsAvailable() { + scoreboard = Bukkit.getServer().getScoreboardManager().getNewScoreboard(); + + RunTask.nextTick(() -> { + worldNormal = setDefaultWorld(World.Environment.NORMAL, QSGConfig.WORLDS.OVERWORLD.get()); + worldNether = setDefaultWorld(World.Environment.NETHER, QSGConfig.WORLDS.NETHER.get()); + worldTheEnd = setDefaultWorld(World.Environment.THE_END, QSGConfig.WORLDS.THE_END.get()); + + modulesManager.loadModules(ModuleLoadTime.POST_WORLD); + }); + + worldsLoaded = true; + } + + /** + * @return The modules manager. + */ + public ModulesManager getModulesManager() { + return modulesManager; + } + + /** + * @return The Bukkit scoreboard to use for everything. + */ + public Scoreboard getScoreboard() { + return scoreboard; + } + + /** + * @param environment An environment. + * @return The world to use for this environment in the game. + */ + public World getWorld(final World.Environment environment) { + if (environment == null) { + return worldNormal; + } + + switch (environment) { + case NORMAL: + return worldNormal; + + case NETHER: + return worldNether; + + case THE_END: + default: + return worldTheEnd; + } + } + + /** + * @return A stream containing all three playing worlds. + */ + public List<World> getWorlds() { + return Arrays.asList(worldNormal, worldNether, worldTheEnd); + } + + @EventHandler(priority = EventPriority.LOWEST) + public final void onWorldsLoaded(final WorldLoadEvent e) { + if (!worldsLoaded) { + onEnableWhenWorldsAvailable(); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onGamePhaseChanged(final GamePhaseChangedEvent ev) { + switch (ev.getNewPhase()) { + case STARTING: + modulesManager.loadModules(ModuleLoadTime.ON_GAME_STARTING); + break; + + case IN_GAME: + modulesManager.loadModules(ModuleLoadTime.ON_GAME_START); + break; + + case END: + modulesManager.loadModules(ModuleLoadTime.ON_GAME_END); + break; + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public final void onPlayerJoin(final PlayerJoinEvent ev) { + ev.getPlayer().setScoreboard(scoreboard); + } + + private World setDefaultWorld(final World.Environment environment, final String worldName) { + final World userWorld = Bukkit.getWorld(worldName); + + // If the world is valid, it is used as-is. + if (userWorld != null && userWorld.getEnvironment() == environment) { + return userWorld; + } + + // Else we use the first world we found with the right type. + for (final World world : Bukkit.getWorlds()) { + if (world.getEnvironment() == environment) { + return world; + } + } + + // We finally fallback on the first world regardless of its type to have at least something. + return Bukkit.getWorlds().get(0); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleCategory.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleCategory.java new file mode 100644 index 0000000..89398ce --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleCategory.java @@ -0,0 +1,165 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.core; + +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.items.ItemStackBuilder; +import java.util.function.Supplier; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; + +public enum ModuleCategory { + CORE( + I.t("Core Modules"), + I.t("These modules are the core of UHCReloaded, required by other modules."), + Material.BEDROCK, + ChatColor.DARK_RED + ), + + WORLD_GENERATION( + I.t("World Generation"), + I.t("These modules alter the world generation. To use them, the server must be started without world."), + Material.COMPARATOR, + ChatColor.DARK_GREEN + ), + + WAITING_PHASE( + I.t("Waiting Phase"), + I.t("These modules manage the waiting phase, when the game is not yet started."), + Material.CLOCK, + ChatColor.YELLOW + ), + + STARTING( + I.t("Game Beginning"), + I.t("These modules enhance the starting phase of the game."), + Material.FEATHER, + ChatColor.GOLD + ), + + END( + I.t("Game End"), + I.t("These modules alter the game end (either player deaths or whole game end)."), + Material.SKELETON_SKULL, + ChatColor.RED + ), + + GAMEPLAY( + I.t("Gameplay"), + I.t("These modules alter the world or gameplay during the game, e.g. adding or nerfing creatures, effects... This category does not contains scenarii, which are in a dedicated one."), + Material.SADDLE, + ChatColor.DARK_AQUA + ), + + SCENARII( + I.t("Scenarii"), + I.t("These modules adds scenarii to the game, i.e. global set of changes that changes the gameplay in a deeper way, and possibly the whole game experience."), + Material.KNOWLEDGE_BOOK, + ChatColor.AQUA + ), + + UTILITIES( + I.t("Utilities"), + I.t("These modules provides tools and utilities to manage the game and offer useful commands."), + Material.REPEATING_COMMAND_BLOCK, + ChatColor.DARK_PURPLE + ), + + COSMETICS( + I.t("Cosmetics"), + I.t("These modules adds cosmetics things to the game, like effects or visual enhancements that can be useful but does not change the gameplay."), + Material.ROSE_BUSH, + ChatColor.LIGHT_PURPLE + ), + + EXTERNAL( + I.t("External"), + I.t("These modules adds features alongside the game, like web maps, external summaries..."), + Material.ENDER_CHEST, + ChatColor.DARK_GREEN + ), + + OTHER( + I.t("Others"), + I.t("All uncategorized modules goes there."), + new ItemStackBuilder(Material.PLAYER_HEAD).withMeta((SkullMeta meta) -> meta.setOwner("MHF_Question")), + ChatColor.WHITE + ); + + + private final String displayName; + private final String description; + private final ItemStack icon; + private final ChatColor color; + + ModuleCategory(final String displayName, final String description, final ItemStack icon, ChatColor color) { + + this.displayName = displayName; + this.description = description; + this.icon = icon; + this.color = color; + } + + ModuleCategory(final String displayName, final String description, final ItemStackBuilder icon, ChatColor color) { + this(displayName, description, icon.item(), color); + } + + ModuleCategory(final String displayName, final String description, final Supplier<ItemStack> icon, + ChatColor color) { + this(displayName, description, icon.get(), color); + } + + ModuleCategory(final String displayName, final String description, final Material icon, ChatColor color) { + this(displayName, description, new ItemStack(icon), color); + } + + public String getDisplayName() { + return displayName; + } + + public String getDescription() { + return description; + } + + public ItemStack getIcon() { + return icon.clone(); + } + + public ChatColor getColor() { + return color; + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleInfo.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleInfo.java new file mode 100644 index 0000000..6359d2d --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleInfo.java @@ -0,0 +1,150 @@ +/* + * 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.quartzsurvivalgames.core; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.bukkit.Material; + + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface ModuleInfo { + /** + * @return A name for the module (optional). + */ + String name() default ""; + + /** + * @return A description for this module. + */ + String description() default ""; + + /** + * @return A short description for this module. Used instead of the long one in the modules + * list GUI, so you can write novels in the description if you want. + */ + String short_description() default ""; + + /** + * @return The author(s) of this module. + */ + String authors() default ""; + + /** + * @return When this module should load. + */ + ModuleLoadTime when() default ModuleLoadTime.POST_WORLD; + + /** + * @return The category under which this module should be classed. + */ + ModuleCategory category() default ModuleCategory.OTHER; + + /** + * @return The icon we should use for this module. If not provide (or {@link Material#AIR air}), + * we'll use the category's icon. + */ + Material icon() default Material.AIR; + + /** + * @return The configuration class to initialize (if any). + * ConfigurationInstance.class is used as a default value to represent no settings as null values are + * not allowed and classes will always be subclasses of this one. + */ + Class<? extends ConfigurationInstance> settings() default ConfigurationInstance.class; + + /** + * @return The settings's filename (without the .yml extension). + * If empty/not provided, derived from the class name. + */ + String settings_filename() default ""; + + /** + * @return The settings's default filename, containing the default configuration written + * to the server's plugins/UHPlugin/modules directory if the file does not exists. + * <p> + * The format can either be a simple filename without extension, like “moduleName“, and + * the file will be copied from the UHCReloaded's JAR, from modules/moduleName.yml; or + * the filename prefixed by the plugin name like so: “OtherPlugin:moduleName”, and the + * file will be copied from the given plugin's JAR, from modules/moduleName.yml too. + * <p> + * If left empty, it will be derived from the module name and category, by converting + * the module's class name into hyphened-snake-case, removing the “-module” suffix (if + * any) and prefixing by the category converted to hyphened-snake-case. + * Example: “external-reports”. + * <p> + * In all cases, the file will be copied into UHPlugin's data directory, under module/. + */ + String settings_default_filename() default ""; + + /** + * @return A list of external Bukkit/Spigot plugin this module depends on. + */ + String[] depends() default {}; + + /** + * @return {@code true} if this module is an internal core module + * that should always be loaded first. + */ + boolean internal() default false; + + /** + * @return {@code true} if this module is a technical core module + * that should not be displayed in the /config gui. + */ + boolean hidden() default false; + + /** + * @return {@code true} if the module can be unloaded and re-loaded. This reflects the status change + * from inside the game, as all modules can always be disabled on the configuration file (or not loaded + * at all). + * <p> + * If this is {@code true}, when disabled, a module will have its {@link QSGModule#onDisable()} + * method called, and after that, its listener will be unregistered and the module instance removed from the system. + * <p> + * When re-loaded, a whole new instance will be created. + */ + boolean can_be_unloaded() default true; + + /** + * @return {@code true} if the module can be loaded after the moment it was declared to be loaded. If {@code false}, + * and an user tries to enable/load it during the game and the module is configured to be loaded, let's say, on + * {@link ModuleLoadTime#ON_GAME_STARTING game starting}, the operation will fail. Use this if you depends on the + * fact that the {@link QSGModule#onEnable()} method is called at a specific time. + */ + boolean can_be_loaded_late() default true; +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleLoadTime.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleLoadTime.java new file mode 100644 index 0000000..bb6a0da --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleLoadTime.java @@ -0,0 +1,82 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.core; + +import fr.zcraft.quartzlib.components.i18n.I; + +public enum ModuleLoadTime { + /** + * Loads the module at startup, before the worlds are loaded. + * <p> + * Please note that most core modules (and localization) are not loaded at this point. Use that + * for modules altering the world generation. + */ + STARTUP(I.t("When the server starts")), + + /** + * Loads the module after the world(s), or immediately if the plugin is reloaded. + * The thing is, all worlds will be loaded when the module is. + */ + POST_WORLD(I.t("When the worlds are loaded")), + + /** + * Loads the module when the game phase is set to STARTING, i.e. when the /uh start command + * is used. + */ + ON_GAME_STARTING(I.t("When the game start command is executed")), + + /** + * Loads the module when the game starts, i.e. when all players falls from their spawn into + * the world. + */ + ON_GAME_START(I.t("When the game starts for real (after teleportations)")), + + /** + * Loads the module when the game ends. + */ + ON_GAME_END(I.t("When the game ends")); + + + private final String description; + + ModuleLoadTime(String description) { + + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleLogger.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleLogger.java new file mode 100644 index 0000000..8beb3fd --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleLogger.java @@ -0,0 +1,124 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.core; + +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.components.rawtext.RawText; +import fr.zcraft.quartzlib.core.QuartzLib; +import fr.zcraft.quartzlib.tools.text.RawMessage; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +public class ModuleLogger extends Logger { + private final String moduleName; + private final String loggerName; + + public ModuleLogger(Class<? extends QSGModule> module) { + super(QuartzLib.getPlugin().getClass().getCanonicalName(), null); + + setParent(QuartzLib.getPlugin().getLogger()); + setLevel(Level.ALL); + + moduleName = ModuleWrapper.computeModuleName(module); + loggerName = "[" + moduleName + "] "; + } + + @Override + public void log(LogRecord logRecord) { + logRecord.setMessage(loggerName + logRecord.getMessage()); + super.log(logRecord); + } + + public void log(Level level, String message, Throwable ex, Object... args) { + log(level, message, args); + log(level, "Exception: ", ex); + } + + public void info(String message, Object... args) { + log(Level.INFO, message, args); + } + + public void warning(String message, Object... args) { + log(Level.WARNING, message, args); + } + + public void warning(String message, Throwable ex) { + log(Level.WARNING, message, ex); + } + + public void warning(String message, Throwable ex, Object... args) { + log(Level.WARNING, message, ex, args); + } + + public void error(String message) { + log(Level.SEVERE, message); + } + + public void error(String message, Throwable ex) { + log(Level.SEVERE, message, ex); + } + + public void error(String message, Throwable ex, Object... args) { + log(Level.SEVERE, message, ex, args); + } + + public void error(String message, Object... args) { + log(Level.SEVERE, message, args); + } + + public void broadcastAdministrative(final String message) { + broadcastAdministrative(message, ChatColor.stripColor(message)); + } + + public void broadcastAdministrative(final RawText message) { + // TODO use permissions + Bukkit.getOnlinePlayers().stream().filter(Player::isOp).forEach(player -> RawMessage.send(player, message)); + info(ChatColor.stripColor(message.toPlainText())); + } + + public void broadcastAdministrativePrefixed(final String message) { + broadcastAdministrative(QSGUtils.prefixedMessage(moduleName, message), ChatColor.stripColor(message)); + } + + private void broadcastAdministrative(final String messagePlayers, final String messageConsole) { + // TODO use permissions + Bukkit.getOnlinePlayers().stream().filter(Player::isOp).forEach(player -> player.sendMessage(messagePlayers)); + info(messageConsole); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleWrapper.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleWrapper.java new file mode 100644 index 0000000..1ebbbc8 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModuleWrapper.java @@ -0,0 +1,511 @@ +/* + * 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.quartzsurvivalgames.core; + +import com.google.common.base.CaseFormat; +import com.google.common.base.Charsets; +import eu.carrade.amaury.quartzsurvivalgames.core.events.ModuleDisabledEvent; +import eu.carrade.amaury.quartzsurvivalgames.core.events.ModuleEnabledEvent; +import eu.carrade.amaury.quartzsurvivalgames.core.events.ModuleLoadedEvent; +import eu.carrade.amaury.quartzsurvivalgames.core.events.ModuleUnloadedEvent; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.core.QuartzLib; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.items.ItemStackBuilder; +import fr.zcraft.quartzlib.tools.reflection.Reflection; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.lang.reflect.InvocationTargetException; +import java.util.stream.Stream; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; + + +public class ModuleWrapper { + private final String name; + private final String shortDescription; + private final String description; + private final String authors; + + private final ModuleLoadTime when; + + private final ModuleCategory category; + private final Material icon; + private final Class<? extends QSGModule> moduleClass; + private final Class<? extends ConfigurationInstance> moduleConfiguration; + private final String settingsFileName; + private final String settingsDefaultFileName; + private final boolean internal; + private final boolean hidden; + private final boolean canBeUnloaded; + private final boolean canBeLoadedLate; + private final String[] dependencies; + private boolean enabled; + private QSGModule instance = null; + + public ModuleWrapper(final Class<? extends QSGModule> moduleClass) { + this(moduleClass, true); + } + + public ModuleWrapper(final Class<? extends QSGModule> moduleClass, boolean enabled) { + this.name = computeModuleName(moduleClass); + this.moduleClass = moduleClass; + this.enabled = enabled; + + final ModuleInfo info = moduleClass.getAnnotation(ModuleInfo.class); + + if (info == null) { + description = ""; + shortDescription = ""; + authors = ""; + internal = false; + hidden = false; + canBeUnloaded = true; + canBeLoadedLate = true; + when = ModuleLoadTime.POST_WORLD; + category = ModuleCategory.OTHER; + icon = Material.AIR; + moduleConfiguration = null; + settingsFileName = null; + settingsDefaultFileName = null; + dependencies = new String[] {}; + } else { + description = info.description(); + shortDescription = info.short_description(); + authors = info.authors(); + internal = info.internal(); + hidden = info.hidden(); + canBeUnloaded = info.can_be_unloaded(); + canBeLoadedLate = info.can_be_loaded_late(); + when = info.when(); + category = info.category(); + icon = info.icon(); + moduleConfiguration = info.settings().equals(ConfigurationInstance.class) ? null : info.settings(); + settingsFileName = info.settings_filename().isEmpty() ? null : info.settings_filename(); + settingsDefaultFileName = + info.settings_default_filename().isEmpty() ? null : info.settings_default_filename(); + dependencies = info.depends(); + } + + saveDefaultConfig(); + loadConfiguration(); + } + + static String computeModuleName(Class<? extends QSGModule> moduleClass) { + final ModuleInfo info = moduleClass.getAnnotation(ModuleInfo.class); + + if (info == null || info.name().isEmpty()) { + return StringUtils.capitalize( + String.join(" ", StringUtils.splitByCharacterTypeCamelCase(moduleClass.getSimpleName()))); + } else { + return info.name(); + } + } + + /** + * Enables this module. + * + * @param late {@code true} if the module is not loaded when specified in + * its {@link ModuleInfo properties}. + */ + public boolean load(boolean late) { + if (isLoaded()) { + return true; + } + + // Check dependencies + + for (final String dependency : dependencies) { + final Plugin plugin = Bukkit.getPluginManager().getPlugin(dependency); + if (plugin == null) { + if (dependencies.length >= 2) { + PluginLogger.error("Cannot enable module {0}: missing dependency {1} (depends on {2}).", name, + dependency, String.join(", ", dependencies)); + } else { + PluginLogger.error("Cannot enable module {0}: missing dependency {1}.", name, dependency); + } + + return false; + } else if (!plugin.isEnabled()) { + // Ensures every dependency is available when a module is loaded. + Bukkit.getPluginManager().enablePlugin(plugin); + } + } + + instance = QuartzLib.loadComponent(moduleClass); + + Bukkit.getPluginManager().callEvent(new ModuleLoadedEvent(this, late)); + + if (late) { + instance.onLateEnable(); + } + + return true; + } + + /** + * Disable this module. + */ + public void unload() { + if (instance == null) { + return; + } + + instance.setEnabled(false); + QuartzLib.unregisterEvents(instance); + + Bukkit.getPluginManager().callEvent(new ModuleUnloadedEvent(this)); + + instance = null; + } + + /** + * Enables or disables this module. + * + * @param enabled new status. + * @return {@code true} if the operation succeeded. It will be {@code false} + * if you try to disable the module and if the module is internal or the + * module is loaded and marked as un-loadable, or if you try to enable the + * module and it is marked as un-loadable after its auto-load moment. + */ + public boolean setEnabled(boolean enabled) { + if (this.enabled != enabled) { + // Can we enabled this module? + if (enabled) { + if (!canBeEnabled()) { + return false; + } + } + + // Can we disable this module? + else if (!canBeDisabled()) { + return false; + } + + + this.enabled = enabled; + + if (enabled) { + Bukkit.getPluginManager().callEvent(new ModuleEnabledEvent(this)); + + if (QSG.get().getModulesManager().isLoaded(when)) { + return load(true); + } + } else { + Bukkit.getPluginManager().callEvent(new ModuleDisabledEvent(this)); + unload(); + } + } + + return true; + } + + /** + * @return {@code true} if after being disabled, this module will be reloadable + * (can depends on the moment this method is called). + */ + public boolean canBeEnabled() { + return canBeLoadedLate || !QSG.get().getModulesManager().isLoaded(when); + } + + /** + * @return {@code true} if, at the moment this method is called, this module can be disabled. + */ + public boolean canBeDisabled() { + return !internal && !(isLoaded() && !canBeUnloaded); + } + + /** + * @return A name for this module. Either the provided name using {@link ModuleInfo} or a name derived from the class name. + */ + public String getName() { + return name; + } + + /** + * @return A description for the module, or {@code null} if none provided. + */ + public String getDescription() { + return description != null && !description.isEmpty() ? description : null; + } + + /** + * @return A short description for the module, or {@code null} if none provided. + */ + public String getShortDescription() { + return shortDescription != null && !shortDescription.isEmpty() ? shortDescription : null; + } + + /** + * @return The authors of the module, or {@code null} if not provided. + */ + public String getAuthors() { + return authors != null && !authors.isEmpty() ? authors : null; + } + + /** + * @return This module's category. + */ + public ModuleCategory getCategory() { + return category; + } + + /** + * @return This module's icon: either the declared one, or the category's. + */ + public ItemStack getIcon() { + return icon == Material.AIR ? category.getIcon() : new ItemStack(icon); + } + + /** + * Generates and returns a full icon for the module, including its status and + * description in the tooltip. + * + * @param complete If {@code true}, will use the long complete description. + * Else, will use the short description if available, else + * the long one. + * @return The icon. + */ + public ItemStackBuilder getFullIcon(final boolean complete) { + final ItemStackBuilder icon = new ItemStackBuilder(getIcon()) + .title( + (isLoaded() ? ChatColor.GREEN : (isEnabled() ? ChatColor.GOLD : ChatColor.RED)) + "" + + ChatColor.BOLD + "\u2758 ", + category.getColor() + "" + ChatColor.BOLD + name + ) + .loreLine( + ChatColor.DARK_GRAY + category.getDisplayName(), + ChatColor.DARK_GRAY + " - ", + ChatColor.DARK_GRAY + + (enabled ? (isLoaded() ? I.t("Enabled and loaded") : I.t("Enabled")) : I.t("Disabled")) + ); + + String description; + if (((description = getShortDescription()) != null && !complete) || (description = getDescription()) != null) { + icon.loreSeparator().longLore(ChatColor.WHITE, description, complete ? 100 : 42); + } + + icon.loreSeparator().longLore(ChatColor.BLUE, I.t("Load time")) + .longLore(ChatColor.WHITE, when.getDescription(), 42); + + if (dependencies.length != 0) { + icon.loreSeparator().longLore(ChatColor.BLUE, I.t("External dependencies")); + Stream.of(dependencies).forEach(dep -> icon.loreLine(ChatColor.GRAY + "- ", + (Bukkit.getPluginManager().getPlugin(dep) != null ? ChatColor.WHITE : ChatColor.RED) + dep)); + } + + String authors; + if ((authors = getAuthors()) != null) { + icon.loreSeparator().longLore(ChatColor.BLUE, I.t("Brought to you by")) + .longLore(ChatColor.WHITE, authors, 42); + } + + return icon.hideAllAttributes(); + } + + /** + * @return A list of external plugins this module depends on. + */ + public String[] getDependencies() { + return dependencies; + } + + /** + * @return When this module should be loaded. + */ + public ModuleLoadTime getWhen() { + return when; + } + + /** + * @return This module's base class. + */ + public Class<? extends QSGModule> getModuleClass() { + return moduleClass; + } + + private String getDefaultSettingsFileName() { + return String.format("%s-%s", category.name().toLowerCase().replace('_', '-'), StringUtils + .removeEnd(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, moduleClass.getSimpleName()), "-module")); + } + + /** + * @return A {@link File} representing the configuration file on the server's filesystem. + */ + private File getConfigurationFile() { + final String settingsFileName = + this.settingsFileName != null ? this.settingsFileName + ".yml" : getDefaultSettingsFileName() + ".yml"; + return new File(QuartzLib.getPlugin().getDataFolder(), "modules" + File.separator + settingsFileName); + } + + /** + * Saves the default configuration file into the plugin's directory, if it + * does not exists ad the default configuration file does exist. + */ + public void saveDefaultConfig() { + final File targetSettingsFile = getConfigurationFile(); + if (targetSettingsFile.exists()) { + return; + } + + final String settingsDefaultFileName = + this.settingsDefaultFileName != null ? this.settingsDefaultFileName : getDefaultSettingsFileName(); + + final Plugin plugin; + final String settingsDefaultFilePath; + + // If the default file is in another plugin + if (settingsDefaultFileName.contains(":")) { + final String[] parts = settingsDefaultFileName.split(":"); + final Plugin pl = Bukkit.getPluginManager().getPlugin(parts[0]); + if (pl != null) { + plugin = pl; + settingsDefaultFilePath = + "modules" + File.separator + String.join(":", (String[]) ArrayUtils.remove(parts, 0)) + ".yml"; + } else { + return; + } + } else { + plugin = QSG.get(); + settingsDefaultFilePath = "modules" + File.separator + settingsDefaultFileName + ".yml"; + } + + final InputStream stream = plugin.getResource(settingsDefaultFilePath); + if (stream == null) { + return; + } + + try (final InputStreamReader reader = new InputStreamReader(stream, Charsets.UTF_8)) { + final StringBuilder buffer = new StringBuilder(); + + int currentChar; + while ((currentChar = reader.read()) != -1) { + buffer.append((char) currentChar); + } + + targetSettingsFile.getParentFile().mkdirs(); + if (!targetSettingsFile.createNewFile()) { + return; + } + + try (final PrintWriter writer = new PrintWriter(targetSettingsFile)) { + writer.write(buffer.toString()); + } + } + catch (final IOException e) { + PluginLogger.error("Cannot create {0}'s default configuration file.", e, getName()); + } + } + + /** + * Loads the configuration from its file and initialize the class. + */ + private void loadConfiguration() { + if (moduleConfiguration != null) { + final File settingsFile = getConfigurationFile(); + try { + if (!settingsFile.exists()) { + try { + settingsFile.getParentFile().mkdirs(); + settingsFile.createNewFile(); + } + catch (IOException e) { + PluginLogger + .error("Cannot create and populate {0}'s module configuration file - using default values.", + e, getName()); + } + } + + final ConfigurationInstance settings = Reflection.instantiate(moduleConfiguration, settingsFile); + settings.setEnabled(true); + } + catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) { + PluginLogger.info("Cannot initialize the configuration for the module {0} ({1})!", e, getName(), + moduleClass.getName()); + } + } + } + + /** + * @return {@code true} if this module is internal. + */ + public boolean isInternal() { + return internal; + } + + /** + * @return {@code true} if this module is hidden. + */ + public boolean isHidden() { + return hidden; + } + + /** + * @return {@code true} if this module can be disabled at runtime. + */ + public boolean canBeUnloaded() { + return canBeUnloaded; + } + + /** + * @return {@code true} if the module is enabled. Disabled modules will not be + * loaded when the time comes. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * @return {@code true} if the module was loaded and enabled. + */ + public boolean isLoaded() { + return instance != null && instance.isEnabled(); + } + + /** + * @return This module's instance. + */ + public QSGModule get() { + return instance; + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModulesManager.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModulesManager.java new file mode 100644 index 0000000..57c546c --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/ModulesManager.java @@ -0,0 +1,405 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.core; + +import com.google.common.reflect.ClassPath; +import eu.carrade.amaury.quartzsurvivalgames.core.events.AllModulesLoadedEvent; +import eu.carrade.amaury.quartzsurvivalgames.core.events.ModuleLoadedEvent; +import eu.carrade.amaury.quartzsurvivalgames.core.events.ModuleUnloadedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.episodes.EpisodesModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.end.kick.KickModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.other.PomfModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances.AlliancesModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.worldgen.creatures.CreaturesModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.ModulesUtils; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.Commands; +import fr.zcraft.quartzlib.core.QuartzComponent; +import fr.zcraft.quartzlib.core.QuartzLib; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.reflection.Reflection; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandMap; +import org.bukkit.command.PluginCommand; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.plugin.Plugin; + +public class ModulesManager extends QuartzComponent implements Listener { + /** + * The package were all built-in modules are stored. + */ + private final static String MODULES_PACKAGE = "eu.carrade.amaury.quartzsurvivalgames.modules"; + + /** + * These built-in modules will not be enabled by default. It includes all scenarii and world generation modules, + * so the default game is a standard one, the kick module, as spectators are better for most admins, and + * the episodes modules, as not everyone is a youtuber. + */ + private final static List<Class<? extends QSGModule>> DISABLED_BY_DEFAULT = Arrays.asList( + KickModule.class, + EpisodesModule.class, + PomfModule.class, + + // Scenarii + AlliancesModule.class, + + // World generation + CreaturesModule.class + ); + + /** + * All the registered modules. + */ + private final Map<Class<? extends QSGModule>, ModuleWrapper> modules = new HashMap<>(); + + /** + * These loads times were loaded using {@link #loadModules(ModuleLoadTime)} and are stored to not + * be loaded again (e.g. in case of cancelled start, modules with {@link ModuleLoadTime#ON_GAME_STARTING} + * will not be loaded twice). + */ + private final Set<ModuleLoadTime> loadedPriorities = new HashSet<>(); + + /** + * Gets a module's instance. This may return null if the module is not currently + * enabled. + * + * @param moduleClass The module's class. + * @param <M> The module's type. + * @return The module's instance. + */ + public static <M extends QSGModule> M getModule(final Class<M> moduleClass) { + final ModuleWrapper module = QSG.get().getModulesManager().modules.get(moduleClass); + + if (module == null || !module.isLoaded()) { + return null; + } else { + return (M) module.get(); + } + } + + /** + * Lookup and loads all built-in modules. They will be enabled by default, except if in + * the {@link #DISABLED_BY_DEFAULT disabled-by-default list}. + */ + public void registerBuiltInModules() { + final long t = System.currentTimeMillis(); + int i = 0; + + try { + for (final ClassPath.ClassInfo classInfo : ClassPath.from(getClass().getClassLoader()) + .getTopLevelClassesRecursive(MODULES_PACKAGE)) { + try { + final Class<?> potentialModuleClass = classInfo.load(); + + if (QSGModule.class.isAssignableFrom(potentialModuleClass)) { + registerModule((Class<? extends QSGModule>) potentialModuleClass, + !DISABLED_BY_DEFAULT.contains(potentialModuleClass)); + i++; + } + } catch (final Throwable e) { + PluginLogger.error("Unable to load built-in module {0}: {1}", classInfo.getName(), e.getMessage()); + } + } + } catch (final IOException e) { + PluginLogger.error("Unable to load built-in modules.", e); + } + + PluginLogger.info("Registered {0} built-in modules in {1}ms", i, System.currentTimeMillis() - t); + } + + /** + * @return A view on all registered modules. + */ + public Collection<ModuleWrapper> getModules() { + return modules.values(); + } + + /** + * Registers an UHCReloaded module (or many). It is not loaded by this method. + * + * @param modules the module's class, that must accept a zero-arguments constructor. + */ + @SafeVarargs + public final void registerModules(final Class<? extends QSGModule>... modules) { + Arrays.stream(modules).forEach(module -> registerModule(module, true)); + } + + /** + * Registers an UHCReloaded module. It is not loaded by this method. + * + * @param module the module's class, that must accept a zero-arguments constructor. + * @param initiallyEnabled {@code true} if this module, according to the configuration file, should be enabled at startup. + */ + public void registerModule(final Class<? extends QSGModule> module, final boolean initiallyEnabled) { + if (!modules.containsKey(module)) { + this.modules.put(module, new ModuleWrapper(module, initiallyEnabled)); + } + } + + /** + * Registers an UHCReloaded module. It is not loaded by this method. + * <p> + * It tries to load the following classes (in this order, taking the first existing): + * <p> + * - eu.carrade.amaury.UHCReloaded.modules.[name] + * - eu.carrade.amaury.UHCReloaded.modules.[name]Module + * - eu.carrade.amaury.UHCReloaded.modules.[capitalizedName] + * - eu.carrade.amaury.UHCReloaded.modules.[capitalizedName]Module + * - eu.carrade.amaury.UHCReloaded.modules.[firstLowercasedName].[name] + * - eu.carrade.amaury.UHCReloaded.modules.[firstLowercasedName].[name]Module + * - eu.carrade.amaury.UHCReloaded.modules.[firstLowercasedName].[capitalizedName] + * - eu.carrade.amaury.UHCReloaded.modules.[firstLowercasedName].[capitalizedName]Module + * - eu.carrade.amaury.UHCReloaded.modules.[firstLowercasedName].Module + * - [name] + * + * @param module the module's class name; the class must accept a zero-arguments constructor. + */ + public void registerModule(final String module) { + registerModule(module, true); + } + + /** + * Registers an UHCReloaded module. It is not loaded by this method. + * <p> + * It tries to load the following classes (in this order, taking the first existing): + * <p> + * - eu.carrade.amaury.UHCReloaded.modules.[name] + * - eu.carrade.amaury.UHCReloaded.modules.[name]Module + * - eu.carrade.amaury.UHCReloaded.modules.[capitalizedName] + * - eu.carrade.amaury.UHCReloaded.modules.[capitalizedName]Module + * - eu.carrade.amaury.UHCReloaded.modules.[firstLowercasedName].[name] + * - eu.carrade.amaury.UHCReloaded.modules.[firstLowercasedName].[name]Module + * - eu.carrade.amaury.UHCReloaded.modules.[firstLowercasedName].[capitalizedName] + * - eu.carrade.amaury.UHCReloaded.modules.[firstLowercasedName].[capitalizedName]Module + * - eu.carrade.amaury.UHCReloaded.modules.[firstLowercasedName].Module + * - [name] + * + * @param module the module's class name; the class must accept a zero-arguments constructor. + * @param initiallyEnabled {@code true} if this module, according to the configuration file, + * should be enabled at startup. + */ + public void registerModule(final String module, boolean initiallyEnabled) { + final Class<? extends QSGModule> moduleClass = ModulesUtils.getClassFromName( + module.replace('-', '.'), + MODULES_PACKAGE, + "Module", + QSGModule.class + ); + + if (moduleClass != null) { + registerModule(moduleClass, initiallyEnabled); + } else { + PluginLogger + .error("Error registering a module: unable to find a module named {0} in the class path. Maybe you spelled it wrong?", + module); + } + } + + /** + * Loads registered modules. Internal modules will always be loaded first. + * + * @param loadTime Loads the modules registered to be loaded at that given time. + */ + public void loadModules(final ModuleLoadTime loadTime) { + if (loadedPriorities.contains(loadTime)) { + return; + } + + // Loads all internal modules first + modules.values().stream() + .filter(module -> module.getWhen() == loadTime) + .filter(ModuleWrapper::isEnabled) + .filter(module -> !module.isLoaded()) + .filter(ModuleWrapper::isInternal) + .forEach(module -> module.load(false)); + + // Then loads other modules + modules.values().stream() + .filter(module -> module.getWhen() == loadTime) + .filter(ModuleWrapper::isEnabled) + .filter(module -> !module.isLoaded()) + .filter(module -> !module.isInternal()) + .forEach(module -> module.load(false)); + + loadedPriorities.add(loadTime); + + collectCommandsFromModules(); + + Bukkit.getPluginManager().callEvent(new AllModulesLoadedEvent(loadTime)); + } + + /** + * Checks if the given load time was already loaded. + * + * @param loadTime The load time. + * @return {@code true} if loaded. + */ + public boolean isLoaded(final ModuleLoadTime loadTime) { + return loadedPriorities.contains(loadTime); + } + + /** + * Checks if the given module is loaded. + * + * @param module The module's class. + * @return {@code true} if loaded. + */ + public boolean isLoaded(final Class<? extends QSGModule> module) { + final ModuleWrapper wrapper = modules.get(module); + + return wrapper != null && wrapper.isLoaded(); + } + + @SuppressWarnings("unchecked") + private void collectCommandsFromModules() { + Commands.register("uh", modules.values().stream() + .filter(ModuleWrapper::isLoaded) + .map(module -> module.get().getCommands()) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .toArray(Class[]::new)); + + final Map<String, Class<? extends Command>> commandAliases = modules.values().stream() + .filter(ModuleWrapper::isLoaded) + .map(module -> module.get().getCommandsAliases()) + .filter(Objects::nonNull) + .flatMap(commandsAliases -> commandsAliases.entrySet().stream()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a)); + + // As they are not registered in the plugin.yml, for each command, we have to force-register + // the name manually. + + final Map<org.bukkit.command.Command, Class<? extends Command>> pluginCommands = new HashMap<>(); + final Set<String> registered = new HashSet<>(); + + try { + final Constructor<PluginCommand> pluginCommandConstructor = + PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); + pluginCommandConstructor.setAccessible(true); + + for (final Map.Entry<String, Class<? extends Command>> commandAlias : commandAliases.entrySet()) { + try { + pluginCommands + .put(pluginCommandConstructor.newInstance(commandAlias.getKey(), QuartzLib.getPlugin()), + commandAlias.getValue()); + registered.add(commandAlias.getKey()); + } + catch (InstantiationException | InvocationTargetException | IllegalAccessException e) { + PluginLogger + .error("Unable to register plugin command for {0}, is this version supported by UHCReloaded?", + e, commandAlias); + } + } + + try { + final CommandMap commandMap = (CommandMap) Reflection.getFieldValue(Bukkit.getServer(), "commandMap"); + + String mutPrefix = QSG.get().getDescription().getPrefix(); + if (mutPrefix == null) { + mutPrefix = QSG.get().getDescription().getName().toLowerCase(); + } + + final String prefix = mutPrefix; + + pluginCommands.forEach((pluginCommand, commandClass) -> + { + if (commandMap.register(prefix, pluginCommand)) { + PluginLogger.info( + "Hot-registered new command /{0} for class “{1}”.", + pluginCommand.getName(), + commandClass.getName().replace("eu.carrade.amaury.UHCReloaded.", "...") + ); + } + }); + } + catch (NoSuchFieldException | IllegalAccessException e) { + PluginLogger + .error("Unable to retrieve Bukkit's command map, is this version supported by UHCReloaded?", e); + } + } + catch (NoSuchMethodException | SecurityException e) { + PluginLogger + .error("Unable to register plugin commands: unable to retrieve PluginCommand's constructor. Is this version supported by UHCReloaded?", + e); + } + + // Now that all commands are registered into Bukkit, we can register them into zLib. + + commandAliases.forEach((name, klass) -> + { + // Bukkit registration failed? + if (!registered.contains(name)) { + return; + } + + Commands.registerShortcut("uh", klass, name); + }); + } + + + @EventHandler + public void onModuleLoaded(final ModuleLoadedEvent ev) { + PluginLogger.info("Module {0} loaded.", ev.getModule().getName()); + + if (ev.isLoadedLate()) { + // If loaded late, we may have to re-register the module's commands. + collectCommandsFromModules(); + } + } + + @EventHandler + public void onModuleUnloaded(final ModuleUnloadedEvent ev) { + PluginLogger.info("Module {0} unloaded.", ev.getModule().getName()); + + // We remove commands if needed when a module is unloaded, + // as it will be unable to handle them properly (the module + // instance being null). + collectCommandsFromModules(); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/QSGModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/QSGModule.java new file mode 100644 index 0000000..fc653c9 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/QSGModule.java @@ -0,0 +1,106 @@ +/* + * 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.quartzsurvivalgames.core; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.scoreboard.Sidebar; +import fr.zcraft.quartzlib.core.QuartzComponent; +import java.util.List; +import java.util.Map; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; + + +public abstract class QSGModule extends QuartzComponent implements Listener { + protected ModuleLogger logger; + + public QSGModule() { + logger = new ModuleLogger(getClass()); + } + + /** + * Called only when the module is enabled late, i.e. not when configured in + * the {@link ModuleInfo}. This happens for modules loaded manually by the + * players, if the module allows such late load. + * <p> + * This method will not be called for normal loads following the module info. + * <p> + * It will be called after {@link #onEnable()}. + */ + public void onLateEnable() { + } + + /** + * Use this method to register sub-commands into the /uh command. + * + * @return A list of command classes to register. + */ + public List<Class<? extends Command>> getCommands() { + return null; + } + + /** + * Use this method to register new commands aliases. + * + * @return The command aliases to add, map from the alias to the command class. + */ + public Map<String, Class<? extends Command>> getCommandsAliases() { + return null; + } + + /** + * This method will be called before calling {@link #injectIntoSidebar(Player, SidebarInjector)} so you can + * prepare and cache lines shared between all players. + * <p> + * Be careful as this method will be called every ten ticks. + * + * @see Sidebar#preRender() + */ + public void prepareInjectionIntoSidebar() { + } + + /** + * Use this method to inject content into the game's sidebar. + * <p> + * Be careful as this method will be called every ten ticks for each player. + * + * @param injector The injector will allows you to inject content in specific parts of the sidebar. + */ + public void injectIntoSidebar(final Player player, final SidebarInjector injector) { + } + + public ModuleLogger log() { + return logger; + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/AllModulesLoadedEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/AllModulesLoadedEvent.java new file mode 100644 index 0000000..1ec8f6e --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/AllModulesLoadedEvent.java @@ -0,0 +1,69 @@ +/* + * 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.quartzsurvivalgames.core.events; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + + +/** + * Fired when all modules registered in the config are loaded (both at startup and post-world). + */ +public class AllModulesLoadedEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + private final ModuleLoadTime loadTime; + + public AllModulesLoadedEvent(ModuleLoadTime loadTime) { + this.loadTime = loadTime; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + /** + * This event is launched for each batch of modules load. This represents the batch. + * + * @return the moment when these modules were all loaded. + */ + public ModuleLoadTime getLoadTime() { + return loadTime; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/ModuleDisabledEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/ModuleDisabledEvent.java new file mode 100644 index 0000000..8644f3f --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/ModuleDisabledEvent.java @@ -0,0 +1,71 @@ +/* + * 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.quartzsurvivalgames.core.events; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleWrapper; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + + +/** + * Fired after a module was disabled. + * <p> + * The module can be loaded at this point. If so, it will be unloaded soon after + * this event was called. + */ +public class ModuleDisabledEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + private final ModuleWrapper module; + + + public ModuleDisabledEvent(final ModuleWrapper module) { + this.module = module; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + /** + * @return the unloaded module. + */ + public ModuleWrapper getModule() { + return module; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/ModuleEnabledEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/ModuleEnabledEvent.java new file mode 100644 index 0000000..79bcbf5 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/ModuleEnabledEvent.java @@ -0,0 +1,69 @@ +/* + * 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.quartzsurvivalgames.core.events; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleWrapper; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + + +/** + * Fired after a module was enabled. + * This does not implies that the module is loaded. + */ +public class ModuleEnabledEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + private final ModuleWrapper module; + + + public ModuleEnabledEvent(final ModuleWrapper module) { + this.module = module; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + /** + * @return the enabled module. + */ + public ModuleWrapper getModule() { + return module; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/events/UHGameEndsEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/ModuleLoadedEvent.java similarity index 66% rename from src/main/java/eu/carrade/amaury/UHCReloaded/events/UHGameEndsEvent.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/ModuleLoadedEvent.java index 1988d69..b240dc2 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/events/UHGameEndsEvent.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/ModuleLoadedEvent.java @@ -30,64 +30,53 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.events; +package eu.carrade.amaury.quartzsurvivalgames.core.events; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import org.bukkit.event.Cancellable; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleWrapper; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; -public class UHGameEndsEvent extends Event implements Cancellable -{ - private UHTeam winner; - private boolean cancelled = false; +/** + * Fired after a module was loaded. + */ +public class ModuleLoadedEvent extends Event { + private static final HandlerList handlers = new HandlerList(); - public UHGameEndsEvent(UHTeam winner) - { - this.winner = winner; - } + private final ModuleWrapper module; + private final boolean loadedLate; - /** - * Returns the last team alive. - * - * @return The team. - */ - public UHTeam getWinnerTeam() - { - return winner; + + public ModuleLoadedEvent(final ModuleWrapper module) { + this(module, false); } + public ModuleLoadedEvent(final ModuleWrapper module, boolean loadedLate) { + this.module = module; + this.loadedLate = loadedLate; + } - @Override - public boolean isCancelled() - { - return cancelled; + public static HandlerList getHandlerList() { + return handlers; } /** - * Cancels the game ends. If cancelled, the end message / effects will not be broadcasted. - * - * @param cancelled {@code true} to cancel. + * @return the loaded module. */ - @Override - public void setCancelled(boolean cancelled) - { - this.cancelled = cancelled; + public ModuleWrapper getModule() { + return module; } - - - private static final HandlerList handlers = new HandlerList(); - - @Override - public HandlerList getHandlers() - { - return handlers; + /** + * @return {@code true} if the module is not loaded when specified in its + * {@link eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo properties}. + */ + public boolean isLoadedLate() { + return loadedLate; } - public static HandlerList getHandlerList() - { + @Override + public HandlerList getHandlers() { return handlers; } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/ModuleUnloadedEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/ModuleUnloadedEvent.java new file mode 100644 index 0000000..8d0eae0 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/core/events/ModuleUnloadedEvent.java @@ -0,0 +1,73 @@ +/* + * 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.quartzsurvivalgames.core.events; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleWrapper; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + + +/** + * Fired after a module was unloaded. + * <p> + * When this event is called, the embed instance is dying, unregistered from all + * events managers and soon-to-be-deleted. At the time the event is called, you + * can still get the instance using {@link ModuleWrapper#get()}, but don't try + * that on a delayed task as the instance will no longer be available. + */ +public class ModuleUnloadedEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + private final ModuleWrapper module; + + + public ModuleUnloadedEvent(final ModuleWrapper module) { + this.module = module; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + /** + * @return the unloaded module. + */ + public ModuleWrapper getModule() { + return module; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/BorderModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/BorderModule.java new file mode 100644 index 0000000..7e43f6d --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/BorderModule.java @@ -0,0 +1,346 @@ +/* + * 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.quartzsurvivalgames.modules.core.border; + +import eu.carrade.amaury.quartzsurvivalgames.QuartzSurvivalGames; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.commands.BorderCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.events.BorderChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.worldborders.WorldBorder; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import fr.zcraft.quartzlib.tools.text.Titles; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + + +@ModuleInfo( + name = "Border", + description = "Manages the border size and reduction.", + category = ModuleCategory.CORE, + icon = Material.BIRCH_FENCE, + settings = Config.class, + can_be_unloaded = false, + internal = true +) +public class BorderModule extends QSGModule { + /** + * The lines in the sidebar, calculated once for every player. Caching purposes. + */ + private final List<String> sidebar = new ArrayList<>(); + private MapShape mapShape = null; + private WorldBorder border = null; + + @Override + public void onEnable() { + mapShape = Config.SHAPE.get(); + + final World world = QuartzSurvivalGames.get().getWorld(World.Environment.NORMAL); + + border = WorldBorder.getInstance(world, Config.MOTOR.get(), mapShape); + + border.setShape(mapShape); + border.setCenter(world.getSpawnLocation()); + border.setDiameter(Config.SIZE.get()); + + border.init(); + + log().info("Using {0} to set the world border.", border.getClass().getSimpleName()); + } + + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(BorderCommand.class); + } + + @Override + public void prepareInjectionIntoSidebar() { + if (QSG.module(GameModule.class).currentPhaseBefore(GamePhase.IN_GAME)) { + return; + } + + sidebar.clear(); + + if (Config.SIDEBAR.DISPLAYED.get()) { + /// Title of the border section in the sidebar + sidebar.add(I.t("{blue}{bold}Border")); + + int diameter = (int) Math.ceil(border.getDiameter()); + + if (Config.SIDEBAR.DISPLAY_DIAMETER.get() || border.getShape() == MapShape.CIRCULAR) { + if (border.getShape() == MapShape.SQUARED) + /// Border diameter for a squared map in the sidebar + { + sidebar.add(I.tn("{white}{0} block wide", "{white}{0} blocks wide", diameter, diameter)); + } else + /// Border diameter for a circular map in the sidebar + { + sidebar.add(I.tn("{gray}Diameter: {white}{0} block", "{gray}Diameter: {white}{0} blocks", diameter, + diameter)); + } + } else { + Location center = border.getCenter(); + int radius = (int) Math.ceil(diameter / 2d); + + int minX = center.getBlockX() - radius; + int maxX = center.getBlockX() + radius; + int minZ = center.getBlockZ() - radius; + int maxZ = center.getBlockZ() + radius; + + // Same min & max, we can display both at once + if (minX == minZ && maxX == maxZ) { + /// Min & max coordinates in the sidebar, to locate the border. Ex: "-500 +500". {0} = minimal coord, {1} = maximal coord. + sidebar.add(I.t("{white}{0} {1}", QSGUtils.integerToStringWithSign(minX), + QSGUtils.integerToStringWithSign(maxZ))); + } else { + /// Min & max X coordinates in the sidebar, to locate the border. Ex: "X: -500 +500". {0} = minimal coord, {1} = maximal coord. + sidebar.add(I.t("{gray}X: {white}{0} {1}", QSGUtils.integerToStringWithSign(minX), + QSGUtils.integerToStringWithSign(maxX))); + /// Min & max Z coordinates in the sidebar, to locate the border. Ex: "Z: -500 +500". {0} = minimal coord, {1} = maximal coord. + sidebar.add(I.t("{gray}Z: {white}{0} {1}", QSGUtils.integerToStringWithSign(minZ), + QSGUtils.integerToStringWithSign(maxZ))); + } + } + } + } + + @Override + public void injectIntoSidebar(Player player, SidebarInjector injector) { + if (QSG.module(GameModule.class).currentPhaseBefore(GamePhase.IN_GAME) || sidebar.isEmpty()) { + return; + } + injector.injectLines(SidebarInjector.SidebarPriority.MIDDLE_BOTTOM, true, sidebar); + } + + /** + * Returns the current shape of the map. + * + * @return The shape. + */ + public MapShape getMapShape() { + return mapShape; + } + + /** + * Sets the shape of the map. Updates the WorldBorder too. + * + * @param shape The shape. + */ + public void setMapShape(MapShape shape) { + this.mapShape = shape; + border.setShape(shape); + } + + /** + * @return The WorldBorder proxy to set the border in-game. + */ + public WorldBorder getBorderProxy() { + return border; + } + + /** + * Checks if a given location is inside the border with the given diameter. + * The check is performed for a circular or squared border, following the configuration. + * + * @param location The location to check. + * @param diameter The diameter of the checked border. + * @return {@code true} if inside. + */ + public boolean isInsideBorder(Location location, double diameter) { + // The nether/end are not limited. + return !location.getWorld().getEnvironment().equals(World.Environment.NORMAL) || + mapShape.getShape().isInsideBorder(location, diameter, location.getWorld().getSpawnLocation()); + } + + /** + * Checks if a given location is inside the border with the current diameter. + * The check is performed for a circular or squared border, following the configuration. + * + * @param location The location to check. + * @return {@code true} if inside. + */ + public boolean isInsideBorder(Location location) { + return this.isInsideBorder(location, getCurrentBorderDiameter()); + } + + /** + * Returns the distance from the location to the border, if the location is outside this border. + * If it is inside, or in another world, returns 0. + * + * @param location The location to check. + * @param diameter The diameter of the checked border. + * @return The distance, or 0 if the player is either inside the border or not in the world. + */ + public double getDistanceToBorder(Location location, double diameter) { + return mapShape.getShape().getDistanceToBorder(location, diameter, location.getWorld().getSpawnLocation()); + } + + + /** + * Returns a list of the players outside a border with the given diameter. + * The check is performed for a circular or squared border, following the configuration. + * + * @param diameter The diameter of the checked border. + * @return A list of players out of the given diameter. + */ + public Set<Player> getPlayersOutside(int diameter) { + return QSG.module(GameModule.class) + .getAliveConnectedPlayers().stream() + .filter(player -> !isInsideBorder(player.getLocation(), diameter)) + .collect(Collectors.toSet()); + } + + /** + * @return the current border diameter. + */ + public int getCurrentBorderDiameter() { + return (int) border.getDiameter(); + } + + /** + * Changes the current border diameter. + * This also reconfigures the used world border. + * <p> + * If WorldBorder is installed, all players out of this new border will be teleported inside the new one. + * Else, nothing will happens. + * + * @param diameter the new diameter. + */ + public void setCurrentBorderDiameter(int diameter) { + border.setDiameter(diameter); + Bukkit.getPluginManager().callEvent(new BorderChangedEvent(diameter)); + } + + /** + * Sends a list of the players outside the given border to the specified sender. + * + * @param to The player/console to send the check. + * @param diameter The diameter of the border to be checked. + */ + public void sendCheckMessage(final CommandSender to, final int diameter) { + final BorderModule borderModule = QSG.module(BorderModule.class); + final Set<Player> playersOutside = borderModule.getPlayersOutside(diameter); + + if (playersOutside.size() == 0) { + to.sendMessage(I.t("{cs}All players are inside the given border.")); + } else { + to.sendMessage( + I.t("{ci}There are {0} players outside the given border.", String.valueOf(playersOutside.size()))); + for (Player player : borderModule.getPlayersOutside(diameter)) { + double distance = borderModule.getDistanceToBorder(player.getLocation(), diameter); + if (distance > 150) { + to.sendMessage(I.t("{lightpurple} - {red}{0}{ci} (far away from the border)", player.getName())); + } else if (distance > 25) { + to.sendMessage(I.t("{lightpurple} - {yellow}{0}{ci} (close to the border)", player.getName())); + } else { + to.sendMessage(I.t("{lightpurple} - {green}{0}{ci} (very close to the border)", player.getName())); + } + } + } + } + + /** + * Schedules the automatic border reduction, if enabled in the configuration. + */ + private void scheduleBorderReduction() { + if (Config.SHRINKING.ENABLED.get()) { + RunTask.later(() -> { + if (QSG.module(GameModule.class).getPhase() != GamePhase.IN_GAME) { + return; + } + + final int secondsPerBlock = (int) Math.rint(Config.SHRINKING.SHRINKS_DURING.get().getSeconds() / + (border.getDiameter() - Config.SHRINKING.DIAMETER_AFTER_SHRINK.get())) * 2; + + border.setDiameter(Config.SHRINKING.DIAMETER_AFTER_SHRINK.get(), Config.SHRINKING.SHRINKS_DURING.get()); + + Titles.broadcastTitle(5, 30, 8, I.t("{red}Warning!"), I.t("{white}The border begins to shrink...")); + + Bukkit.broadcastMessage( + QSGUtils.prefixedMessage(I.t("Border"), I.t("{red}{bold}The border begins to shrink..."))); + Bukkit.broadcastMessage(QSGUtils.prefixedMessage(I.t("Border"), + I.t("{gray}It will shrink by one block every {0} second(s) until {1} blocks in diameter.", + secondsPerBlock, Config.SHRINKING.DIAMETER_AFTER_SHRINK.get()))); + }, Config.SHRINKING.STARTS_AFTER.get().getSeconds() * 20L); + + scheduleBorderReductionWarning(new TimeDelta(1, 0, 0)); + scheduleBorderReductionWarning(new TimeDelta(0, 30, 0)); + scheduleBorderReductionWarning(new TimeDelta(0, 10, 0)); + } + } + + private void scheduleBorderReductionWarning(final TimeDelta warnBefore) { + if (Config.SHRINKING.STARTS_AFTER.get().greaterThan(warnBefore.add(new TimeDelta(0, 5, 0)))) { + RunTask.later(() -> { + if (QSG.module(GameModule.class).getPhase() != GamePhase.IN_GAME) { + return; + } + + Bukkit.broadcastMessage(""); + Bukkit.broadcastMessage(QSGUtils.prefixedMessage(I.t("Border"), + I.tn("{red}The border will start to shrink in {0} minute...", + "{red}The border will start to shrink in {0} minutes...", + (int) (warnBefore.getSeconds() / 60)))); + Bukkit.broadcastMessage(""); + }, Config.SHRINKING.STARTS_AFTER.get().subtract(warnBefore).getSeconds() * 20L); + } + } + + @EventHandler + public void onGameStarts(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() != GamePhase.IN_GAME) { + return; + } + scheduleBorderReduction(); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/Config.java new file mode 100644 index 0000000..af4d4d3 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/Config.java @@ -0,0 +1,72 @@ +/* + * 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.quartzsurvivalgames.modules.core.border; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.section; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.worldborders.WorldBorder; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.configuration.ConfigurationSection; +import java.io.File; + + +public class Config extends ConfigurationInstance { + public static final ConfigurationItem<Integer> SIZE = item("size", 2000); + public static final ConfigurationItem<MapShape> SHAPE = item("shape", MapShape.SQUARED); + public static final ConfigurationItem<WorldBorder.WorldBorderMotor> MOTOR = + item("motor", WorldBorder.WorldBorderMotor.VANILLA); + public static final ConfigurationItem<Double> DAMAGES_BUFFER = item("damages-buffer", 5d); + public static final ConfigurationItem<Double> DAMAGES_AMOUNT = item("damages-amount", 0.2); + public static final ConfigurationItem<Integer> WARNING_DISTANCE = item("warning-distance", 5); + public static final ShrinkingSection SHRINKING = section("shrinking", ShrinkingSection.class); + static public final BorderSection SIDEBAR = section("sidebar", BorderSection.class); + + public Config(File file) { + super(file); + } + + static public class ShrinkingSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ENABLED = item("enabled", false); + public final ConfigurationItem<TimeDelta> STARTS_AFTER = item("starts-after", new TimeDelta(1, 30, 0)); + public final ConfigurationItem<TimeDelta> SHRINKS_DURING = item("shrinks-during", new TimeDelta(2, 0, 0)); + public final ConfigurationItem<Integer> DIAMETER_AFTER_SHRINK = item("diameter-after-shrink", 200); + } + + static public class BorderSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> DISPLAYED = item("displayed", true); + public final ConfigurationItem<Boolean> DISPLAY_DIAMETER = item("display-diameter", false); + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/categories/Category.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/MapShape.java similarity index 66% rename from src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/categories/Category.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/MapShape.java index 896d66b..7b58947 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/categories/Category.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/MapShape.java @@ -29,27 +29,36 @@ * 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.commands.commands.categories; -import fr.zcraft.zlib.components.i18n.I; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.border; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.shapes.CircularMapShape; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.shapes.MapShapeDescriptor; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.shapes.SquaredMapShape; -public enum Category -{ - GAME(I.t("{aqua}------ Game-related commands ------")), - BUGS(I.t("{aqua}------ Bugs-related commands ------")), - MISC(I.t("{aqua}------ Miscellaneous commands ------")); +public enum MapShape { + CIRCULAR(new CircularMapShape()), + SQUARED(new SquaredMapShape()), - private String title; + ; - Category(String title) - { - this.title = title; + + private final MapShapeDescriptor shape; + + /** + * @param shape The shape descriptor to use for border-checks. + */ + MapShape(MapShapeDescriptor shape) { + this.shape = shape; } - public String getTitle() - { - return title; + /** + * Returns the shape descriptor. + * + * @return The shape. + */ + public MapShapeDescriptor getShape() { + return shape; } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/commands/BorderCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/commands/BorderCommand.java new file mode 100644 index 0000000..db44e37 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/commands/BorderCommand.java @@ -0,0 +1,160 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.border.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.BorderModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.MapShape; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import org.bukkit.Bukkit; + + +@CommandInfo(name = "border", usageParameters = "[new diameter] [duration]", aliases = "b") +public class BorderCommand extends Command { + @Override + protected void run() throws CommandException { + final BorderModule border = QSG.module(BorderModule.class); + + // No arguments: displays current size + if (args.length == 0) { + if (border.getMapShape() == MapShape.CIRCULAR) { + sender.sendMessage(I.tn("{ci}The current diameter of the map is {0} block.", + "{ci}The current diameter of the map is {0} blocks.", border.getCurrentBorderDiameter())); + } else { + sender.sendMessage(I.t("{ci}The current map size is {0}×{0}.", border.getCurrentBorderDiameter())); + } + } else { + // /uh border <radius> + if (args.length == 1) { + try { + final int newDiameter = Integer.valueOf(args[0]); + + // Some players are outside + if (border.getPlayersOutside(newDiameter).size() != 0) { + sender.sendMessage( + I.t("{ce}Some players are outside the future border, so this operation was cancelled.")); + sender.sendMessage( + I.t("{ci}Use {cc}/uh border set {0} force{ci} to resize the border regardless to this point.", + args[0])); + + sender.sendMessage(I.t("{ce}WARNING: {ci}players out of the border will not be teleported!")); + + border.sendCheckMessage(sender, newDiameter); + } else { + border.setCurrentBorderDiameter(newDiameter); + + if (border.getMapShape() == MapShape.CIRCULAR) { + Bukkit.getServer().broadcastMessage( + I.tn("{lightpurple}The diameter of the map is now {0} block.", + "{lightpurple}The diameter of the map is now {0} blocks.", newDiameter)); + } else { + Bukkit.getServer().broadcastMessage( + I.t("{lightpurple}The size of the map is now {0}×{0}.", newDiameter)); + } + } + } + catch (NumberFormatException e) { + error(I.t("{ce}“{0}” is not a number...", args[0])); + } + } + + // /uh border <radius> force + else if (args.length == 2 && args[1].equalsIgnoreCase("force")) { + try { + final Integer newDiameter = Integer.valueOf(args[0]); + + border.setCurrentBorderDiameter(newDiameter); + + if (border.getMapShape() == MapShape.CIRCULAR) { + Bukkit.getServer().broadcastMessage( + I.tn("{lightpurple}The diameter of the map is now {0} block.", + "{lightpurple}The diameter of the map is now {0} blocks.", newDiameter)); + } else { + Bukkit.getServer() + .broadcastMessage(I.t("{lightpurple}The size of the map is now {0}×{0}.", newDiameter)); + } + } + catch (NumberFormatException e) { + error(I.t("{ce}“{0}” is not a number...", args[0])); + } + } + + // /uh border <radius> <duration> + else if (args.length == 2) { + if (!border.getBorderProxy().supportsProgressiveResize()) { + error(I.t("The border motor ({0}) does not supports progressive resizes.", + border.getBorderProxy().getClass().getSimpleName())); + } + + final Integer newDiameter; + final TimeDelta delta; + + try { + newDiameter = Integer.valueOf(args[0]); + } + catch (NumberFormatException e) { + error(I.t("{ce}“{0}” is not a number...", args[0])); + return; + } + + try { + delta = new TimeDelta(args[1]); + } + catch (IllegalArgumentException e) { + error(I.t("{ce}“{0}” is not a valid time delta... Accepted formats are mm, mm:ss or hh:mm:ss.", + args[1])); + return; + } + + border.getBorderProxy().setDiameter(newDiameter, delta); + + if (border.getMapShape() == MapShape.CIRCULAR) { + Bukkit.getServer().broadcastMessage( + I.tn("{lightpurple}The diameter of the map will be set to {0} block over {1}.", + "{lightpurple}The diameter of the map will be set to {0} blocks over {1}.", + newDiameter, newDiameter, delta)); + } else { + Bukkit.getServer().broadcastMessage( + I.t("{lightpurple}The size of the map will be set to {0}×{0} over {1}.", newDiameter, + delta)); + } + } + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/events/BorderChangedEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/events/BorderChangedEvent.java new file mode 100644 index 0000000..9cd6b57 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/events/BorderChangedEvent.java @@ -0,0 +1,61 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.border.events; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class BorderChangedEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + private final int newDiameter; + + public BorderChangedEvent(final int newDiameter) { + this.newDiameter = newDiameter; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + public int getNewDiameter() { + return newDiameter; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/shapes/CircularMapShape.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/shapes/CircularMapShape.java similarity index 90% rename from src/main/java/eu/carrade/amaury/UHCReloaded/borders/shapes/CircularMapShape.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/shapes/CircularMapShape.java index 2fa71e3..37fac6a 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/shapes/CircularMapShape.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/shapes/CircularMapShape.java @@ -29,26 +29,24 @@ * 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.borders.shapes; + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.border.shapes; import org.bukkit.Location; import org.bukkit.World; -public class CircularMapShape implements MapShapeDescriptor -{ +public class CircularMapShape implements MapShapeDescriptor { /** * Returns true if the given location is inside the map. * * @param location The location to check. * @param diameter The diameter of the map. * @param center The center of the map. - * * @return {@code true} if the given location is inside the map. */ @Override - public boolean isInsideBorder(final Location location, final Double diameter, final Location center) - { + public boolean isInsideBorder(final Location location, final Double diameter, final Location center) { final Location centerRef = center.clone(); centerRef.setY(location.getY()); @@ -61,21 +59,17 @@ public boolean isInsideBorder(final Location location, final Double diameter, fi * @param location The distance will be calculated between this location and the closest point of the border. * @param diameter The diameter of the border. * @param center The center of the border. - * * @return The distance between the given {@code location} and the closest point of the border.<br /> * {@code -1} if the location is inside the border. */ @Override - public double getDistanceToBorder(final Location location, final Double diameter, final Location center) - { + public double getDistanceToBorder(final Location location, final Double diameter, final Location center) { // The nether/end are not limited. - if (!location.getWorld().getEnvironment().equals(World.Environment.NORMAL)) - { + if (!location.getWorld().getEnvironment().equals(World.Environment.NORMAL)) { return -1; } - if (isInsideBorder(location, diameter, center)) - { + if (isInsideBorder(location, diameter, center)) { return -1; } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/shapes/MapShapeDescriptor.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/shapes/MapShapeDescriptor.java similarity index 93% rename from src/main/java/eu/carrade/amaury/UHCReloaded/borders/shapes/MapShapeDescriptor.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/shapes/MapShapeDescriptor.java index c2590c5..144d2b2 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/shapes/MapShapeDescriptor.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/shapes/MapShapeDescriptor.java @@ -29,7 +29,8 @@ * 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.borders.shapes; + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.border.shapes; import org.bukkit.Location; @@ -37,15 +38,13 @@ /** * Represents a shape of the map. */ -public interface MapShapeDescriptor -{ +public interface MapShapeDescriptor { /** * Returns true if the given location is inside the map. * * @param location The location to check. * @param diameter The diameter of the map. * @param center The center of the map. - * * @return {@code true} if the given location is inside the map. */ boolean isInsideBorder(final Location location, final Double diameter, final Location center); @@ -56,9 +55,8 @@ public interface MapShapeDescriptor * @param location The distance will be calculated between this location and the closest point of the border. * @param diameter The diameter of the border. * @param center The center of the border. - * * @return The distance between the given {@code location} and the closest point of the border.<br /> - * {@code -1} if the location is inside the border. + * {@code -1} if the location is inside the border. */ double getDistanceToBorder(final Location location, final Double diameter, final Location center); } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/shapes/SquaredMapShape.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/shapes/SquaredMapShape.java similarity index 74% rename from src/main/java/eu/carrade/amaury/UHCReloaded/borders/shapes/SquaredMapShape.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/shapes/SquaredMapShape.java index a46b5e4..7763ea4 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/shapes/SquaredMapShape.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/shapes/SquaredMapShape.java @@ -29,26 +29,24 @@ * 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.borders.shapes; + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.border.shapes; import org.bukkit.Location; import org.bukkit.World; -public class SquaredMapShape implements MapShapeDescriptor -{ +public class SquaredMapShape implements MapShapeDescriptor { /** * Returns true if the given location is inside the map. * * @param location The location to check. * @param diameter The diameter of the map. * @param center The center of the map. - * * @return {@code true} if the given location is inside the map. */ @Override - public boolean isInsideBorder(final Location location, final Double diameter, final Location center) - { + public boolean isInsideBorder(final Location location, final Double diameter, final Location center) { final Integer halfMapSize = (int) Math.floor(diameter / 2); final Integer x = location.getBlockX(); final Integer z = location.getBlockZ(); @@ -67,21 +65,17 @@ public boolean isInsideBorder(final Location location, final Double diameter, fi * @param location The distance will be calculated between this location and the closest point of the border. * @param diameter The diameter of the border. * @param center The center of the border. - * * @return The distance between the given {@code location} and the closest point of the border.<br /> * {@code -1} if the location is inside the border. */ @Override - public double getDistanceToBorder(final Location location, final Double diameter, final Location center) - { + public double getDistanceToBorder(final Location location, final Double diameter, final Location center) { // The nether/end are not limited. - if (!location.getWorld().getEnvironment().equals(World.Environment.NORMAL)) - { + if (!location.getWorld().getEnvironment().equals(World.Environment.NORMAL)) { return -1; } - if (isInsideBorder(location, diameter, center)) - { + if (isInsideBorder(location, diameter, center)) { return -1; } @@ -97,37 +91,32 @@ public double getDistanceToBorder(final Location location, final Double diameter if (x > limitXSup && z < limitZSup && z > limitZInf) // East of the border { return Math.abs(x - limitXSup); - } - else if (x < limitXInf && z < limitZSup && z > limitZInf) // West of the border + } else if (x < limitXInf && z < limitZSup && z > limitZInf) // West of the border { return Math.abs(x - limitXInf); - } - else if (z > limitZSup && x < limitXSup && x > limitXInf) // South of the border + } else if (z > limitZSup && x < limitXSup && x > limitXInf) // South of the border { return Math.abs(z - limitZSup); - } - else if (z < limitZInf && x < limitXSup && x > limitXInf) // North of the border + } else if (z < limitZInf && x < limitXSup && x > limitXInf) // North of the border { return Math.abs(z - limitZInf); - } - else if (x > limitXSup && z < limitZInf) // North-East + } else if (x > limitXSup && z < limitZInf) // North-East { - return (int) location.distance(new Location(location.getWorld(), limitXSup, location.getBlockY(), limitZInf)); - } - else if (x > limitXSup && z > limitZSup) // South-East + return (int) location + .distance(new Location(location.getWorld(), limitXSup, location.getBlockY(), limitZInf)); + } else if (x > limitXSup && z > limitZSup) // South-East { - return (int) location.distance(new Location(location.getWorld(), limitXSup, location.getBlockY(), limitZSup)); - } - else if (x < limitXInf && z > limitZSup) // South-West + return (int) location + .distance(new Location(location.getWorld(), limitXSup, location.getBlockY(), limitZSup)); + } else if (x < limitXInf && z > limitZSup) // South-West { - return (int) location.distance(new Location(location.getWorld(), limitXInf, location.getBlockY(), limitZSup)); - } - else if (x < limitXInf && z < limitZInf) // North-West - { - return (int) location.distance(new Location(location.getWorld(), limitXInf, location.getBlockY(), limitZInf)); - } - else + return (int) location + .distance(new Location(location.getWorld(), limitXInf, location.getBlockY(), limitZSup)); + } else if (x < limitXInf && z < limitZInf) // North-West { + return (int) location + .distance(new Location(location.getWorld(), limitXInf, location.getBlockY(), limitZInf)); + } else { return -1; // Should never happen. } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/worldborders/FakeWorldBorder.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/worldborders/FakeWorldBorder.java similarity index 66% rename from src/main/java/eu/carrade/amaury/UHCReloaded/borders/worldborders/FakeWorldBorder.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/worldborders/FakeWorldBorder.java index a93e212..d7759a9 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/worldborders/FakeWorldBorder.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/worldborders/FakeWorldBorder.java @@ -29,9 +29,10 @@ * 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.borders.worldborders; -import eu.carrade.amaury.UHCReloaded.borders.MapShape; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.border.worldborders; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.MapShape; import org.bukkit.Location; import org.bukkit.World; @@ -41,96 +42,100 @@ * * <p>Used when a circular world border is requested without the WorldBorder plugin.</p> */ -public class FakeWorldBorder extends WorldBorder -{ +public class FakeWorldBorder extends WorldBorder { private final World world; private Location center; private Double diameter; private MapShape shape; - public FakeWorldBorder(World world) - { + public FakeWorldBorder(final World world) { this.world = world; - - init(); } @Override - public World getWorld() - { + public World getWorld() { return world; } @Override - public double getDiameter() - { + public double getDiameter() { return diameter; } @Override - public void setDiameter(double diameter) - { + public void setDiameter(final double diameter) { this.diameter = diameter; } @Override - public void setDiameter(double diameter, long time) - { + public void setDiameter(final double diameter, final long time) { this.diameter = diameter; } @Override - public Location getCenter() - { + public Location getCenter() { return center; } @Override - public void setCenter(double x, double z) - { - this.center = new Location(world, x, 0, z); + public void setCenter(final Location center) { + setCenter(center.getX(), center.getZ()); } @Override - public void setCenter(Location center) - { - setCenter(center.getX(), center.getZ()); + public void setCenter(final double x, final double z) { + this.center = new Location(world, x, 0, z); } @Override - public double getDamageBuffer() { return 0; } + public double getDamageBuffer() { + return 0; + } @Override - public void setDamageBuffer(double distance) {} + public void setDamageBuffer(final double distance) { + } @Override - public double getDamageAmount() { return 0; } + public double getDamageAmount() { + return 0; + } @Override - public void setDamageAmount(double damageAmount) {} + public void setDamageAmount(final double damageAmount) { + } @Override - public int getWarningTime() { return 0; } + public int getWarningTime() { + return 0; + } @Override - public void setWarningTime(int seconds) {} + public void setWarningTime(final int seconds) { + } @Override - public int getWarningDistance() { return 0; } + public int getWarningDistance() { + return 0; + } @Override - public void setWarningDistance(int blocks) {} + public void setWarningDistance(final int blocks) { + } @Override - public MapShape getShape() - { + public MapShape getShape() { return shape; } @Override - public void setShape(MapShape shape) - { + public void setShape(final MapShape shape) { this.shape = shape; } + + @Override + public boolean supportsProgressiveResize() { + return false; + } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/worldborders/VanillaWorldBorder.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/worldborders/VanillaWorldBorder.java similarity index 67% rename from src/main/java/eu/carrade/amaury/UHCReloaded/borders/worldborders/VanillaWorldBorder.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/worldborders/VanillaWorldBorder.java index 5ca69e4..d9c0d63 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/worldborders/VanillaWorldBorder.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/worldborders/VanillaWorldBorder.java @@ -29,10 +29,11 @@ * 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.borders.worldborders; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.borders.MapShape; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.border.worldborders; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.Config; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.MapShape; import org.bukkit.Location; import org.bukkit.World; @@ -43,124 +44,108 @@ * <p>This border is always squared, so {@link #setShape(MapShape)} does nothing and {@link * #getShape()} always returns {@link MapShape#SQUARED}.</p> */ -public class VanillaWorldBorder extends WorldBorder -{ +public class VanillaWorldBorder extends WorldBorder { private final World world; private final org.bukkit.WorldBorder border; - public VanillaWorldBorder(World world) - { + public VanillaWorldBorder(final World world) { this.world = world; this.border = world.getWorldBorder(); } @Override - public void init() - { - if (UHConfig.MAP.BORDER.isDefined()) - { - setDamageBuffer(UHConfig.MAP.BORDER.DAMAGES_BUFFER.get()); - setDamageAmount(UHConfig.MAP.BORDER.DAMAGES_AMOUNT.get()); - setWarningDistance(UHConfig.MAP.BORDER.WARNING_DISTANCE.get()); - } + public void init() { + setDamageBuffer(Config.DAMAGES_BUFFER.get()); + setDamageAmount(Config.DAMAGES_AMOUNT.get()); + setWarningDistance(Config.WARNING_DISTANCE.get()); } @Override - public World getWorld() - { + public World getWorld() { return world; } @Override - public double getDiameter() - { + public double getDiameter() { return border.getSize(); } @Override - public void setDiameter(double diameter) - { + public void setDiameter(final double diameter) { border.setSize(diameter); } @Override - public void setDiameter(double diameter, long time) - { + public void setDiameter(final double diameter, final long time) { border.setSize(diameter, time); } @Override - public Location getCenter() - { + public Location getCenter() { return border.getCenter(); } @Override - public void setCenter(double x, double z) - { - border.setCenter(x, z); + public void setCenter(final Location center) { + border.setCenter(center); } @Override - public void setCenter(Location center) - { - border.setCenter(center); + public void setCenter(final double x, final double z) { + border.setCenter(x, z); } @Override - public double getDamageBuffer() - { + public double getDamageBuffer() { return border.getDamageBuffer(); } @Override - public void setDamageBuffer(double distance) - { + public void setDamageBuffer(final double distance) { border.setDamageBuffer(distance); } @Override - public double getDamageAmount() - { + public double getDamageAmount() { return border.getDamageAmount(); } @Override - public void setDamageAmount(double damageAmount) - { + public void setDamageAmount(final double damageAmount) { border.setDamageAmount(damageAmount); } @Override - public int getWarningTime() - { + public int getWarningTime() { return border.getWarningTime(); } @Override - public void setWarningTime(int seconds) - { + public void setWarningTime(final int seconds) { border.setWarningTime(seconds); } @Override - public int getWarningDistance() - { + public int getWarningDistance() { return border.getWarningDistance(); } @Override - public void setWarningDistance(int blocks) - { + public void setWarningDistance(final int blocks) { border.setWarningDistance(blocks); } @Override - public MapShape getShape() - { + public MapShape getShape() { return MapShape.SQUARED; } @Override - public void setShape(MapShape shape) {} + public void setShape(final MapShape shape) { + } + + @Override + public boolean supportsProgressiveResize() { + return true; + } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/worldborders/WorldBorder.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/worldborders/WorldBorder.java similarity index 69% rename from src/main/java/eu/carrade/amaury/UHCReloaded/borders/worldborders/WorldBorder.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/worldborders/WorldBorder.java index 3284b79..a7e511f 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/worldborders/WorldBorder.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/border/worldborders/WorldBorder.java @@ -29,10 +29,12 @@ * 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.borders.worldborders; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.borders.MapShape; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.border.worldborders; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.MapShape; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import fr.zcraft.quartzlib.tools.PluginLogger; import org.bukkit.Location; import org.bukkit.World; @@ -41,14 +43,32 @@ * An abstraction layer to manipulate world borders, typically the vanilla world border or * the Brettflan one. */ -public abstract class WorldBorder -{ +public abstract class WorldBorder { /** - * Initializes the world border configuration, if needed. + * Returns a new instance of a WorldBorder proxy using the requested types. * + * @param motor The border motor; can be "vanilla" or "brettflan" (from config). + * @param shape The border shape. + * @return An instance of a WorldBorder proxy. + */ + public static WorldBorder getInstance(final World world, final WorldBorderMotor motor, final MapShape shape) { + // For circular shapes, the vanilla motor cannot be used. + // Without the WorldBorder plugin, a fake world border is used (i.e., no border control). + if (shape == MapShape.CIRCULAR) { + PluginLogger.error("Circular world borders are no longer supported due to Brettflan world border plugin being abandoned."); + return new FakeWorldBorder(world); + } else { + return new VanillaWorldBorder(world); + } + } + + /** + * Initializes the world border configuration, if needed. + * <p> * This method does not initializes the shape, size, etc. */ - public void init() {} + public void init() { + } /** * @return The world bordered by this world border. @@ -63,31 +83,39 @@ public void init() {} /** * @param diameter The new diameter of the border. */ - public abstract void setDiameter(double diameter); + public abstract void setDiameter(final double diameter); /** * @param diameter The new diameter of the border. - * @param time The ticks used to change the size from the old size to the new one. + * @param time The seconds used to change the size from the old size to the new one. */ - public abstract void setDiameter(double diameter, long time); + public abstract void setDiameter(final double diameter, final long time); + + /** + * @param diameter The new diameter of the border. + * @param time The seconds used to change the size from the old size to the new one. + */ + public void setDiameter(final double diameter, final TimeDelta time) { + setDiameter(diameter, time.getSeconds()); + } /** * @return The center of the border. */ public abstract Location getCenter(); + /** + * @param center The new center of the border. + */ + public abstract void setCenter(final Location center); + /** * Sets the center of the border. * * @param x The x coordinate of the new center. * @param z The z coordinate of the new center. */ - public abstract void setCenter(double x, double z); - - /** - * @param center The new center of the border. - */ - public abstract void setCenter(Location center); + public abstract void setCenter(final double x, final double z); /** * @return the amount of blocks a player may safely be outside the border before taking damage. @@ -98,7 +126,7 @@ public void init() {} * @param distance the amount of blocks a player may safely be outside the border before taking * damage. */ - public abstract void setDamageBuffer(double distance); + public abstract void setDamageBuffer(final double distance); /** * @return the amount of damage a player takes when outside the border plus the border buffer. @@ -109,7 +137,7 @@ public void init() {} * @param damageAmount the amount of damage a player takes when outside the border plus the * border buffer. */ - public abstract void setDamageAmount(double damageAmount); + public abstract void setDamageAmount(final double damageAmount); /** * @return the warning time that causes the screen to be tinted red when a contracting border @@ -121,7 +149,7 @@ public void init() {} * @param seconds the warning time that causes the screen to be tinted red when a contracting * border will reach the player within the specified time. */ - public abstract void setWarningTime(int seconds); + public abstract void setWarningTime(final int seconds); /** * @return the warning distance that causes the screen to be tinted red when the player is @@ -133,7 +161,7 @@ public void init() {} * @param blocks the warning distance that causes the screen to be tinted red when the player is * within the specified number of blocks from the border. */ - public abstract void setWarningDistance(int blocks); + public abstract void setWarningDistance(final int blocks); /** * @return The current border shape. @@ -143,42 +171,17 @@ public void init() {} /** * @param shape the new border shape. */ - public abstract void setShape(MapShape shape); - + public abstract void setShape(final MapShape shape); /** - * Returns a new instance of a WorldBorder proxy using the requested types. - * - * @param motor The border motor; can be "vanilla" or "brettflan" (from config). - * @param shape The border shape. - * - * @return An instance of a WorldBorder proxy. + * @return {@code true} if this border supports progressive resizes using {@link #setDiameter(double, long)}. */ - public static WorldBorder getInstance(World world, String motor, MapShape shape) - { - // For circular shapes, the vanilla motor cannot be used. - // Without the WorldBorder plugin, a fake world border is used (i.e., no border control). - if (shape == MapShape.CIRCULAR) - { - if (UHCReloaded.get().getWorldBorderIntegration().isWBIntegrationEnabled()) - { - return new BrettflanWorldBorder(world); - } - else - { - return new FakeWorldBorder(world); - } - } - else - { - if (motor.equalsIgnoreCase("vanilla") || !UHCReloaded.get().getWorldBorderIntegration().isWBIntegrationEnabled()) - { - return new VanillaWorldBorder(world); - } - else - { - return new BrettflanWorldBorder(world); - } - } + public abstract boolean supportsProgressiveResize(); + + public enum WorldBorderMotor { + /** + * Uses the vanilla world border (for squared borders only). + */ + VANILLA } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/Config.java new file mode 100644 index 0000000..50b8e76 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/Config.java @@ -0,0 +1,76 @@ +/* + * 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.quartzsurvivalgames.modules.core.game; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.section; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.configuration.ConfigurationSection; +import java.io.File; + + +public class Config extends ConfigurationInstance { + public static final ConfigurationItem<Integer> COUNTDOWN = item("countdown", 7); + public static final ConfigurationItem<Boolean> STARTUP_TITLE = item("startup-title", true); + public static final ConfigurationItem<Boolean> RANDOM_COLORS_IN_SOLO_GAMES = + item("random-color-in-solo-games", true); + public static final ConfigurationItem<Boolean> BROADCAST_PROGRESS = item("broadcast-progress", true); + public static final SlowSection SLOW = section("slow", SlowSection.class); + public static final BeginningSection BEGINNING = section("beginning", BeginningSection.class); + public static final SidebarSection SIDEBAR = section("sidebar", SidebarSection.class); + + public Config(File file) { + super(file); + } + + public static final class SlowSection extends ConfigurationSection { + public final ConfigurationItem<Long> DELAY_BETWEEN_TP = item("delay-between-teleportations", 3L); + } + + public static final class BeginningSection extends ConfigurationSection { + public final ConfigurationItem<TimeDelta> GRACE_PERIOD = item("grace-period", new TimeDelta(0, 0, 30)); + public final ConfigurationItem<Boolean> BROADCAST_GRACE_END = item("broadcast-grace-end", true); + + public final ConfigurationItem<TimeDelta> PEACE_PERIOD = item("peace-period", new TimeDelta(0, 1, 0)); + public final ConfigurationItem<TimeDelta> SURFACE_MOBS_FREE_PERIOD = + item("surface-mobs-free-period", new TimeDelta(0, 20, 0)); + } + + public static final class SidebarSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> PLAYERS = item("players", true); + public final ConfigurationItem<Boolean> TEAMS = item("teams", true); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/GameModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/GameModule.java new file mode 100644 index 0000000..2c28de9 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/GameModule.java @@ -0,0 +1,826 @@ +/* + * 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.quartzsurvivalgames.modules.core.game; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.commands.KillCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.commands.ResurrectCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.commands.StartCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.PlayerResurrectedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.TeamDeathEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start.AfterTeleportationPhaseEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start.BeforeTeleportationPhaseEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start.PlayerAboutToBeTeleportedToSpawnPointEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start.PlayerSpawnPointSelectedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start.PlayerTeleportedToSpawnPointEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.submanagers.GameBeginning; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.teleporter.TeleportationMode; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.teleporter.Teleporter; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.SpawnsModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.SpectatorsModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGSound; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.components.rawtext.RawText; +import fr.zcraft.quartzlib.core.QuartzLib; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import fr.zcraft.quartzlib.tools.text.ActionBar; +import fr.zcraft.quartzlib.tools.text.Titles; +import fr.zcraft.quartzteams.QuartzTeam; +import fr.zcraft.quartzteams.QuartzTeams; +import fr.zcraft.quartzteams.colors.TeamColor; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Queue; +import java.util.Random; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.permissions.ServerOperator; +import org.bukkit.scheduler.BukkitRunnable; + + +@ModuleInfo( + name = "Game", + description = "Manages the game execution and phases.", + category = ModuleCategory.CORE, + icon = Material.REDSTONE_BLOCK, + settings = Config.class, + internal = true, + can_be_unloaded = false +) +public class GameModule extends QSGModule implements Listener { + /** + * A list containing the currently alive players. + */ + private final Set<UUID> alivePlayers = new HashSet<>(); + /** + * A list containing the currently (cached) alive teams. + * Refreshed using the {@link #updateAliveTeams()} method. + */ + private final Set<QuartzTeam> aliveTeams = new HashSet<>(); + /** + * The current game phase (initialized to {@link GamePhase#WAIT} in the + * {@link #onEnable()} method). + */ + private GamePhase phase = null; + /** + * When the game ends, stores the last standing team. + */ + private QuartzTeam winner = null; + + /** + * {@code true} if there is teams in this game. + */ + private boolean teamsGame = false; + + /** + * {@code true} if the starting process should be slow (for small servers). + */ + private boolean slowMode = false; + + /** + * The teleportation process, to teleport teams as a group or apart. + */ + private TeleportationMode teleportationMode = TeleportationMode.NORMAL; + + /** + * The teleporter used, storing effective spawn points for each player, used + * if we need them after the startup process. + */ + private Teleporter teleporter = null; + + /** + * An internal lock to avoid someone starting the game if the teleportation process + * is still running. + */ + private boolean teleportationProcessLock = false; + + /** + * An internal lock used to avoid multiple starting countdowns at the same time. + */ + private boolean startingCountdownLock = false; + + /** + * An internal counter for the displayed teleportation progress in the action bar (x/y). + */ + private int teleportationProgress = 0; + + + @Override + protected void onEnable() { + setPhase(GamePhase.WAIT); + Bukkit.getOnlinePlayers().forEach(this::updatePlayerFlightOptions); + + QuartzLib.loadComponent(GameBeginning.class); + } + + @Override + public List<Class<? extends Command>> getCommands() { + return Arrays.asList( + StartCommand.class, + KillCommand.class, + ResurrectCommand.class + ); + } + + @Override + public void injectIntoSidebar(Player player, SidebarInjector injector) { + final List<String> topSidebar = new ArrayList<>(); + + if (Config.SIDEBAR.PLAYERS.get()) { + topSidebar.add(I.tn( + "{white}{0}{gray} player", "{white}{0}{gray} players", + phase == GamePhase.WAIT ? Bukkit.getOnlinePlayers().size() : alivePlayers.size() + )); + } + + if (Config.SIDEBAR.TEAMS.get() && teamsGame && phase != GamePhase.WAIT) { + topSidebar.add(I.tn("{white}{0}{gray} team", "{white}{0}{gray} teams", aliveTeams.size())); + } + + injector.injectLines(SidebarInjector.SidebarPriority.TOP, true, topSidebar); + + switch (phase) { + case WAIT: + injector.injectLines( + SidebarInjector.SidebarPriority.TOP, true, + I.t("{gray}Waiting for players...") + ); + break; + + case STARTING: + injector.injectLines( + SidebarInjector.SidebarPriority.TOP, true, + I.t("{gray}The game is starting..."), + I.t("{gray}Please wait.") + ); + break; + } + } + + public boolean isTeamsGame() { + return teamsGame; + } + + public Set<UUID> getAlivePlayersUUIDs() { + return Collections.unmodifiableSet(alivePlayers); + } + + public Set<OfflinePlayer> getAlivePlayers() { + return alivePlayers.stream().map(Bukkit::getOfflinePlayer).collect(Collectors.toSet()); + } + + public int countAlivePlayers() { + return alivePlayers.size(); + } + + public Set<Player> getAliveConnectedPlayers() { + return alivePlayers.stream().map(Bukkit::getPlayer).filter(Objects::nonNull).filter(Player::isOnline) + .collect(Collectors.toSet()); + } + + public Set<QuartzTeam> getAliveTeams() { + return Collections.unmodifiableSet(aliveTeams); + } + + public int countAliveTeams() { + return aliveTeams.size(); + } + + /** + * @return The game's winner, if any; null else. + */ + public QuartzTeam getWinner() { + return winner; + } + + public boolean isAlive(final OfflinePlayer player) { + return alivePlayers.contains(player.getUniqueId()); + } + + public boolean isAlive(final UUID playerID) { + return alivePlayers.contains(playerID); + } + + public boolean isAlive(final QuartzTeam team) { + return team.getPlayersUUID().stream().anyMatch(alivePlayers::contains); + } + + /** + * Kills a player. + * <p> + * This method calls an event. If the event is cancelled, the player is not + * killed. + * + * @param player The player to kill. + * @return {@code true} if the player was effectively killed (event not cancelled). + */ + public boolean kill(final OfflinePlayer player) { + return kill(player, null); + } + + /** + * Kills a player. Internal use for natural deaths. + * <p> + * This method calls an event. If the event is cancelled, the player is not + * killed. + * + * @param player The player to kill. + * @param ev The underlying death event. + * @return {@code true} if the player was effectively killed (event not cancelled). + */ + private boolean kill(final OfflinePlayer player, final PlayerDeathEvent ev) { + final AlivePlayerDeathEvent event = new AlivePlayerDeathEvent(player, ev); + Bukkit.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + alivePlayers.remove(player.getUniqueId()); + + updateAliveTeams(); + + // We check the player's team to see if there is players left inside. + if (teamsGame) { + final QuartzTeam team = QuartzTeams.get().getTeamForPlayer(player); + if (team != null && !aliveTeams.contains(team)) { + Bukkit.getPluginManager().callEvent(new TeamDeathEvent(team)); + } + } + + if (aliveTeams.size() <= 1) { + setPhase(GamePhase.END); + } + + return true; + } + + return false; + } + + /** + * Resurrects a player and puts it into the game (even if he/she never played + * before). + * + * @param player The player to resurrect. + * @return {@code true} if the player was effectively resurrected (i.e. not already alive). + */ + public boolean resurrect(final OfflinePlayer player) { + if (isAlive(player)) { + return false; + } + + log().info("Resurrecting player {0}", player.getName()); + + alivePlayers.add(player.getUniqueId()); + updateAliveTeams(); + + log().info("Resurrected. Alive players: {0}. Teams: {1}. Phase: {2}.", alivePlayers.size(), aliveTeams.size(), + phase); + + if (aliveTeams.size() > 1 && phase == GamePhase.END) { + setPhase(GamePhase.IN_GAME); + log().info("Going back to IN_GAME phase. Phase is now {0}.", phase); + } + + Bukkit.getPluginManager().callEvent(new PlayerResurrectedEvent(player)); + + return true; + } + + /** + * @return the current phase of the game. + */ + public GamePhase getPhase() { + return phase; + } + + /** + * Changes the phase of the game. + * <p> + * The phase must be a phase after the current one, with two exceptions: + * the phase order can be STARTING → WAIT or END → IN_GAME. + * + * @param phase The new phase. + */ + public void setPhase(final GamePhase phase) { + if (this.phase == null + || (this.phase != phase && phase.ordinal() > this.phase.ordinal()) + || (this.phase == GamePhase.STARTING && phase == GamePhase.WAIT) + || (this.phase == GamePhase.END && phase == GamePhase.IN_GAME) + ) { + final GamePhase oldPhase = this.phase; + + this.phase = phase; + + log().info("Game phase changed to {0}.", phase); + + RunTask.nextTick( + () -> Bukkit.getServer().getPluginManager().callEvent(new GamePhaseChangedEvent(oldPhase, phase))); + } + } + + /** + * Compares the current phase with the given one. + * + * @param phase The compared phase. + * @return {@code true} if the current phase is strictly before this one. + */ + public boolean currentPhaseBefore(final GamePhase phase) { + return this.phase.ordinal() < phase.ordinal(); + } + + /** + * Compares the current phase with the given one. + * + * @param phase The compared phase. + * @return {@code true} if the current phase is strictly after this one. + */ + public boolean currentPhaseAfter(final GamePhase phase) { + return this.phase.ordinal() > phase.ordinal(); + } + + public boolean isSlowMode() { + return slowMode; + } + + public void setSlowMode(boolean slowMode) { + this.slowMode = slowMode; + } + + public TeleportationMode getTeleportationMode() { + return teleportationMode; + } + + public void setTeleportationMode(TeleportationMode teleportationMode) { + this.teleportationMode = teleportationMode; + } + + public Teleporter getTeleporter() { + return teleporter; + } + + /** + * Sets the phase to {@link GamePhase#IN_GAME} after a countdown. + */ + public void start() { + if (startingCountdownLock) { + return; + } + if (phase != GamePhase.STARTING) { + throw new IllegalStateException("Cannot start the game if not in “starting” phase."); + } + if (teleportationProcessLock) { + throw new IllegalStateException("Cannot start the game: the teleportation phase is still running."); + } + + startingCountdownLock = true; + + final AtomicInteger countdown = new AtomicInteger(Config.COUNTDOWN.get() + 1); + final float[] countdownNotes = new float[] {.75f, .86f, .66f, 1, .5f, .5f, .5f}; + final AtomicInteger countdownIndex = new AtomicInteger(-1); + + RunTask.timer(new BukkitRunnable() { + @Override + public void run() { + countdown.getAndDecrement(); + + if (countdown.get() != 0 || !Config.STARTUP_TITLE.get()) { + Titles.broadcastTitle( + countdown.get() == 10 ? 8 : 0, + countdown.get() == 0 ? 40 : 20, + countdown.get() == 0 ? 20 : 0, + (countdown.get() > 5 ? ChatColor.GREEN : + (countdown.get() > 3 ? ChatColor.YELLOW : ChatColor.RED)) + countdown.toString(), + "" + ); + } else { + Titles.broadcastTitle( + 0, 84, 8, + /// Title of title displayed when the game starts. + I.t("{darkgreen}Let's go!"), + /// Subtitle of title displayed when the game starts. + I.t("{green}Good luck, and have fun") + ); + } + + if (countdown.get() != 0) { + if (countdownIndex.incrementAndGet() == countdownNotes.length) { + countdownIndex.set(0); + } + + new QSGSound(1f, countdownNotes[countdownIndex.get()], "ARROW_HIT_PLAYER", "SUCCESSFUL_HIT") + .broadcast(); + } else { + new QSGSound("WITHER_DEATH").broadcast(); + } + + if (countdown.get() == 0) { + setPhase(GamePhase.IN_GAME); + cancel(); + } + } + }, 5L, 20L); + } + + + + /* *** GAME STARTUP + TELEPORTATION *** */ + + + @EventHandler(priority = EventPriority.LOW) + public void onGameStarting(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() != GamePhase.STARTING) { + return; + } + + teleportationProcessLock = true; + + // We allow modules to prepare themselves for the teleportation phase + // (e.g. the spawns modules can generate missing spawn points on the fly). + Bukkit.getPluginManager().callEvent(new BeforeTeleportationPhaseEvent()); + + // We determine if the game is or not with teams by counting the teams. + teamsGame = QuartzTeams.get().countTeams() > 0; + + alivePlayers.clear(); + aliveTeams.clear(); + + // The Team is the base unit of the game. In a solo game, there is one team per player, with one player inside. + // In case of a teams game, we create a “wrapping” team for each alone player. Else, a team for each player. + // These teams created on the fly are saved in case of startup fail. + + final Set<QuartzTeam> onTheFlyTeams = new HashSet<>(); + final Random random = new Random(); + + Bukkit.getOnlinePlayers().stream() + .filter(player -> QuartzTeams.get().getTeamForPlayer(player) == null) + .filter(player -> !QSG.module(SpectatorsModule.class).isSpectator(player)) + .forEach(player -> + { + // We need an unique name for the team. + String teamName = player.getName(); + while (QuartzTeams.get().isTeamRegistered(teamName)) { + teamName = player.getName() + " " + random.nextInt(1000000); + } + + final QuartzTeam team = QuartzTeams.get().createTeam( + teamName, + Config.RANDOM_COLORS_IN_SOLO_GAMES.get() ? TeamColor.RANDOM : TeamColor.WHITE, + player + ); + + onTheFlyTeams.add(team); + }); + + + // Loading alive players from teams, now that they are constructed and complete. + + QuartzTeams.get().getTeams().stream() + .flatMap(team -> team.getPlayers().stream()) + .map(OfflinePlayer::getUniqueId) + .filter(player -> !QSG.module(SpectatorsModule.class).isSpectator(player)) + .forEach(alivePlayers::add); + + updateAliveTeams(); + + + // We have to check if there is enough spawn points. + + int spawnsNeeded = + teleportationMode == TeleportationMode.IGNORE_TEAMS ? alivePlayers.size() : aliveTeams.size(); + + if (QSG.module(SpawnsModule.class).getSpawnPoints().size() < spawnsNeeded) { + log().broadcastAdministrative(I.t("{ce}Unable to start the game: not enough teleportation spots.")); + log().broadcastAdministrative( + I.t("{ci}You can use {cc}/uh spawns generate <random|circular|grid>{ci} to generate the missing spawns automatically.")); + + /// In the sentence: "Or click here to generate the spawns randomly." + log().broadcastAdministrative(new RawText(I.t("Or")) + .then(" ") + /// In the sentence: "Or click here to generate the spawns randomly." + .then(I.t("click here")) + .color(ChatColor.GREEN).style(ChatColor.BOLD) + .command("/uh spawns generate random") + .hover(new RawText("/uh spawns generate random")) + .then(" ") + /// In the sentence: "Or click here to generate the spawns randomly." + .then(I.t("to generate the spawns randomly.")).color(ChatColor.WHITE) + .build() + ); + + // We clears the teams created on-the-fly + onTheFlyTeams.forEach(QuartzTeam::deleteTeam); + + // We set the phase back to WAIT. + setPhase(GamePhase.WAIT); + + return; + } + + + // Preparation of the spawn points. + + final List<Location> spawnPoints = QSG.module(SpawnsModule.class).getSpawnPoints(); + Collections.shuffle(spawnPoints); + + final Queue<Location> unusedSpawnPoints = new ArrayDeque<>(spawnPoints); + + teleporter = new Teleporter(); + + QuartzTeams.get().getTeams().stream().filter(team -> !team.isEmpty()).forEach(team -> + { + if (teleportationMode == TeleportationMode.NORMAL && teamsGame) { + final Location teamSpawn = unusedSpawnPoints.poll(); + + // Should never happen + if (teamSpawn == null) { + log().error( + "A fatal error occurred while starting the game: cannot set spawn point for team {0}: not enough spawn points", + team.getName() + ); + + return; + } + + team.getPlayersUUID().forEach(player -> + { + final PlayerSpawnPointSelectedEvent event = new PlayerSpawnPointSelectedEvent( + Bukkit.getOfflinePlayer(player), teamSpawn.clone()); + + Bukkit.getPluginManager().callEvent(event); + + teleporter.setSpawnForPlayer(player, event.getSpawnPoint()); + }); + } else { + team.getPlayersUUID().forEach(player -> + { + final Location playerSpawn = unusedSpawnPoints.poll(); + final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); + + // Should never happen + if (playerSpawn == null) { + log().error( + "A fatal error occurred while starting the game: cannot set spawn point for player {0}: not enough spawn points", + offlinePlayer.getName() + ); + + return; + } + + final PlayerSpawnPointSelectedEvent event = new PlayerSpawnPointSelectedEvent( + offlinePlayer, playerSpawn); + + Bukkit.getPluginManager().callEvent(event); + + teleporter.setSpawnForPlayer(player, event.getSpawnPoint()); + }); + } + }); + + + // Effective teleportation. + + teleporter + .whenTeleportationOccurs(uuid -> Bukkit.getPluginManager().callEvent( + new PlayerAboutToBeTeleportedToSpawnPointEvent(Bukkit.getPlayer(uuid), + teleporter.getSpawnForPlayer(uuid)))) + + .whenTeleportationSuccesses(uuid -> { + final Player player = Bukkit.getPlayer(uuid); + + log().info("Player {0} - {1} teleported to its spawn point.", uuid, player.getName()); + + Bukkit.getPluginManager().callEvent( + new PlayerTeleportedToSpawnPointEvent(player, teleporter.getSpawnForPlayer(uuid))); + }) + + .whenTeleportationFails(uuid -> log() + .error("Unable to teleport player {0} - {1}", uuid, Bukkit.getOfflinePlayer(uuid).getName())) + + .whenTeleportationEnds(uuids -> { + teleportationProcessLock = false; + Bukkit.getPluginManager().callEvent(new AfterTeleportationPhaseEvent()); + }) + + .startTeleportationProcess(slowMode); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerTeleportedToSpawnPoint(final PlayerTeleportedToSpawnPointEvent ev) { + Player player = Bukkit.getPlayer(ev.getPlayer().getUniqueId()); + + if (player != null) { + player.setGameMode(GameMode.ADVENTURE); + player.setAllowFlight(true); + player.setFlying(true); + player.setFlySpeed(0f); + } + + if (Config.BROADCAST_PROGRESS.get()) { + teleportationProgress++; + + /// Displayed in the action bar while the slow teleportation occurs. + final String message = + I.t("{lightpurple}Teleporting... {gray}({0}/{1})", teleportationProgress, alivePlayers.size()); + Bukkit.getOnlinePlayers().forEach(onlinePlayer -> ActionBar.sendPermanentMessage(onlinePlayer, message)); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onTeleportationProcessComplete(final AfterTeleportationPhaseEvent ev) { + log().broadcastAdministrative(I.t("{cs}All teams are teleported.")); + + if (slowMode) { + log().broadcastAdministrative( + new RawText(I.t("{gray}Use {cc}/uh start{gray} or click here to start the game.")) + .hover(new RawText(I.t("Click here to start the game"))) + .command(StartCommand.class) + ); + } else { + start(); + } + + // TODO Use permissions + if (Config.BROADCAST_PROGRESS.get()) { + /// Displayed in the action bar when the slow teleportation is finished but the game not started. + Bukkit.getOnlinePlayers().stream().filter(p -> !p.isOp()).forEach(player -> ActionBar.sendPermanentMessage(player, + I.tl(player, "{lightpurple}Teleportation complete. {gray}The game will start soon..."))); + + /// Displayed in the action bar when the slow teleportation is finished but the game not started, for ops. + Bukkit.getOnlinePlayers().stream().filter(ServerOperator::isOp).forEach(player -> ActionBar.sendPermanentMessage(player, + I.tl(player, "{lightpurple}Teleportation complete. {gray}Use {cc}/uh start{gray} to start the game."))); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onGameStarts(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() != GamePhase.IN_GAME || !ev.isRunningForward()) { + return; + } + + Bukkit.getOnlinePlayers().forEach(ActionBar::removeMessage); + + getAliveConnectedPlayers().forEach(player -> { + updatePlayerFlightOptions(player); + + player.setFlying(false); + player.setAllowFlight(false); + + player.setGameMode(GameMode.SURVIVAL); + + player.setHealth(player.getMaxHealth()); + + player.setFoodLevel(20); + player.setSaturation(20); + + player.getInventory().clear(); + player.getInventory().setArmorContents(null); + + player.closeInventory(); + + player.setExp(0L); + player.setLevel(0); + }); + + // Just in case... + QSG.get().getWorlds().forEach(world -> world.setGameRuleValue("keepInventory", Boolean.FALSE.toString())); + } + + + + /* *** PLAYER OR TEAM DEATH & GAME END *** */ + + + @EventHandler + public void onPlayerDeath(final PlayerDeathEvent ev) { + if (phase != GamePhase.IN_GAME) { + return; + } + if (!isAlive(ev.getEntity())) { + return; + } + + kill(ev.getEntity(), ev); + } + + @EventHandler + public void onPlayerKilled(final AlivePlayerDeathEvent ev) { + log().info("{0} killed", ev.getPlayer().getName()); + } + + @EventHandler + public void onPlayerResurrected(final PlayerResurrectedEvent ev) { + log().info("{0} resurrected", ev.getPlayer().getName()); + + /// Resurrection notification. {0} = raw resurrected player name. + Bukkit.broadcastMessage(I.t("{gold}{0} returned from the dead!", ev.getPlayer().getName())); + } + + @EventHandler + public void onGameEndsOrEndsCancelled(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() == GamePhase.END) { + winner = aliveTeams.stream().findAny().orElse(null); // There will be one alive team left here. + } else if (ev.getNewPhase() == GamePhase.IN_GAME && !ev.isRunningForward()) { + winner = null; // Win cancelled because a team was resurrected. + } + } + + + + /* *** OTHER PLAYERS MANAGEMENT *** */ + + @EventHandler + public void onPlayerJoin(final PlayerJoinEvent ev) { + updatePlayerFlightOptions(ev.getPlayer()); + } + + + /** + * Sets the flight options for the player according to the current game phase. + * + * @param player The player. + */ + private void updatePlayerFlightOptions(final Player player) { + switch (phase) { + case WAIT: + player.setFlySpeed(.1f); + break; + + case STARTING: + if (alivePlayers.contains(player.getUniqueId())) { + player.setAllowFlight(true); + player.setFlySpeed(0f); + } else { + player.setFlySpeed(.1f); + } + + break; + + case IN_GAME: + case END: + player.setFlySpeed(.1f); + } + } + + private void updateAliveTeams() { + aliveTeams.clear(); + + QuartzTeams.get().getTeams() + .forEach(t -> t.getPlayersUUID().stream().filter(alivePlayers::contains).map(pid -> t) + .forEach(aliveTeams::add)); + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/events/EpisodeChangedCause.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/GamePhase.java similarity index 76% rename from src/main/java/eu/carrade/amaury/UHCReloaded/events/EpisodeChangedCause.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/GamePhase.java index 70bb4f4..dbedf3e 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/events/EpisodeChangedCause.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/GamePhase.java @@ -30,18 +30,30 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.events; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.game; + + +/** + * Represents the current phase of the game. + */ +public enum GamePhase { + /** + * Before the game, when the players are waiting for the game to start. + */ + WAIT, + + /** + * While the game is starting (can last the time of the start countdown, or longer with the slow start). + */ + STARTING, -public enum EpisodeChangedCause -{ /** - * The episode changed because the previous episode was finished. + * The main phase of the game. */ - FINISHED, + IN_GAME, /** - * The episode changed because the previous episode was shifted by someone using - * the {@code /uh shift} command. + * After the game when some player(s) won. */ - SHIFTED + END } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/commands/KillCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/commands/KillCommand.java new file mode 100644 index 0000000..231d842 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/commands/KillCommand.java @@ -0,0 +1,97 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.game.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; + +@CommandInfo(name = "kill", usageParameters = "<player>") +public class KillCommand extends Command { + @Override + protected void run() throws CommandException { + if (args.length < 1) { + throwInvalidArgument(I.t("You must specify the player to kill.")); + } + + final OfflinePlayer player = Arrays.stream(Bukkit.getOfflinePlayers()) + .filter(pl -> pl.getName().equalsIgnoreCase(args[0])) + .findAny().orElse(null); + + if (player == null) { + error(I.t("{ce}This player was never seen on this server.")); + return; + } + + if (QSG.module(GameModule.class).isAlive(player)) { + if (player.isOnline()) { + // If the player is online, we kill it. + // It will be cached by normal alive players's death listeners, + // plus the inventory will drop, effects will be complete, etc. + player.getPlayer().setHealth(0d); + } else { + // We only kill the player this way if he is offline. + QSG.module(GameModule.class).kill(player); + } + + success(I.t("{cs}The player {0} is now marked as dead.", player.getName())); + } else { + error(I.t("{ce}{0} is not an alive player.", player.getName())); + } + } + + @Override + protected List<String> complete() { + if (args.length == 1) { + return getMatchingSubset( + QSG.module(GameModule.class) + .getAlivePlayers().stream() + .map(OfflinePlayer::getName) + .collect(Collectors.toList()), + args[0] + ); + } else { + return null; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/commands/ResurrectCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/commands/ResurrectCommand.java new file mode 100644 index 0000000..8c5671a --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/commands/ResurrectCommand.java @@ -0,0 +1,85 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.game.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; + + +@CommandInfo(name = "resurrect", usageParameters = "<player>", aliases = {"revive", "undead"}) +public class ResurrectCommand extends Command { + @Override + protected void run() throws CommandException { + if (args.length != 1) { + throwInvalidArgument(I.t("You must specify the player to resurrect.")); + } + + final OfflinePlayer player = Arrays.stream(Bukkit.getOfflinePlayers()) + .filter(pl -> pl.getName().equalsIgnoreCase(args[0])) + .findAny().orElse(null); + + if (player == null) { + error(I.t("{ce}This player was never seen on this server.")); + } else if (QSG.module(GameModule.class).resurrect(player)) { + success(I.t("{0} was resurrected.", player.getName())); + } else { + error(I.t("{ce}This player is not playing or dead!")); + } + } + + @Override + protected List<String> complete() { + final GameModule game = QSG.module(GameModule.class); + + if (args.length == 1) { + return getMatchingPlayerNames( + Bukkit.getOnlinePlayers().stream().filter(player -> !game.isAlive(player)) + .collect(Collectors.toList()), + args[0] + ); + } else { + return null; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/commands/StartCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/commands/StartCommand.java new file mode 100644 index 0000000..e9b26f9 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/commands/StartCommand.java @@ -0,0 +1,93 @@ +/* + * 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.quartzsurvivalgames.modules.core.game.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.teleporter.TeleportationMode; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.commands.WithFlags; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.List; +import org.bukkit.entity.Player; + + +@CommandInfo(name = "start", usageParameters = "[--slow] [--ignore-teams]") +@WithFlags({"slow", "ignore-teams"}) +public class StartCommand extends Command { + @Override + protected void run() throws CommandException { + final GameModule game = QSG.module(GameModule.class); + + switch (game.getPhase()) { + case WAIT: + game.setSlowMode(hasFlag("slow")); + game.setTeleportationMode( + hasFlag("ignore-teams") ? TeleportationMode.IGNORE_TEAMS : TeleportationMode.NORMAL); + + if (hasFlag("slow")) { + if (sender instanceof Player) { + info(""); + } + info(I.t("{green}{bold}The game is now starting.")); + info(I.t( + "{green}Wait for the teleportation to finish; you'll then be prompted to start the game.")); + } + + game.setPhase(GamePhase.STARTING); + + break; + + case STARTING: + try { + game.start(); + } + catch (final IllegalStateException e) { + error(I.t("The starting process is not finished yet. Please be patient.")); + } + + break; + + default: + error(I.t("{ce}The game is already started! Reload or restart the server to restart the game.")); + } + } + + @Override + protected List<String> complete() { + return getMatchingSubset(args[args.length - 1], "--slow", "--ignore-teams"); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/game/GamePhaseChangedEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/game/GamePhaseChangedEvent.java new file mode 100644 index 0000000..a99f225 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/game/GamePhaseChangedEvent.java @@ -0,0 +1,102 @@ +/* + * 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.quartzsurvivalgames.modules.core.game.events.game; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + + +/** + * Fired when the game phase changes. + * + * <p><strong>Warning:</strong> if the new phase is {@link GamePhase#IN_GAME IN_GAME} + * or {@link GamePhase#WAIT WAIT}, the game may be going backwards, if the game start + * was cancelled because of an error, or if a player was resurrected at the end of the + * game. To check if you are in this case, and e.g. avoid running game-start-code when + * a player is resurrected, check the old phase with {@link #getOldPhase()}, or simpler, + * use the {@link #isRunningForward()} method.</p> + */ +public class GamePhaseChangedEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + private final GamePhase oldPhase; + private final GamePhase newPhase; + + public GamePhaseChangedEvent(final GamePhase oldPhase, final GamePhase newPhase) { + this.oldPhase = oldPhase; + this.newPhase = newPhase; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + /** + * The old phase. May be {@code null} if this is the first phase ever (i.e. {@link GamePhase#WAIT}). + * + * @return The old phase. + */ + public GamePhase getOldPhase() { + return oldPhase; + } + + /** + * @return The new phase. + */ + public GamePhase getNewPhase() { + return newPhase; + } + + /** + * Checks if this phase change is running forward regarding the normal phases progression. + * + * <h3>Example</h3> + * <ul> + * <li>If we have the cycle {@link GamePhase#STARTING STARTING} → {@link GamePhase#IN_GAME IN_GAME}, + * this will return {@code true}.</li> + * <li>If we have the cycle {@link GamePhase#END END} → {@link GamePhase#IN_GAME IN_GAME}, + * this will return {@code false}.</li> + * </ul> + * + * @return {@code true} if the game is running forward. + */ + public boolean isRunningForward() { + return oldPhase == null || newPhase.ordinal() > oldPhase.ordinal(); + } + + @Override + public HandlerList getHandlers() { + return handlers; + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/players/AlivePlayerDeathEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/players/AlivePlayerDeathEvent.java new file mode 100644 index 0000000..a940fa3 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/players/AlivePlayerDeathEvent.java @@ -0,0 +1,100 @@ +/* + * 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.quartzsurvivalgames.modules.core.game.events.players; + +import org.bukkit.OfflinePlayer; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.PlayerDeathEvent; + + +/** + * Fired when a player playing an UHC match is dead. + * <p> + * When this event is called, the player is not yet removed from the alive + * players (i.e. {@code UR.module(GameModule.class).isAlive(ev.getPlayer())} + * will return {@code true}). + * <p> + * If the event is cancelled, the player will die but will not be removed + * from the alive players. + */ +public class AlivePlayerDeathEvent extends Event implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private final OfflinePlayer player; + private final PlayerDeathEvent playerDeathEvent; + private boolean cancelled = false; + + public AlivePlayerDeathEvent(final OfflinePlayer player, final PlayerDeathEvent playerDeathEvent) { + this.player = player; + this.playerDeathEvent = playerDeathEvent; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + /** + * Returns the dead player. + * + * @return The player. + */ + public OfflinePlayer getPlayer() { + return player; + } + + /** + * Returns the underlying {@link PlayerDeathEvent}. Can be {@code null} if the player + * was killed using {@code /uh kill} or programmatically. + * + * @return The {@link PlayerDeathEvent}. + */ + public PlayerDeathEvent getPlayerDeathEvent() { + return playerDeathEvent; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/events/UHPlayerResurrectedEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/players/PlayerResurrectedEvent.java similarity index 76% rename from src/main/java/eu/carrade/amaury/UHCReloaded/events/UHPlayerResurrectedEvent.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/players/PlayerResurrectedEvent.java index b71bc5b..c859329 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/events/UHPlayerResurrectedEvent.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/players/PlayerResurrectedEvent.java @@ -30,54 +30,39 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.events; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players; -import org.bukkit.entity.Player; +import org.bukkit.OfflinePlayer; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * Called when a player is resurrected. - * <p> - * This event is called when: - * <ul> - * <li>the command {@code /uh resurrect <player>} is executed, if the target is online;</li> - * <li>the resurrected player logins, else</li> - * </ul> - * (i.e. when the message “the player is resurrected” is broadcasted). */ -public class UHPlayerResurrectedEvent extends Event -{ - private Player resurrectedPlayer; +public class PlayerResurrectedEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + private final OfflinePlayer resurrectedPlayer; - public UHPlayerResurrectedEvent(Player player) - { + public PlayerResurrectedEvent(final OfflinePlayer player) { this.resurrectedPlayer = player; } + public static HandlerList getHandlerList() { + return handlers; + } + /** * Returns the resurrected player. * * @return The player. */ - public Player getPlayer() - { + public OfflinePlayer getPlayer() { return resurrectedPlayer; } - - - private static final HandlerList handlers = new HandlerList(); - @Override - public HandlerList getHandlers() - { - return handlers; - } - - public static HandlerList getHandlerList() - { + public HandlerList getHandlers() { return handlers; } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/events/UHTeamDeathEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/players/TeamDeathEvent.java similarity index 84% rename from src/main/java/eu/carrade/amaury/UHCReloaded/events/UHTeamDeathEvent.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/players/TeamDeathEvent.java index b02ef9e..b7a0c5f 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/events/UHTeamDeathEvent.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/players/TeamDeathEvent.java @@ -30,9 +30,9 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.events; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; +import fr.zcraft.quartzteams.QuartzTeam; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; @@ -40,37 +40,29 @@ /** * Event fired when the last member of a team die. */ -public class UHTeamDeathEvent extends Event -{ - private UHTeam team; +public class TeamDeathEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + private final QuartzTeam team; - public UHTeamDeathEvent(UHTeam team) - { + public TeamDeathEvent(QuartzTeam team) { this.team = team; } + public static HandlerList getHandlerList() { + return handlers; + } + /** * Returns the now-dead team. * * @return The team. */ - public UHTeam getTeam() - { + public QuartzTeam getTeam() { return team; } - - - private static final HandlerList handlers = new HandlerList(); - @Override - public HandlerList getHandlers() - { - return handlers; - } - - public static HandlerList getHandlerList() - { + public HandlerList getHandlers() { return handlers; } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/events/UHGameStartsEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/AfterTeleportationPhaseEvent.java similarity index 85% rename from src/main/java/eu/carrade/amaury/UHCReloaded/events/UHGameStartsEvent.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/AfterTeleportationPhaseEvent.java index 2592d7e..c712319 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/events/UHGameStartsEvent.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/AfterTeleportationPhaseEvent.java @@ -30,27 +30,24 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.events; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** - * This event is fired when the UHC game is started. + * Fired while starting the game, when the teleportation phase is finished. */ -public class UHGameStartsEvent extends Event -{ +public class AfterTeleportationPhaseEvent extends Event { private static final HandlerList handlers = new HandlerList(); - @Override - public HandlerList getHandlers() - { + public static HandlerList getHandlerList() { return handlers; } - public static HandlerList getHandlerList() - { + @Override + public HandlerList getHandlers() { return handlers; } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/task/UpdateTimerTask.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/BeforeTeleportationPhaseEvent.java similarity index 75% rename from src/main/java/eu/carrade/amaury/UHCReloaded/task/UpdateTimerTask.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/BeforeTeleportationPhaseEvent.java index 37310b1..cc33957 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/task/UpdateTimerTask.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/BeforeTeleportationPhaseEvent.java @@ -29,21 +29,26 @@ * 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.task; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; -import org.bukkit.scheduler.BukkitRunnable; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + + +/** + * Fired while starting the game, when the teleportation phase is about + * to start. + */ +public class BeforeTeleportationPhaseEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlerList() { + return handlers; + } -public class UpdateTimerTask extends BukkitRunnable -{ @Override - public void run() - { - for (UHTimer timer : UHCReloaded.get().getTimerManager().getRunningTimers()) - { - timer.update(); - } + public HandlerList getHandlers() { + return handlers; } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/events/UHPlayerDeathEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/PlayerAboutToBeTeleportedToSpawnPointEvent.java similarity index 69% rename from src/main/java/eu/carrade/amaury/UHCReloaded/events/UHPlayerDeathEvent.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/PlayerAboutToBeTeleportedToSpawnPointEvent.java index f0cbe82..85f8e8c 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/events/UHPlayerDeathEvent.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/PlayerAboutToBeTeleportedToSpawnPointEvent.java @@ -30,60 +30,46 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.events; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start; +import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; -import org.bukkit.event.entity.PlayerDeathEvent; /** - * Fired when a player playing an UHC match is dead. + * Fired just before a player's teleportation to its spawn point. * <p> - * This event is called before all the action executed on player death (sound, scoreboard updates, etc.). + * The spawn point cannot be modified here. + * + * @see PlayerSpawnPointSelectedEvent */ -public class UHPlayerDeathEvent extends Event -{ - private Player player; - private PlayerDeathEvent ev; +public class PlayerAboutToBeTeleportedToSpawnPointEvent extends Event { + private static final HandlerList handlers = new HandlerList(); - public UHPlayerDeathEvent(Player player, PlayerDeathEvent ev) - { + private final Player player; + private final Location spawnPoint; + + public PlayerAboutToBeTeleportedToSpawnPointEvent(final Player player, final Location spawnPoint) { this.player = player; - this.ev = ev; + this.spawnPoint = spawnPoint; } - /** - * Returns the dead player. - * @return The player. - */ - public Player getPlayer() - { - return player; + public static HandlerList getHandlerList() { + return handlers; } - /** - * Returns the PlayerDeathEvent under this event. - * @return The PlayerDeathEvent. - */ - public PlayerDeathEvent getPlayerDeathEvent() - { - return ev; + public Player getPlayer() { + return player; } - - - private static final HandlerList handlers = new HandlerList(); - - @Override - public HandlerList getHandlers() - { - return handlers; + public Location getSpawnPoint() { + return spawnPoint; } - public static HandlerList getHandlerList() - { + @Override + public HandlerList getHandlers() { return handlers; } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/PlayerSpawnPointSelectedEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/PlayerSpawnPointSelectedEvent.java new file mode 100644 index 0000000..730b934 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/PlayerSpawnPointSelectedEvent.java @@ -0,0 +1,75 @@ +/* + * 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.quartzsurvivalgames.modules.core.game.events.start; + +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + + +/** + * Fired when a spawn point is selected for a given player. + */ +public class PlayerSpawnPointSelectedEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + private final OfflinePlayer player; + private Location spawnPoint; + + public PlayerSpawnPointSelectedEvent(final OfflinePlayer player, final Location spawnPoint) { + this.player = player; + this.spawnPoint = spawnPoint; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + public OfflinePlayer getPlayer() { + return player; + } + + public Location getSpawnPoint() { + return spawnPoint; + } + + public void setSpawnPoint(Location spawnPoint) { + this.spawnPoint = spawnPoint; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/PlayerTeleportedToSpawnPointEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/PlayerTeleportedToSpawnPointEvent.java new file mode 100644 index 0000000..330ebad --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/events/start/PlayerTeleportedToSpawnPointEvent.java @@ -0,0 +1,75 @@ +/* + * 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.quartzsurvivalgames.modules.core.game.events.start; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + + +/** + * Fired when a player is teleported to its spawn point. + * <p> + * The spawn point cannot be modified here. + * + * @see PlayerSpawnPointSelectedEvent + */ +public class PlayerTeleportedToSpawnPointEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + private final Player player; + private final Location spawnPoint; + + public PlayerTeleportedToSpawnPointEvent(final Player player, final Location spawnPoint) { + this.player = player; + this.spawnPoint = spawnPoint; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + public Player getPlayer() { + return player; + } + + public Location getSpawnPoint() { + return spawnPoint; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/submanagers/GameBeginning.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/submanagers/GameBeginning.java new file mode 100644 index 0000000..c813833 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/submanagers/GameBeginning.java @@ -0,0 +1,245 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.game.submanagers; + +import com.google.common.collect.ImmutableSet; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.Config; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.EntitiesUtils; +import eu.carrade.amaury.quartzsurvivalgames.utils.Run; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.core.QuartzComponent; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import java.util.Set; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityDamageEvent; + +public class GameBeginning extends QuartzComponent implements Listener { + private static final Set<String> SURFACE_MATERIAL_ENDS = ImmutableSet.of( + "LOG", + "LEAVES", + "PLANKS", + "STAIRS", + "BANNER", + "WALL", + "FENCE" + ); + /** + * A flag used to disable damages at the beginning of the game to avoid fall damages and early ones. + */ + private boolean inGracePeriod = false; + /** + * A flag used to disable hostile mobs spawn on the surface a few minutes after the beginning of the game. + */ + private boolean inMobsFreePeriod = false; + + @EventHandler(priority = EventPriority.LOWEST) + private void onGameStarts(GamePhaseChangedEvent ev) { + if (ev.getNewPhase() != GamePhase.IN_GAME || !ev.isRunningForward()) { + return; + } + + + /* *** Grace period (damages disabled) *** */ + + TimeDelta grace = Config.BEGINNING.GRACE_PERIOD.get(); + + if (grace.getSeconds() < 15) { + grace = new TimeDelta(15); + } + + inGracePeriod = true; + + Run.withCountdown( + I.t("{green}{bold}Grace period"), + I.t("{green}All damages are disabled"), + second -> I.tn("{yellow}{bold}Over in {gold}{bold}{0}{yellow}{bold} second", + "{yellow}{bold}Over in {gold}{bold}{0}{yellow}{bold} second", (int) second), + I.t("{yellow}{bold}Over! {yellow}You are now vulnerable..."), + () -> QSG.game().getAliveConnectedPlayers(), + () -> { + inGracePeriod = false; + + if (Config.BEGINNING.BROADCAST_GRACE_END.get()) { + Bukkit.broadcastMessage( + I.t("{red}{bold}Warning!{white} The grace period is over, you are now vulnerable.")); + } + }, + grace + ); + + + /* *** Peace period (PVP disabled) *** */ + + if (Config.BEGINNING.PEACE_PERIOD.get().getSeconds() > 0) { + setPVP(false); + + Run.withCountdown( + I.t("{red}{bold}Combats between players"), + null, + second -> I.tn("{yellow}{bold}Allowed in {gold}{bold}{0}{yellow}{bold} second", + "{yellow}{bold}Allowed in {gold}{bold}{0}{yellow}{bold} second", (int) second), + I.t("{yellow}{bold}Now allowed! {yellow}Beware..."), + (short) 10, + () -> QSG.game().getAliveConnectedPlayers(), + () -> { + setPVP(true); + Bukkit.broadcastMessage(I.t("{red}{bold}Warning!{white} PvP is now enabled.")); + }, + Config.BEGINNING.PEACE_PERIOD.get() + ); + } else { + setPVP(true); + } + + + /* *** Mobs-free period (mobs disabled on surface) *** */ + + if (Config.BEGINNING.SURFACE_MOBS_FREE_PERIOD.get().getSeconds() > 0) { + inMobsFreePeriod = true; + RunTask.later(() -> inMobsFreePeriod = false, + Config.BEGINNING.SURFACE_MOBS_FREE_PERIOD.get().getSeconds() * 20L); + } + } + + + /** + * Used to disable all damages if the game is not started. + */ + @EventHandler + private void onEntityDamage(final EntityDamageEvent ev) { + if (ev.getEntity() instanceof Player && inGracePeriod) { + ev.setCancelled(true); + } + } + + /** + * Used to cancel the spawn of hostile entities on the surface only, at the beginning of the game. + */ + @EventHandler + private void onSurfaceCreatureSpawn(final CreatureSpawnEvent ev) { + if (inMobsFreePeriod && EntitiesUtils.isNaturalSpawn(ev.getSpawnReason()) && + EntitiesUtils.isHostile(ev.getEntityType())) { + // We check the blocs above the entity to see if we only find surface blocks. + final Location spawnLocation = ev.getLocation(); + final World world = spawnLocation.getWorld(); + final int highestBlockY = world.getHighestBlockYAt(spawnLocation); + + final int x = spawnLocation.getBlockX(); + final int z = spawnLocation.getBlockZ(); + + boolean surface = true; + + for (int y = spawnLocation.getBlockY(); y <= highestBlockY; y++) { + final Material type = world.getBlockAt(x, y, z).getType(); + + switch (type) { + // Air + case AIR: + + // Trees + case BROWN_MUSHROOM_BLOCK: + case RED_MUSHROOM_BLOCK: + + // Vegetation + case DEAD_BUSH: + case CHORUS_PLANT: + case KELP_PLANT: + case GRASS: + case CHORUS_FLOWER: + case SUNFLOWER: + case CORNFLOWER: + case VINE: + case SUGAR_CANE: + case BROWN_MUSHROOM: + case RED_MUSHROOM: + + // Nature + case SNOW: + + // Igloos + case SNOW_BLOCK: + + // Villages + case BOOKSHELF: + + // Redstone + case REDSTONE_WIRE: + case COMPARATOR: + case REDSTONE_TORCH: + + // Other blocs frequently used on surface on custom maps + case TORCH: + case RAIL: + case ACTIVATOR_RAIL: + case DETECTOR_RAIL: + case POWERED_RAIL: + break; + + default: + surface = false; + } + + if (!surface) { + final String typeName = type.name(); + surface = SURFACE_MATERIAL_ENDS.stream().anyMatch(typeName::endsWith); + } + + if (!surface) { + break; + } + } + + if (surface) { + ev.setCancelled(true); + } + } + } + + private void setPVP(final boolean pvp) { + QSG.get().getWorlds().forEach(world -> world.setPVP(pvp)); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/teleporter/TeleportationMode.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/teleporter/TeleportationMode.java new file mode 100644 index 0000000..2032b6f --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/teleporter/TeleportationMode.java @@ -0,0 +1,47 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.game.teleporter; + +public enum TeleportationMode { + /** + * Teams are teleported together. + */ + NORMAL, + + /** + * Players are all teleported alone, even if they are in teams. + */ + IGNORE_TEAMS +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/game/TeleportationRunnable.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/teleporter/TeleportationRunnable.java similarity index 76% rename from src/main/java/eu/carrade/amaury/UHCReloaded/game/TeleportationRunnable.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/teleporter/TeleportationRunnable.java index 91059b3..0c7b2e6 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/game/TeleportationRunnable.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/teleporter/TeleportationRunnable.java @@ -29,25 +29,24 @@ * 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.game; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.tools.Callback; -import org.bukkit.scheduler.BukkitRunnable; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.game.teleporter; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.tools.Callback; import java.util.ArrayDeque; import java.util.HashSet; import java.util.NoSuchElementException; import java.util.Queue; import java.util.Set; import java.util.UUID; +import org.bukkit.scheduler.BukkitRunnable; /** * @see Teleporter */ -class TeleportationRunnable extends BukkitRunnable -{ +class TeleportationRunnable extends BukkitRunnable { private final Teleporter teleporter; private final Queue<UUID> teleportationQueue; @@ -58,8 +57,9 @@ class TeleportationRunnable extends BukkitRunnable private final Set<UUID> failed = new HashSet<>(); - public TeleportationRunnable(Teleporter teleporter, Set<UUID> playersToTeleport, Callback<UUID> onTeleportation, Callback<UUID> onTeleportationSuccessful, Callback<UUID> onTeleportationFailed, Callback<Set<UUID>> onTeleportationProcessFinished) - { + public TeleportationRunnable(Teleporter teleporter, Set<UUID> playersToTeleport, Callback<UUID> onTeleportation, + Callback<UUID> onTeleportationSuccessful, Callback<UUID> onTeleportationFailed, + Callback<Set<UUID>> onTeleportationProcessFinished) { this.teleporter = teleporter; this.onTeleportation = onTeleportation; this.onTeleportationSuccessful = onTeleportationSuccessful; @@ -70,27 +70,22 @@ public TeleportationRunnable(Teleporter teleporter, Set<UUID> playersToTeleport, } @Override - public void run() - { - try - { + public void run() { + try { UUID player = teleportationQueue.remove(); - UHUtils.callIfDefined(onTeleportation, player); + QSGUtils.callIfDefined(onTeleportation, player); - if (teleporter.teleportPlayer(player, false)) - { - UHUtils.callIfDefined(onTeleportationSuccessful, player); - } - else - { - UHUtils.callIfDefined(onTeleportationFailed, player); + if (teleporter.teleportPlayer(player, false)) { + QSGUtils.callIfDefined(onTeleportationSuccessful, player); + } else { + QSGUtils.callIfDefined(onTeleportationFailed, player); failed.add(player); } } catch (NoSuchElementException e) // Queue empty { - UHUtils.callIfDefined(onTeleportationProcessFinished, failed); + QSGUtils.callIfDefined(onTeleportationProcessFinished, failed); cancel(); } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/game/Teleporter.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/teleporter/Teleporter.java similarity index 68% rename from src/main/java/eu/carrade/amaury/UHCReloaded/game/Teleporter.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/teleporter/Teleporter.java index 8b8b906..90472b9 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/game/Teleporter.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/game/teleporter/Teleporter.java @@ -29,38 +29,30 @@ * 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.game; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import fr.zcraft.zlib.tools.Callback; -import fr.zcraft.zlib.tools.runners.RunTask; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Player; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.game.teleporter; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.Config; +import fr.zcraft.quartzlib.tools.Callback; +import fr.zcraft.quartzlib.tools.runners.RunTask; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; /** * Manages the initial teleportation process, and stores the spawn points of the players. */ -public class Teleporter -{ +public class Teleporter { /** * The spawn point designed for each player. */ private final Map<UUID, Location> spawnPoints = new HashMap<>(); - /** - * The cages generated for each team - */ - private final Map<UUID, Cage> cages = new HashMap<>(); - /** * Called when a player is teleported, during the teleportation process. @@ -94,8 +86,7 @@ public class Teleporter * @param playerUUID The player's UUID. * @param spawn The spawn location. */ - public void setSpawnForPlayer(final UUID playerUUID, final Location spawn) - { + public void setSpawnForPlayer(final UUID playerUUID, final Location spawn) { spawnPoints.put(playerUUID, spawn); } @@ -105,8 +96,7 @@ public void setSpawnForPlayer(final UUID playerUUID, final Location spawn) * @param playerUUID The player UUID. * @return {@code true} if a spawn point is registered. */ - public boolean hasSpawnForPlayer(final UUID playerUUID) - { + public boolean hasSpawnForPlayer(final UUID playerUUID) { return spawnPoints.containsKey(playerUUID); } @@ -114,71 +104,32 @@ public boolean hasSpawnForPlayer(final UUID playerUUID) * @param playerUUID A player's UUID. * @return The registered spawn point for that player, or {@code null} if no-one was ever registered. */ - public Location getSpawnForPlayer(final UUID playerUUID) - { + public Location getSpawnForPlayer(final UUID playerUUID) { return spawnPoints.get(playerUUID).clone(); } - /** - * Registers a cage for a player. - * - * @param player The player - * @param cage The cage - */ - public void setCageForPlayer(final UUID player, final Cage cage) - { - cages.put(player, cage); - } - - /** - * Checks if a cage is registered for the given player. - * @param player The player. - * @return {@code true} if a cage is registered. - */ - public boolean hasCageForPlayer(final UUID player) - { - return cages.containsKey(player); - } - - /** - * @param player A player - * @return The registered {@link Cage} for this player, or {@code null} if no one is registered. - */ - public Cage getCageForPlayer(final UUID player) - { - return cages.get(player); - } - - /** * Teleports the given player to the spawn point. * * @param playerUUID The player's UUID. * @param teleportOnGround if {@code true} the player will be teleported on the ground; else, at * the location directly. - * * @return {@code true} if the player was teleported (i.e. was online and with an associated * spawn point). */ - public boolean teleportPlayer(UUID playerUUID, Boolean teleportOnGround) - { + public boolean teleportPlayer(UUID playerUUID, Boolean teleportOnGround) { Player player = Bukkit.getPlayer(playerUUID); - if (player == null) + if (player == null) { return false; + } Location spawn = spawnPoints.get(playerUUID); - if (spawn == null) + if (spawn == null) { return false; - - else if (teleportOnGround) + } else if (teleportOnGround) { spawn = spawn.getWorld().getHighestBlockAt(spawn).getLocation().add(0, 2, 0); - - if (!teleportOnGround) - { - final Cage cage = cages.get(playerUUID); - if (cage != null) cage.build(); } player.teleport(spawn); @@ -187,14 +138,12 @@ else if (teleportOnGround) /** - * Registers a callback called while trying to teleport a player. + * Registers a callback called just before trying to teleport a player. * * @param callback The callback. Argument: the teleported player's UUID. - * * @return Same instance for chaining. */ - public Teleporter whenTeleportationOccurs(Callback<UUID> callback) - { + public Teleporter whenTeleportationOccurs(Callback<UUID> callback) { onTeleportation = callback; return this; } @@ -203,11 +152,9 @@ public Teleporter whenTeleportationOccurs(Callback<UUID> callback) * Registers a callback called when a player is teleported successfully. * * @param callback The callback. Argument: the non-teleported player's UUID. - * * @return Same instance for chaining. */ - public Teleporter whenTeleportationSuccesses(Callback<UUID> callback) - { + public Teleporter whenTeleportationSuccesses(Callback<UUID> callback) { onTeleportationSuccessful = callback; return this; } @@ -216,11 +163,9 @@ public Teleporter whenTeleportationSuccesses(Callback<UUID> callback) * Registers a callback called when a player cannot be teleported. * * @param callback The callback. Argument: the non-teleported player's UUID. - * * @return Same instance for chaining. */ - public Teleporter whenTeleportationFails(Callback<UUID> callback) - { + public Teleporter whenTeleportationFails(Callback<UUID> callback) { onTeleportationFailed = callback; return this; } @@ -233,11 +178,9 @@ public Teleporter whenTeleportationFails(Callback<UUID> callback) * * @param callback The callback. Argument: a set containing the UUID of all non-teleported * players. - * * @return Same instance for chaining. */ - public Teleporter whenTeleportationEnds(Callback<Set<UUID>> callback) - { + public Teleporter whenTeleportationEnds(Callback<Set<UUID>> callback) { onTeleportationProcessFinished = callback; return this; } @@ -249,35 +192,8 @@ public Teleporter whenTeleportationEnds(Callback<Set<UUID>> callback) * @param slowMode if {@code true}, the players will be slowly teleported one by one, with a * delay between them. */ - public void startTeleportationProcess(Boolean slowMode) - { - // Fast mode: we loop on the spawn points and teleport everyone. Bim. - if (!slowMode) - { - Set<UUID> fails = new HashSet<>(); - - for (UUID playerUUID : spawnPoints.keySet()) - { - UHUtils.callIfDefined(onTeleportation, playerUUID); - - if (teleportPlayer(playerUUID, false)) - { - UHUtils.callIfDefined(onTeleportationSuccessful, playerUUID); - } - else - { - UHUtils.callIfDefined(onTeleportationFailed, playerUUID); - fails.add(playerUUID); - } - } - - UHUtils.callIfDefined(onTeleportationProcessFinished, fails); - } - - // Slow mode - else - { - RunTask.timer( + public void startTeleportationProcess(Boolean slowMode) { + RunTask.timer( new TeleportationRunnable( this, spawnPoints.keySet(), @@ -287,17 +203,7 @@ public void startTeleportationProcess(Boolean slowMode) onTeleportationProcessFinished ), 1L, - UHConfig.START.SLOW.DELAY_BETWEEN_TP.get() * 20L - ); - } - } - - /** - * Cleanups the cages left by the teleportation process, to be executed when the game really starts. - */ - public void cleanup() - { - for (final Cage nicolas : cages.values()) // sorry - nicolas.destroy(); + slowMode ? 1L : Config.SLOW.DELAY_BETWEEN_TP.get() * 20L + ); } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/ModulesModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/ModulesModule.java new file mode 100644 index 0000000..ab4eec4 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/ModulesModule.java @@ -0,0 +1,93 @@ +/* + * 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.quartzsurvivalgames.modules.core.modules; + +import com.google.common.collect.ImmutableMap; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.commands.ConfigurationCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.commands.ModuleCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.commands.ModulesCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import org.bukkit.Material; +import org.bukkit.entity.Player; + + +@ModuleInfo( + name = "Modules", + description = "Offers to the users a way to manage modules.", + when = ModuleLoadTime.STARTUP, + category = ModuleCategory.CORE, + icon = Material.COMMAND_BLOCK, + can_be_unloaded = false +) +public class ModulesModule extends QSGModule { + @Override + public List<Class<? extends Command>> getCommands() { + return Arrays.asList( + ModulesCommand.class, + ModuleCommand.class, + ConfigurationCommand.class + ); + } + + @Override + public Map<String, Class<? extends Command>> getCommandsAliases() { + return ImmutableMap.of( + "modules", ModulesCommand.class, + "config", ConfigurationCommand.class + ); + } + + @Override + public void injectIntoSidebar(Player player, SidebarInjector injector) { + if (player.isOp() && QSG.module(GameModule.class).getPhase() == GamePhase.WAIT) // TODO Permissions + { + injector.injectLines( + true, + I.t("{gold}To configure the game,"), + I.t("{gold}use {bold}/config") + ); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/commands/ConfigurationCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/commands/ConfigurationCommand.java new file mode 100644 index 0000000..aee2547 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/commands/ConfigurationCommand.java @@ -0,0 +1,49 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.gui.MainConfigGUI; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.gui.Gui; + +@CommandInfo(name = "config") +public class ConfigurationCommand extends Command { + @Override + protected void run() throws CommandException { + Gui.open(playerSender(), new MainConfigGUI()); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/commands/ModuleCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/commands/ModuleCommand.java new file mode 100644 index 0000000..874e8dc --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/commands/ModuleCommand.java @@ -0,0 +1,134 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.commands; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleWrapper; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.text.Normalizer; +import java.util.List; +import java.util.Locale; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import org.bukkit.ChatColor; + +@CommandInfo(name = "module", usageParameters = "enable|disable <module>") +public class ModuleCommand extends Command { + private static final Pattern NON_LATIN = Pattern.compile("[^\\w-]"); + private static final Pattern WHITESPACE = Pattern.compile("[\\s]"); + + /** + * Generates a slug from the (potentially Minecraft-formatted) given string. + * + * @param input The string to convert into a slug. May contain Minecraft + * formatting codes: they will be striped. + * @return The slug. + */ + private static String slug(final String input) { + final String nowhitespace = WHITESPACE.matcher(ChatColor.stripColor(input)).replaceAll("-"); + final String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD); + final String slug = NON_LATIN.matcher(normalized).replaceAll(""); + + return slug.toLowerCase(Locale.ENGLISH); + } + + @Override + protected void run() throws CommandException { + if (args.length < 2 || (!args[0].equalsIgnoreCase("enable") && !args[0].equalsIgnoreCase("disable"))) { + throwInvalidArgument(I.t("Invalid command usage.")); + } + + ModuleWrapper module = null; + + for (final ModuleWrapper m : QSG.get().getModulesManager().getModules()) { + if (getModuleKey(m).equalsIgnoreCase(args[1])) { + module = m; + break; + } + } + + if (module == null) { + throwInvalidArgument(I.t("No module with key {0}. Use autocompletion to get a list of keys.", args[1])); + return; + } + + if (args[0].equalsIgnoreCase("enable")) { + if (module.isEnabled()) { + error(I.t("{red}The module {darkred}{0}{red} is already enabled.", module.getName())); + } else if (module.setEnabled(true)) { + success(I.t("{green}The module {darkgreen}{0}{green} was successfully enabled.", module.getName())); + + if (module.isLoaded()) { + info(I.t("It was also loaded and is now running.")); + } else { + info(I.t("It will be loaded when needed.")); + } + } else { + warning(I.t("{red}Unable to load the module {darkred}{0}{red}.", module.getName())); + info("It is probably too late to enable this module."); + } + } else { + if (!module.isEnabled()) { + error(I.t("{red}he module {darkred}{0}{red} is already disabled.", module.getName())); + } else if (module.setEnabled(false)) { + success(I.t("{green}The module {darkred}{0}{green} was successfully disabled.", module.getName())); + } else { + error(I.t("{red}Unable to disable the module {darkred}{0}{red}. It is probably protected.", + module.getName())); + } + } + } + + @Override + protected List<String> complete() { + if (args.length == 1) { + return getMatchingSubset(args[0], "enable", "disable"); + } else if (args.length == 2) { + return getMatchingSubset( + QSG.get().getModulesManager().getModules().stream() + .filter(module -> args[0].equalsIgnoreCase("enable") != module.isEnabled()) + .map(this::getModuleKey).collect(Collectors.toSet()), args[1]); + } else { + return null; + } + } + + private String getModuleKey(final ModuleWrapper module) { + return slug(module.getName()); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/commands/ModulesCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/commands/ModulesCommand.java new file mode 100644 index 0000000..e24cd45 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/commands/ModulesCommand.java @@ -0,0 +1,165 @@ +/* + * 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.quartzsurvivalgames.modules.core.modules.commands; + +import eu.carrade.amaury.quartzsurvivalgames.QuartzSurvivalGames; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleWrapper; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.commands.Commands; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.components.rawtext.RawText; +import fr.zcraft.quartzlib.components.rawtext.RawTextPart; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Stream; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; + + +@CommandInfo(name = "modules") +public class ModulesCommand extends Command { + @Override + protected void run() throws CommandException { + final Set<ModuleWrapper> modules = new TreeSet<>((module1, module2) -> { + if (module1.equals(module2)) { + return 0; + } + + if (module1.isLoaded() != module2.isLoaded()) { + return module1.isLoaded() ? -1 : 1; + } + if (module1.isEnabled() != module2.isEnabled()) { + return module1.isEnabled() ? -1 : 1; + } + + if (module1.getWhen() != module2.getWhen()) { + return Integer.compare(module1.getWhen().ordinal(), module2.getWhen().ordinal()); + } + + if (module1.isInternal() != module2.isInternal()) { + return module1.isInternal() ? -1 : 1; + } + + return module1.getName().compareTo(module2.getName()); + }); + + modules.addAll(QuartzSurvivalGames.get().getModulesManager().getModules()); + + success(I.tn("{0} module registered {gray}(hover for details)", + "{0} modules registered {gray}(hover for details)", modules.size())); + modules.forEach(module -> { + final List<String> commands = new ArrayList<>(); + + if (module.isLoaded()) { + final List<Class<? extends Command>> commandsClasses = module.get().getCommands(); + if (commandsClasses != null) { + commandsClasses.forEach(clazz -> { + final Command cmd = Commands.getCommandInfo(clazz); + if (cmd != null) { + commands.add(cmd.getUsageString()); + } + }); + } + + final Map<String, Class<? extends Command>> commandsAliases = module.get().getCommandsAliases(); + if (commandsAliases != null) { + commandsAliases.forEach((alias, clazz) -> { + final Command cmd = Commands.getCommandInfo(clazz); + if (cmd != null) { + commands.add( + "/" + alias + " " + cmd.getUsageParameters() + ChatColor.DARK_GRAY + " (alias)"); + } + }); + } + } + + final RawTextPart<?> tooltip = new RawText(); + + tooltip + .then(module.getName()) + .style(ChatColor.BOLD, + module.isLoaded() ? ChatColor.GREEN : (module.isEnabled() ? ChatColor.GOLD : ChatColor.RED)) + .then("\n") + .then(module.isLoaded() ? I.t("Loaded") : I.t("Unloaded")) + .color(ChatColor.GRAY) + .then(" - ") + .color(ChatColor.DARK_GRAY) + .then(module.isEnabled() ? I.t("Enabled") : I.t("Disabled")) + .color(ChatColor.GRAY) + .then("\n\n") + .then(module.getDescription()) + .color(ChatColor.WHITE) + .then("\n\n") + .then(I.t("Load time")) + .color(ChatColor.BLUE) + .then("\n") + .then(module.getWhen().toString()) + .color(ChatColor.WHITE); + + if (!commands.isEmpty()) { + tooltip.then("\n\n").then(I.t("Provided commands")).style(ChatColor.BLUE); + commands.forEach( + command -> tooltip.then("\n- ").style(ChatColor.GRAY).then(command).color(ChatColor.WHITE)); + } + + if (module.getDependencies().length != 0) { + tooltip.then("\n\n").then(I.t("External dependencies")).style(ChatColor.BLUE); + Stream.of(module.getDependencies()).forEach(dep -> tooltip.then("\n- ").style(ChatColor.GRAY).then(dep) + .color(Bukkit.getPluginManager().getPlugin(dep) != null ? ChatColor.WHITE : ChatColor.RED)); + } + + if (module.isInternal()) { + tooltip.then("\n\n").then(I.t("Internal module")).style(ChatColor.DARK_GRAY); + } + if (!module.canBeUnloaded()) { + tooltip.then(module.isInternal() ? " - " : "\n\n").color(ChatColor.DARK_GRAY) + .then(I.t("Cannot be disabled")).color(ChatColor.DARK_GRAY); + } + if (module.isHidden()) { + tooltip.then("\n").then(I.t("Technical module (hidden)")).style(ChatColor.DARK_GRAY); + } + + send(new RawText().hover(tooltip) + .then("• ") + .color(module.isLoaded() ? ChatColor.GREEN : (module.isEnabled() ? ChatColor.GOLD : ChatColor.RED)) + .then(module.getName()).color(ChatColor.WHITE) + .build() + ); + }); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/MainConfigGUI.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/MainConfigGUI.java new file mode 100644 index 0000000..59766e3 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/MainConfigGUI.java @@ -0,0 +1,234 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.gui; + +import eu.carrade.amaury.quartzsurvivalgames.QSGConfig; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleWrapper; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.gui.modules.ModulesListGUI; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.gui.start.StartGameGUI; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.SpectatorsModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.waitingPhase.wait.Config; +import eu.carrade.amaury.quartzsurvivalgames.modules.waitingPhase.wait.WaitModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.gui.ActionGui; +import fr.zcraft.quartzlib.components.gui.Gui; +import fr.zcraft.quartzlib.components.gui.GuiAction; +import fr.zcraft.quartzlib.components.gui.PromptGui; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.items.ItemStackBuilder; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import fr.zcraft.quartzteams.QuartzTeams; +import fr.zcraft.quartzteams.guis.TeamsSelectorGUI; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.scheduler.BukkitTask; + +public class MainConfigGUI extends ActionGui { + private BukkitTask headsCycleTask = null; + private String[] headCycleNames = null; + private int headCycleIndex = 0; + + @Override + protected void onUpdate() { + setTitle(I.tl(getPlayerLocale(), "{black}Game Configuration")); + setHeight(QSG.game().currentPhaseAfter(GamePhase.WAIT) ? 3 : 5); + + final Set<String> alivePlayers = (QSG.game().currentPhaseBefore(GamePhase.IN_GAME) + ? Bukkit.getOnlinePlayers().stream() + .filter(player -> !QSG.module(SpectatorsModule.class).isSpectator(player)) + : QSG.game().getAlivePlayers().stream()) + .map(OfflinePlayer::getName) + .collect(Collectors.toSet()); + + final Set<String> spectators = QSG.module(SpectatorsModule.class).getSpectators().stream() + .map(Bukkit::getOfflinePlayer) + .map(OfflinePlayer::getName) + .collect(Collectors.toSet()); + + headCycleNames = Stream.concat(alivePlayers.stream(), spectators.stream()).toArray(String[]::new); + + action("players", 10, new ItemStackBuilder(Material.PLAYER_HEAD) + .amount(Math.max(alivePlayers.size(), 1)) + .title(ChatColor.GREEN, ChatColor.BOLD + I.tl(getPlayerLocale(), "Players")) + .loreLine( + ChatColor.DARK_GRAY, + I.tln(getPlayerLocale(), "{0} player", "{0} players", alivePlayers.size()), + " - ", + I.tln(getPlayerLocale(), "{0} spectator", "{0} spectators", + QSG.module(SpectatorsModule.class).getSpectators().size()) + ) + .loreSeparator() + .longLore(ChatColor.BLUE, I.tl(getPlayerLocale(), "Players")) + .longLore(ChatColor.GRAY, + alivePlayers.isEmpty() ? ChatColor.DARK_GRAY + I.tl(getPlayerLocale(), "(none)") : + String.join(", ", alivePlayers), 38) + .loreSeparator() + .longLore(ChatColor.BLUE, I.tl(getPlayerLocale(), "Spectators")) + .longLore(ChatColor.GRAY, + spectators.isEmpty() ? ChatColor.DARK_GRAY + I.tl(getPlayerLocale(), "(none)") : + String.join(", ", spectators), 38) + .loreSeparator() + .longLore(ChatColor.DARK_GRAY, + I.tl(getPlayerLocale(), "Actions on players coming soon: in the mean time, use commands."), 38) + ); + + action("teams", 12, new ItemStackBuilder( + QSG.module(WaitModule.class) != null ? Config.TEAM_SELECTOR.ITEM.get() : Material.NETHER_STAR) + .title(ChatColor.AQUA, ChatColor.BOLD + I.tl(getPlayerLocale(), "Teams")) + .amount(Math.max(QuartzTeams.get().countTeams(), 1)) + .loreLine(ChatColor.DARK_GRAY, + I.tln(getPlayerLocale(), "{0} team", "{0} teams", QuartzTeams.get().countTeams())) + .loreSeparator() + .longLore(ChatColor.GRAY, I.tl(getPlayerLocale(), + "The game can either be solo or in teams. In the second case, click here to create or update teams."), + 38) + .loreSeparator() + .longLore( + ChatColor.DARK_GRAY + " » " + I.tl(getPlayerLocale(), "{white}Click {gray}to manage the teams")) + ); + + action("title", 14, new ItemStackBuilder(Material.WRITABLE_BOOK) + .title(ChatColor.DARK_PURPLE, ChatColor.BOLD + I.tl(getPlayerLocale(), "Game Title")) + .loreSeparator() + .longLore(ChatColor.GRAY, I.tl(getPlayerLocale(), + "Click to update the game title. It is displayed on the sidebar and may be used by other modules (like the reports one)."), + 38) + .loreSeparator() + .longLore(ChatColor.BLUE, I.tl(getPlayerLocale(), "Current Title")) + .longLore(QSGConfig.TITLE.get()) + .loreSeparator() + .longLore( + ChatColor.DARK_GRAY + " » " + I.tl(getPlayerLocale(), "{white}Click {gray}to change the title")) + ); + + final int modules = QSG.get().getModulesManager().getModules().size(); + final int modulesEnabled = + (int) QSG.get().getModulesManager().getModules().stream().filter(ModuleWrapper::isEnabled).count(); + final int modulesLoaded = + (int) QSG.get().getModulesManager().getModules().stream().filter(ModuleWrapper::isLoaded).count(); + + action("modules", 16, new ItemStackBuilder(Material.REPEATING_COMMAND_BLOCK) + .title(ChatColor.LIGHT_PURPLE, ChatColor.BOLD + I.tl(getPlayerLocale(), "Modules")) + .loreLine( + ChatColor.DARK_GRAY, + I.tln(getPlayerLocale(), "{0} module", "{0} modules", modules), + " - ", + I.tln(getPlayerLocale(), "{0} enabled", "{0} enabled", modulesEnabled), + " - ", + I.tln(getPlayerLocale(), "{0} loaded", "{0} loaded", modulesLoaded) + ) + .loreSeparator() + .longLore(ChatColor.GRAY, I.tl(getPlayerLocale(), + "This plugin is divided into modules, each one bringing one small or large piece of the game."), + 52) + .loreSeparator() + .lore(ChatColor.DARK_GRAY + " » " + + I.tl(getPlayerLocale(), "{white}Click {gray}to manage modules and their configuration")) + ); + + if (!QSG.game().currentPhaseAfter(GamePhase.WAIT)) { + action("start", 31, new ItemStackBuilder(Material.LIME_DYE) + .title(ChatColor.GREEN, ChatColor.BOLD + I.tl(getPlayerLocale(), "Start the game")) + .longLore(ChatColor.GRAY, I.tl(getPlayerLocale(), "If you're ready, click here to start the game!")) + ); + } + + if (headsCycleTask != null) { + headsCycleTask.cancel(); + } + + headsCycleTask = RunTask.timer(() -> { + final ItemStack skull = getInventory().getItem(10); + if (skull != null) { + // TODO replace with QL 0.1 ISB + final SkullMeta meta = (SkullMeta) getInventory().getItem(10).getItemMeta(); + meta.setOwner(headCycleNames[headCycleIndex]); + getInventory().getItem(10).setItemMeta(meta); + + headCycleIndex = (headCycleIndex + 1) % headCycleNames.length; + if (headCycleIndex < 0) { + headCycleIndex += headCycleNames.length; + } + } + }, 0L, 40L); + } + + @Override + protected void onClose() { + if (headsCycleTask != null) { + headsCycleTask.cancel(); + headsCycleTask = null; + headCycleIndex = 0; + } + + super.onClose(); + } + + @GuiAction + protected void players() { + update(); + } + + + @GuiAction + protected void teams() { + Gui.open(getPlayer(), new TeamsSelectorGUI(), this); + } + + @GuiAction + protected void title() { + PromptGui.prompt(getPlayer(), + newTitle -> QSGConfig.TITLE.set(ChatColor.translateAlternateColorCodes('&', newTitle), false), + QSGConfig.TITLE.get().replace(ChatColor.COLOR_CHAR, '&'), this); + } + + @GuiAction + protected void modules() { + Gui.open(getPlayer(), new ModulesListGUI(), this); + } + + @GuiAction + protected void start() { + Gui.open(getPlayer(), new StartGameGUI()); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/modules/ConfirmModuleDisableGUI.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/modules/ConfirmModuleDisableGUI.java new file mode 100644 index 0000000..44e1272 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/modules/ConfirmModuleDisableGUI.java @@ -0,0 +1,100 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.gui.modules; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleWrapper; +import fr.zcraft.quartzlib.components.gui.GuiAction; +import fr.zcraft.quartzlib.components.gui.GuiUtils; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.items.ItemStackBuilder; +import fr.zcraft.quartzlib.tools.mojang.MojangHead; +import java.util.List; +import java.util.stream.Collectors; +import org.bukkit.ChatColor; +import org.bukkit.Material; + +public class ConfirmModuleDisableGUI extends FramedModuleGUI { + public ConfirmModuleDisableGUI(final ModuleWrapper module) { + super(module); + } + + @Override + protected void onUpdate() { + setTitle(I.t("{darkgray}{0} » {black}Disable", module.getName())); + setSize(5 * 9); + + final List<String> title = + GuiUtils.generateLore(I.t("If you disable this module, you won't be able to re-enable it."), 38); + final String firstTitleLine = title.get(0); + + title.remove(0); + + action("", 22, MojangHead.QUESTION.asItemBuilder() + .title(ChatColor.RED, ChatColor.BOLD + firstTitleLine) + .lore(title.stream().map(line -> ChatColor.RED + "" + ChatColor.BOLD + line) + .collect(Collectors.toList())) + .loreSeparator() + .longLore(ChatColor.GRAY, + I.t("This module cannot be re-loaded after its original load period. This means that if you disable this module, you won't be able to re-enable it during this game."), + 38) + .longLore(ChatColor.WHITE, I.t("Are you sure you want to disable {0}?", module.getName()), 38) + .item()); + + final ItemStackBuilder no = new ItemStackBuilder(Material.RED_STAINED_GLASS_PANE) + .title(ChatColor.GREEN, ChatColor.BOLD + I.t("I changed my mind")) + .longLore(ChatColor.GRAY, I.t("Go back without disabling the module")); + + final ItemStackBuilder yes = new ItemStackBuilder(Material.LIME_STAINED_GLASS_PANE) + .title(ChatColor.RED, ChatColor.BOLD + I.t("Yes, disable")) + .longLore(ChatColor.GRAY, + I.t("Disable {0} without any possibility of re-enabling it", module.getName())); + + for (int slot : new int[] {10, 11, 19, 20, 28, 29}) { + action("cancel", slot, no); + action("disable", slot + 5, yes); + } + } + + @GuiAction + protected void cancel() { + close(); + } + + @GuiAction + protected void disable() { + module.setEnabled(false); + close(); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/modules/FramedModuleGUI.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/modules/FramedModuleGUI.java new file mode 100644 index 0000000..105749f --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/modules/FramedModuleGUI.java @@ -0,0 +1,73 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.gui.modules; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleWrapper; +import fr.zcraft.quartzlib.components.gui.ActionGui; +import fr.zcraft.quartzlib.tools.items.ColorableMaterial; +import fr.zcraft.quartzlib.tools.items.ItemStackBuilder; +import fr.zcraft.quartzlib.tools.items.ItemUtils; +import org.bukkit.inventory.ItemStack; + +public abstract class FramedModuleGUI extends ActionGui { + protected final ModuleWrapper module; + + public FramedModuleGUI(ModuleWrapper module) { + this.module = module; + } + + @Override + protected void onAfterUpdate() { + final ItemStack framePart = + new ItemStackBuilder(ItemUtils.colorize(ColorableMaterial.STAINED_GLASS_PANE, module.getCategory().getColor())) + .title("") + .item(); + + // Top and bottom + for (int slot = 0; slot < 9; slot++) { + action("", slot, framePart); + action("", getSize() - (slot + 1), framePart); + } + + // Sides + for (int line = 0; line < getSize() / 9; line++) { + action("", line * 9, framePart); + action("", line * 9 + 8, framePart); + } + + // Icon + action("__module_icon__", 4, module.getFullIcon(false)); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/modules/ModulesListGUI.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/modules/ModulesListGUI.java new file mode 100644 index 0000000..ad9b9ca --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/modules/ModulesListGUI.java @@ -0,0 +1,292 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.gui.modules; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleWrapper; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.components.gui.ExplorerGui; +import fr.zcraft.quartzlib.components.gui.Gui; +import fr.zcraft.quartzlib.components.gui.GuiAction; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.items.ColorableMaterial; +import fr.zcraft.quartzlib.tools.items.ItemStackBuilder; +import fr.zcraft.quartzlib.tools.items.ItemUtils; +import fr.zcraft.quartzlib.tools.mojang.MojangHead; +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; + +public class ModulesListGUI extends ExplorerGui<ModuleWrapper> { + /** + * The category filtered. {@code null} means all. + */ + private ModuleCategory filterCategory; + private StateFilter filterState = StateFilter.ALL; + + public ModulesListGUI() { + this(null); + } + + public ModulesListGUI(final ModuleCategory filterCategory) { + this.filterCategory = filterCategory; + } + + @Override + protected void onUpdate() { + setSize(6 * 9); + setMode(Mode.READONLY); + setKeepHorizontalScrollingSpace(true); + + final ModuleWrapper[] modules = QSG.get().getModulesManager().getModules().stream() + .filter(module -> !module.isHidden()) + .filter(module -> filterCategory == null || module.getCategory() == filterCategory) + .filter(module -> { + switch (filterState) { + case ALL: + return true; + + case ENABLED: + return module.isEnabled(); + + case LOADED: + return module.isLoaded(); + + case DISABLED: + default: + return !module.isEnabled(); + } + }) + .sorted((module1, module2) -> { + if (module1.equals(module2)) { + return 0; + } + + if (module1.getCategory() != module2.getCategory()) { + return Integer.compare(module1.getCategory().ordinal(), module2.getCategory().ordinal()); + } + + if (module1.getWhen() != module2.getWhen()) { + return Integer.compare(module1.getWhen().ordinal(), module2.getWhen().ordinal()); + } + + if (module1.isInternal() != module2.isInternal()) { + return module1.isInternal() ? -1 : 1; + } + + return module1.getName().compareTo(module2.getName()); + }) + .toArray(ModuleWrapper[]::new); + + setData(modules); + + + // Sets the title + + if (filterCategory == null) { + setTitle(I.t("{black}All modules {darkgray}({0})", QSG.get().getModulesManager().getModules().size())); + } else { + setTitle(ChatColor.BLACK + filterCategory.getDisplayName() + ChatColor.DARK_GRAY + + String.format(" (%d / %d)", modules.length, QSG + .get().getModulesManager().getModules().size())); + } + + + // Displays the bottom bar of color + + final ItemStackBuilder bottomColorStripe = new ItemStackBuilder() + .material(ItemUtils.colorize(ColorableMaterial.STAINED_GLASS_PANE, filterCategory != null ? filterCategory.getColor() : ChatColor.WHITE)) + .title(filterCategory != null ? filterCategory.getColor() + "" + ChatColor.BOLD + filterCategory.getDisplayName() : ""); + + if (filterCategory != null) { + bottomColorStripe.longLore(ChatColor.GRAY, filterCategory.getDescription(), 38); + } + + for (int slot = getSize() - 9; slot < getSize(); slot++) { + action("", slot, bottomColorStripe); + } + + + final String prefixActive = ChatColor.YELLOW + "» "; + final String prefixInactive = ChatColor.DARK_GRAY + "» " + ChatColor.GRAY; + + + // Displays the category filter button + + final Material endCrystal = Material.getMaterial("END_CRYSTAL"); + final ItemStackBuilder catFilter = new ItemStackBuilder( + filterCategory == null ? new ItemStack(endCrystal != null ? endCrystal : Material.HOPPER) : + filterCategory.getIcon()) + .title(ChatColor.YELLOW, ChatColor.BOLD + I.t("Filter modules category")) + .loreSeparator(); + + catFilter.loreLine((filterCategory == null ? prefixActive : prefixInactive) + I.t("All modules")); + + for (ModuleCategory category : ModuleCategory.values()) { + catFilter + .loreLine((filterCategory == category ? prefixActive : prefixInactive) + category.getDisplayName()); + } + + catFilter.loreSeparator(); + catFilter.longLore(ChatColor.WHITE, filterCategory == null ? + I.t("Click to filter the modules by category. A description will be displayed here.") : + filterCategory.getDescription(), 38); + + action("switch_category", getSize() - 5, catFilter); + + + // Displays the state filter button + + final ItemStackBuilder stateFilter = new ItemStackBuilder(ItemUtils.colorize(ColorableMaterial.DYE, filterState.color)) + .title(ChatColor.YELLOW, ChatColor.BOLD + I.tl(getPlayerLocale(), "Filter modules state")) + .loreSeparator(); + + for (StateFilter filter : StateFilter.values()) { + stateFilter.loreLine(filterState == filter ? prefixActive : prefixInactive, filter.displayName); + } + + stateFilter.loreSeparator(); + stateFilter.longLore(ChatColor.WHITE, I.tl(getPlayerLocale(), + "Click here to filter by state. Loaded modules are currently running. Enabled ones are running or will run when needed. Disabled modules will never run."), + 48); + + action("switch_status", getSize() - 7, stateFilter); + + + // Displays the back button + + action("quit", getSize() - 3, MojangHead.ARROW_LEFT.asItemBuilder() + .title(ChatColor.GREEN, ChatColor.BOLD + + (getParent() != null ? I.tl(getPlayerLocale(), "Go Back") : I.tl(getPlayerLocale(), "Close"))) + .longLore(ChatColor.GRAY, I.tl(getPlayerLocale(), + "Click here to close this GUI and go back. You can also press “Escape”.")) + ); + } + + @Override + protected ItemStack getViewItem(final ModuleWrapper module) { + final ItemStackBuilder item = module.getFullIcon(false).loreSeparator(); + final String prefix = ChatColor.DARK_GRAY + "» "; + + if (!module.isEnabled()) { + if (module.canBeEnabled()) { + item.lore(prefix + I.t("{white}Click {gray}to enable this module")); + } else { + item.lore(prefix + I.t("{red}This module can no longer be enabled.")); + } + } else { + if (module.canBeDisabled()) { + item.lore(prefix + I.t("{white}Click {gray}to disable this module")); + } else { + item.lore(prefix + I.t("{red}This module cannot be disabled.")); + } + } + + item.lore(prefix + I.t("{white}Right click {gray}to access details and config")); + + return item.item(); + } + + + /** + * On left click + * + * @param module Clicked module + */ + @Override + protected ItemStack getPickedUpItem(final ModuleWrapper module) { + if (module.isEnabled() && !module.canBeEnabled()) { + Gui.open(getPlayer(), new ConfirmModuleDisableGUI(module), this); + } else { + if (module.setEnabled(!module.isEnabled())) { + if (module.isEnabled()) { + QSG.log().broadcastAdministrativePrefixed( + I.t("{yellow}{0} {green}enabled {yellow}the module {1}.", getPlayer().getName(), + module.getName())); + } else { + QSG.log().broadcastAdministrativePrefixed( + I.t("{yellow}{0} {red}disabled {yellow}the module {1}.", getPlayer().getName(), + module.getName())); + } + } + + update(); + } + + return null; + } + + @Override + protected void onRightClick(final ModuleWrapper module) { + // TODO open details-gui + } + + @GuiAction + protected void switch_category(final InventoryClickEvent ev) { + filterCategory = QSGUtils + .getNextElement(filterCategory, ev.getClick() == ClickType.RIGHT ? -1 : 1, true, ModuleCategory.class); + update(); + } + + @GuiAction + protected void switch_status(final InventoryClickEvent ev) { + filterState = QSGUtils.getNextElement(filterState, ev.getClick() == ClickType.RIGHT ? -1 : 1); + update(); + } + + @GuiAction + protected void quit() { + close(); + } + + private enum StateFilter { + ALL(DyeColor.PURPLE, I.t("All modules")), + ENABLED(DyeColor.PINK, I.t("Enabled modules")), + LOADED(DyeColor.LIME, I.t("Loaded modules")), + DISABLED(DyeColor.GRAY, I.t("Disabled modules")); + + private final DyeColor color; + private final String displayName; + + StateFilter(DyeColor color, String displayName) { + this.color = color; + this.displayName = displayName; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/start/StartGameGUI.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/start/StartGameGUI.java new file mode 100644 index 0000000..0c5148e --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/modules/gui/start/StartGameGUI.java @@ -0,0 +1,135 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.gui.start; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.teleporter.TeleportationMode; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.gui.MainConfigGUI; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.components.gui.ActionGui; +import fr.zcraft.quartzlib.components.gui.Gui; +import fr.zcraft.quartzlib.components.gui.GuiAction; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.items.ItemStackBuilder; +import fr.zcraft.quartzlib.tools.mojang.MojangHead; +import fr.zcraft.quartzteams.QuartzTeams; +import org.bukkit.ChatColor; +import org.bukkit.Material; + +public class StartGameGUI extends ActionGui { + private TeleportationMode mode = TeleportationMode.NORMAL; + + @Override + protected void onUpdate() { + setHeight(5); + setTitle(I.tl(getPlayerLocale(), "{black}Ready to start the game?")); + + final String prefixActive = ChatColor.YELLOW + "» "; + final String prefixInactive = ChatColor.DARK_GRAY + "» " + ChatColor.GRAY; + + action("fast", 11, new ItemStackBuilder(Material.MAGMA_CREAM) + .title(ChatColor.DARK_GREEN, ChatColor.BOLD + I.tl(getPlayerLocale(), "Fast Start")) + .loreSeparator() + .longLore(ChatColor.GRAY, I.tl(getPlayerLocale(), + "Click here to start the game immediately. Players will be teleported at once (thus loading a lot of chunks in a few seconds) and the countdown will begin immediately after."), + 52) + ); + + action("slow", 15, new ItemStackBuilder(Material.SLIME_BALL) + .title(ChatColor.GREEN, ChatColor.BOLD + I.tl(getPlayerLocale(), "Slow Start")) + .loreSeparator() + .longLore(ChatColor.GRAY, I.tl(getPlayerLocale(), + "If your server is a little bit small, use this option to teleport players slowly, loading the chunks one player at a time. You'll have to confirm the game start using a link in the chat."), + 52) + ); + + if (QuartzTeams.get().countTeams() > 0) { + action("teleportation_mode", 13, new ItemStackBuilder() + .material(mode == TeleportationMode.NORMAL ? Material.SUGAR : Material.GLOWSTONE_DUST) + .title(ChatColor.YELLOW, ChatColor.BOLD + I.tl(getPlayerLocale(), "Teleportation Mode")) + .loreSeparator() + .loreLine(mode == TeleportationMode.NORMAL ? prefixActive : prefixInactive, + I.tl(getPlayerLocale(), "Teams together")) + .longLore(mode == TeleportationMode.NORMAL ? ChatColor.GRAY : ChatColor.DARK_GRAY, + I.tl(getPlayerLocale(), + "Teams are teleported to a shared spawn point. Teammates start together."), 38) + .loreSeparator() + .loreLine(mode == TeleportationMode.IGNORE_TEAMS ? prefixActive : prefixInactive, + I.tl(getPlayerLocale(), "Ignoring teams")) + .longLore(mode == TeleportationMode.NORMAL ? ChatColor.GRAY : ChatColor.DARK_GRAY, + I.tl(getPlayerLocale(), + "Players will be alone at the beginning, even if they are in a team."), 38) + ); + } + + action("back", 31, MojangHead.ARROW_LEFT.asItemBuilder() + .title(ChatColor.RED, ChatColor.BOLD + I.tl(getPlayerLocale(), "Go Back")) + .loreSeparator() + .longLore(ChatColor.GRAY, I.tl(getPlayerLocale(), + "Changed your mind? No problem, click here to go back without starting the game."), 38) + ); + } + + @GuiAction + protected void teleportation_mode() { + mode = QSGUtils.getNextElement(mode, 1); + update(); + } + + @GuiAction + protected void fast() { + start(false); + close(); + } + + @GuiAction + protected void slow() { + start(true); + close(); + } + + private void start(final boolean slow) { + QSG.game().setTeleportationMode(mode); + QSG.game().setSlowMode(slow); + + QSG.game().setPhase(GamePhase.STARTING); + } + + @GuiAction + protected void back() { + Gui.open(getPlayer(), new MainConfigGUI()); + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamGUICommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/sidebar/GameSidebar.java similarity index 54% rename from src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamGUICommand.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/sidebar/GameSidebar.java index 5226fee..052af15 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamGUICommand.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/sidebar/GameSidebar.java @@ -29,54 +29,48 @@ * 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.commands.commands.uh.team; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import eu.carrade.amaury.UHCReloaded.gui.teams.TeamsSelectorGUI; -import fr.zcraft.zlib.components.gui.Gui; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar; -import java.util.Collections; +import eu.carrade.amaury.quartzsurvivalgames.QSGConfig; +import eu.carrade.amaury.quartzsurvivalgames.QuartzSurvivalGames; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleWrapper; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import fr.zcraft.quartzlib.components.scoreboard.Sidebar; +import fr.zcraft.quartzlib.components.scoreboard.SidebarMode; import java.util.List; +import org.bukkit.entity.Player; -@Command (name = "gui", noPermission = true, inheritPermission = false) -public class UHTeamGUICommand extends AbstractCommand -{ - public UHTeamGUICommand(UHCReloaded plugin) {} - - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (!(sender instanceof Player)) - { - throw new CannotExecuteCommandException(CannotExecuteCommandException.Reason.ONLY_AS_A_PLAYER, this); - } - - Gui.open((Player) sender, new TeamsSelectorGUI()); +public class GameSidebar extends Sidebar { + public GameSidebar() { + setAutoRefreshDelay(10); + setTitleMode(SidebarMode.GLOBAL); + setContentMode(SidebarMode.PER_PLAYER); } @Override - public List<String> tabComplete(CommandSender sender, String[] args) - { - return null; + public void preRender() { + QuartzSurvivalGames.get().getModulesManager().getModules().stream() + .filter(ModuleWrapper::isLoaded) + .map(ModuleWrapper::get) + .forEach(QSGModule::prepareInjectionIntoSidebar); } @Override - public List<String> help(CommandSender sender) - { - return null; + public List<String> getContent(Player player) { + final SidebarInjector injector = new SidebarInjector(); + + QuartzSurvivalGames.get().getModulesManager().getModules().stream() + .filter(ModuleWrapper::isLoaded) + .map(ModuleWrapper::get) + .forEach(module -> module.injectIntoSidebar(player, injector)); + + return injector.buildLines(); } @Override - public List<String> onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh team gui {ci}: opens a GUI to join and manage the teams.")); + public String getTitle(Player player) { + return QSGConfig.TITLE.get(); } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/sidebar/SidebarInjector.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/sidebar/SidebarInjector.java new file mode 100644 index 0000000..8e21a54 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/sidebar/SidebarInjector.java @@ -0,0 +1,321 @@ +/* + * 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.quartzsurvivalgames.modules.core.sidebar; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + + +/** + * An instance of this class will be passed to each modules to add for a given player lines to the sidebar. + */ +public class SidebarInjector { + private final Set<LinesBucket> buckets = new TreeSet<>(new LinesBucketComparator()); + + /** + * Injects lines into the sidebar. + * + * @param priority The lines priority to order all injected lines. + * @param spacesAbove {@code true} to add a space above the given lines (if not first) + * @param spacesBelow {@code true} to add a space below the given lines (if not last) + * @param lines The lines (from top to bottom). + * @return current instance, for methods chaining. + */ + public SidebarInjector injectLines(final SidebarPriority priority, final boolean spacesAbove, + final boolean spacesBelow, final Collection<String> lines) { + buckets.add(new LinesBucket(priority, spacesAbove, spacesBelow, new LinkedList<>(lines))); + return this; + } + + /** + * Injects lines into the sidebar. + * + * @param priority The lines priority to order all injected lines. + * @param spacesAbove {@code true} to add a space above the given lines (if not first) + * @param spacesBelow {@code true} to add a space below the given lines (if not last) + * @param lines The lines (from top to bottom). + * @return current instance, for methods chaining. + */ + public SidebarInjector injectLines(final SidebarPriority priority, final boolean spacesAbove, + final boolean spacesBelow, final String... lines) { + injectLines(priority, spacesAbove, spacesBelow, Arrays.asList(lines)); + return this; + } + + /** + * Injects lines into the sidebar. + * + * @param priority The lines priority to order all injected lines. + * @param spacesAround {@code true} to add a space above and below the given lines (if not first/last) + * @param lines The lines (from top to bottom). + * @return current instance, for methods chaining. + */ + public SidebarInjector injectLines(final SidebarPriority priority, final boolean spacesAround, + final Collection<String> lines) { + injectLines(priority, spacesAround, spacesAround, lines); + return this; + } + + /** + * Injects lines into the sidebar. + * + * @param priority The lines priority to order all injected lines. + * @param spacesAround {@code true} to add a space above and below the given lines (if not first/last) + * @param lines The lines (from top to bottom). + * @return current instance, for methods chaining. + */ + public SidebarInjector injectLines(final SidebarPriority priority, final boolean spacesAround, + final String... lines) { + injectLines(priority, spacesAround, spacesAround, Arrays.asList(lines)); + return this; + } + + /** + * Injects lines into the sidebar. No spaces are added before or after. + * + * @param priority The lines priority to order all injected lines. + * @param lines The lines (from top to bottom). + * @return current instance, for methods chaining. + */ + public SidebarInjector injectLines(final SidebarPriority priority, final Collection<String> lines) { + injectLines(priority, false, false, lines); + return this; + } + + /** + * Injects lines into the sidebar. No spaces are added before or after. + * + * @param priority The lines priority to order all injected lines. + * @param lines The lines (from top to bottom). + * @return current instance, for methods chaining. + */ + public SidebarInjector injectLines(final SidebarPriority priority, final String... lines) { + injectLines(priority, false, false, Arrays.asList(lines)); + return this; + } + + /** + * Injects lines into the sidebar without constrain on placement. + * + * @param spacesAbove {@code true} to add a space above the given lines (if not first) + * @param spacesBelow {@code true} to add a space below the given lines (if not last) + * @param lines The lines (from top to bottom). + * @return current instance, for methods chaining. + */ + public SidebarInjector injectLines(final boolean spacesAbove, final boolean spacesBelow, + final Collection<String> lines) { + injectLines(SidebarPriority.MIDDLE, spacesAbove, spacesBelow, lines); + return this; + } + + /** + * Injects lines into the sidebar without constrain on placement. + * + * @param spacesAbove {@code true} to add a space above the given lines (if not first) + * @param spacesBelow {@code true} to add a space below the given lines (if not last) + * @param lines The lines (from top to bottom). + * @return current instance, for methods chaining. + */ + public SidebarInjector injectLines(final boolean spacesAbove, final boolean spacesBelow, final String... lines) { + injectLines(SidebarPriority.MIDDLE, spacesAbove, spacesBelow, Arrays.asList(lines)); + return this; + } + + /** + * Injects lines into the sidebar without constrain on placement. + * + * @param spacesAround {@code true} to add a space above and below the given lines (if not first/last) + * @param lines The lines (from top to bottom). + * @return current instance, for methods chaining. + */ + public SidebarInjector injectLines(final boolean spacesAround, final Collection<String> lines) { + injectLines(SidebarPriority.MIDDLE, spacesAround, spacesAround, lines); + return this; + } + + /** + * Injects lines into the sidebar without constrain on placement. + * + * @param spacesAround {@code true} to add a space above and below the given lines (if not first/last) + * @param lines The lines (from top to bottom). + * @return current instance, for methods chaining. + */ + public SidebarInjector injectLines(final boolean spacesAround, final String... lines) { + injectLines(SidebarPriority.MIDDLE, spacesAround, spacesAround, Arrays.asList(lines)); + return this; + } + + /** + * Injects lines into the sidebar without constrain on placement. No spaces are added before or after. + * + * @param lines The lines (from top to bottom). + * @return current instance, for methods chaining. + */ + public SidebarInjector injectLines(final Collection<String> lines) { + injectLines(SidebarPriority.MIDDLE, false, false, lines); + return this; + } + + /** + * Injects lines into the sidebar without constrain on placement. No spaces are added before or after. + * + * @param lines The lines (from top to bottom). + * @return current instance, for methods chaining. + */ + public SidebarInjector injectLines(final String... lines) { + injectLines(SidebarPriority.MIDDLE, false, false, Arrays.asList(lines)); + return this; + } + + /** + * Builds the lines for the sidebar according to the priorities and the spaces requirements. + * <p> + * Does not adds multiple empty lines if one bucket requiring spaces below is followed by one + * requiring spaces above. + * + * @return a list of lines ready to be used by the sidebar. + */ + public List<String> buildLines() { + final LinkedList<String> lines = new LinkedList<>(); + + // Initially to true so for the first one, if there is a space above, it's not added. + boolean lastInsertedASpace = true; + + for (final LinesBucket bucket : buckets) { + if (bucket.spaceAbove && !lastInsertedASpace) { + lines.add(""); + } + + lines.addAll(bucket.lines); + + if (bucket.spaceBelow) { + lines.add(""); + lastInsertedASpace = true; + } else { + lastInsertedASpace = false; + } + } + + if (lines.getLast().equals("")) { + lines.removeLast(); + } + + return lines; + } + + /** + * The priority is used to order the lines given by various modules in the + * sidebar. Lines in the same priority bucket will be displayed in an order + * dependant on the modules's loading order. + */ + public enum SidebarPriority { + /** + * Places the lines at the very top of the scoreboard. + */ + VERY_TOP, + + /** + * Places the lines on the top part of the scoreboard. + */ + TOP, + + /** + * Places the lines somewhere between the top and the middle. + */ + MIDDLE_TOP, + + /** + * Places the lines at the middle, without any strong preferences on placement. + */ + MIDDLE, + + /** + * Places the lines somewhere between the middle and the bottom. + */ + MIDDLE_BOTTOM, + + /** + * Places the lines on the bottom part of the scoreboard. + */ + BOTTOM, + + /** + * Places the lines at the very bottom of the scoreboard. + */ + VERY_BOTTOM + } + + /** + * Represents a packet of lines added to the scoreboard. + */ + private static class LinesBucket { + private static int inserts = 0; + + private final int insertOrder; + private final SidebarPriority priority; + private final boolean spaceAbove; + private final boolean spaceBelow; + private final List<String> lines; + + private LinesBucket(final SidebarPriority priority, final boolean spaceAbove, final boolean spaceBelow, + final List<String> lines) { + this.insertOrder = ++inserts; + + this.priority = priority; + this.spaceAbove = spaceAbove; + this.spaceBelow = spaceBelow; + this.lines = lines; + } + } + + /** + * Comparator for {@link LinesBucket}. + */ + protected class LinesBucketComparator implements Comparator<LinesBucket> { + @Override + public int compare(final LinesBucket bucket1, final LinesBucket bucket2) { + final int priorityComparison = Integer.compare(bucket1.priority.ordinal(), bucket2.priority.ordinal()); + + if (priorityComparison != 0) { + return priorityComparison; + } else { + return Integer.compare(bucket1.insertOrder, bucket2.insertOrder); + } + } + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditColorGUI.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/sidebar/SidebarModule.java similarity index 58% rename from src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditColorGUI.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/sidebar/SidebarModule.java index 7eee0e9..12be0a2 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditColorGUI.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/sidebar/SidebarModule.java @@ -29,37 +29,40 @@ * 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.gui.teams.editor; -import eu.carrade.amaury.UHCReloaded.gui.teams.builder.TeamBuilderStepColorGUI; -import eu.carrade.amaury.UHCReloaded.teams.TeamColor; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import fr.zcraft.zlib.components.gui.Gui; -import fr.zcraft.zlib.components.i18n.I; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; -public class TeamEditColorGUI extends TeamBuilderStepColorGUI -{ - private final UHTeam team; - public TeamEditColorGUI(UHTeam team) - { - this.team = team; - } +@ModuleInfo( + name = "Sidebar", + description = "Manages the sidebar and allows hooks for all modules into it.", + category = ModuleCategory.CORE, + icon = Material.WRITABLE_BOOK, + internal = true, + can_be_unloaded = false +) +public class SidebarModule extends QSGModule { + private GameSidebar sidebar; @Override - protected void onUpdate() - { - /// The title of the edit team color GUI. {0} = team name (raw). - setTitle(I.t("{0} » {black}Color", team.getName())); - setSize(6 * 9); - insertColors(2); + protected void onEnable() { + sidebar = new GameSidebar(); + sidebar.runAutoRefresh(true); + + Bukkit.getOnlinePlayers().forEach(player -> sidebar.addRecipient(player)); } - @Override - protected void saveColor(TeamColor color) - { - team.setColor(color); - Gui.open(getPlayer(), new TeamEditGUI(team), getParent().getParent()); + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerJoin(final PlayerJoinEvent ev) { + sidebar.addRecipient(ev.getPlayer()); } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/LeaveCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/Config.java similarity index 66% rename from src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/LeaveCommand.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/Config.java index 92d6f8e..c6f09dd 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/LeaveCommand.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/Config.java @@ -29,19 +29,23 @@ * 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.commands.commands; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.uh.team.UHTeamLeaveCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.list; -// The permissions are too complex, we need to manage them manually. -@Command (name = "leave", noPermission = true, inheritPermission = false) -public class LeaveCommand extends UHTeamLeaveCommand -{ - public LeaveCommand(UHCReloaded plugin) - { - super(plugin); +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.configuration.ConfigurationList; +import java.io.File; +import org.bukkit.Location; + + +public class Config extends ConfigurationInstance { + public static final ConfigurationItem<Boolean> AVOID_WATER = item("avoid-water", true); + public static final ConfigurationList<Location> SPAWN_POINTS = list("spawn-points", Location.class); + public Config(File file) { + super(file); } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/Generator.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/Generator.java similarity index 68% rename from src/main/java/eu/carrade/amaury/UHCReloaded/spawns/Generator.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/Generator.java index 8351b77..66c0f83 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/Generator.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/Generator.java @@ -30,22 +30,20 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.spawns; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns; -import eu.carrade.amaury.UHCReloaded.spawns.generators.CircularSpawnPointsGenerator; -import eu.carrade.amaury.UHCReloaded.spawns.generators.GridSpawnPointsGenerator; -import eu.carrade.amaury.UHCReloaded.spawns.generators.RandomSpawnPointsGenerator; -import eu.carrade.amaury.UHCReloaded.spawns.generators.SpawnPointsGenerator; -import fr.zcraft.zlib.tools.PluginLogger; -import fr.zcraft.zlib.tools.reflection.Reflection; - +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.generators.CircularSpawnPointsGenerator; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.generators.GridSpawnPointsGenerator; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.generators.RandomSpawnPointsGenerator; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.generators.SpawnPointsGenerator; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.reflection.Reflection; import java.lang.reflect.InvocationTargetException; import java.util.logging.Level; -public enum Generator -{ +public enum Generator { /** * Spawn points generated randomly. */ @@ -64,13 +62,12 @@ public enum Generator CIRCULAR(CircularSpawnPointsGenerator.class); - private Class<? extends SpawnPointsGenerator> generatorClass; + private final Class<? extends SpawnPointsGenerator> generatorClass; /** * @param generatorClass The generator. */ - Generator(Class<? extends SpawnPointsGenerator> generatorClass) - { + Generator(Class<? extends SpawnPointsGenerator> generatorClass) { this.generatorClass = generatorClass; } @@ -82,14 +79,11 @@ public enum Generator * @param name The name. * @return The Generator, or null if not found. */ - public static Generator fromString(String name) - { - try - { + public static Generator fromString(String name) { + try { return Generator.valueOf(name.trim().toUpperCase()); } - catch (IllegalArgumentException e) - { + catch (IllegalArgumentException e) { return null; } } @@ -99,20 +93,19 @@ public static Generator fromString(String name) * * @return The instance. */ - public SpawnPointsGenerator getInstance() - { - try - { + public SpawnPointsGenerator getInstance() { + try { return Reflection.instantiate(generatorClass); } - catch (NoSuchMethodException | InstantiationException | IllegalAccessException e) - { - PluginLogger.log(Level.SEVERE, "Cannot instantiate the spawn points generator: invalid class (missing constructor?): " + generatorClass.getName(), e.getCause()); + catch (NoSuchMethodException | InstantiationException | IllegalAccessException e) { + PluginLogger.log(Level.SEVERE, + "Cannot instantiate the spawn points generator: invalid class (missing constructor?): " + + generatorClass.getName(), e.getCause()); return null; } - catch (InvocationTargetException e) - { - PluginLogger.log(Level.SEVERE, "Error during the spawn points generator instantiation: " + generatorClass.getName(), e.getCause()); + catch (InvocationTargetException e) { + PluginLogger.log(Level.SEVERE, + "Error during the spawn points generator instantiation: " + generatorClass.getName(), e.getCause()); return null; } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/SpawnsManager.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/SpawnsModule.java similarity index 55% rename from src/main/java/eu/carrade/amaury/UHCReloaded/spawns/SpawnsManager.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/SpawnsModule.java index 728250c..abac9ca 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/SpawnsManager.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/SpawnsModule.java @@ -30,38 +30,55 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.spawns; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.spawns.exceptions.CannotGenerateSpawnPointsException; -import eu.carrade.amaury.UHCReloaded.spawns.exceptions.UnknownGeneratorException; -import eu.carrade.amaury.UHCReloaded.spawns.generators.SpawnPointsGenerator; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.World.Environment; -import org.bukkit.util.Vector; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns; +import eu.carrade.amaury.quartzsurvivalgames.QuartzSurvivalGames; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.BorderModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start.BeforeTeleportationPhaseEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.commands.SpawnsCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.exceptions.CannotGenerateSpawnPointsException; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.exceptions.UnknownGeneratorException; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.generators.SpawnPointsGenerator; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzteams.QuartzTeams; +import java.util.Collections; import java.util.LinkedList; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.event.EventHandler; +import org.bukkit.util.Vector; -public class SpawnsManager -{ - private final boolean AVOID_WATER; - - private UHCReloaded p; - private LinkedList<Location> spawnPoints = new LinkedList<>(); - +@ModuleInfo( + name = "Spawns", + description = "Manages the spawn points and allow users to generate them randomly.", + category = ModuleCategory.CORE, + icon = Material.MAP, + settings = Config.class, + internal = true, + can_be_unloaded = false +) +public class SpawnsModule extends QSGModule { + private final List<Location> spawnPoints = new LinkedList<>(); - public SpawnsManager(UHCReloaded plugin) - { - this.p = plugin; + @Override + protected void onEnable() { + spawnPoints.addAll(Config.SPAWN_POINTS); + } - AVOID_WATER = UHConfig.MAP.SPAWN_POINTS.DONT_GENERATE_ABOVE_WATER.get(); + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(SpawnsCommand.class); } /** @@ -69,20 +86,18 @@ public SpawnsManager(UHCReloaded plugin) * * @param vec The vector representing the X and Z coordinates. */ - public void addSpawnPoint(final Vector vec) - { - addSpawnPoint(p.getServer().getWorlds().get(0), vec.getX(), vec.getZ()); + public void addSpawnPoint(final Vector vec) { + addSpawnPoint(QuartzSurvivalGames.get().getWorld(World.Environment.NORMAL), vec.getX(), vec.getZ()); } - + /** * Adds a spawn point at (x;z) in the default world. * * @param x The X coordinate. * @param z The Z coordinate. */ - public void addSpawnPoint(final Double x, final Double z) - { - addSpawnPoint(p.getServer().getWorlds().get(0), x, z); + public void addSpawnPoint(final Double x, final Double z) { + addSpawnPoint(QuartzSurvivalGames.get().getWorld(World.Environment.NORMAL), x, z); } /** @@ -92,8 +107,7 @@ public void addSpawnPoint(final Double x, final Double z) * @param x The X coordinate. * @param z The Z coordinate. */ - public void addSpawnPoint(final World world, final Double x, final Double z) - { + public void addSpawnPoint(final World world, final Double x, final Double z) { addSpawnPoint(new Location(world, x, 0, z)); } @@ -102,33 +116,26 @@ public void addSpawnPoint(final World world, final Double x, final Double z) * * @param location The location. Cloned, so you can use the same location object with * modifications between two calls. - * * @throws RuntimeException If the spawn point is in the Nether and no safe spot was * found. * @throws IllegalArgumentException If the spawn point is out of the current border. */ - public void addSpawnPoint(final Location location) - { - Location spawnPoint = location.clone(); + public void addSpawnPoint(final Location location) { + final Location spawnPoint = location.clone(); // Initial fall, except in the nether. - if (!(spawnPoint.getWorld().getEnvironment() == Environment.NETHER)) - { + if (!(spawnPoint.getWorld().getEnvironment() == World.Environment.NETHER)) { spawnPoint.setY(location.getWorld().getHighestBlockYAt(location.getBlockX(), location.getBlockZ()) + 120); - } - else - { - Location safeSpot = UHUtils.searchSafeSpot(location); - if (safeSpot == null) - { + } else { + final Location safeSpot = QSGUtils.searchSafeSpot(location); + if (safeSpot == null) { throw new RuntimeException("Unable to find a safe spot to set the spawn point " + location.toString()); } spawnPoint.setY(safeSpot.getY()); } - if (!p.getBorderManager().isInsideBorder(spawnPoint)) - { + if (!QSG.module(BorderModule.class).isInsideBorder(spawnPoint)) { throw new IllegalArgumentException("The given spawn location is outside the current border"); } @@ -140,8 +147,7 @@ public void addSpawnPoint(final Location location) * * @return The spawn points. */ - public List<Location> getSpawnPoints() - { + public List<Location> getSpawnPoints() { return spawnPoints; } @@ -152,25 +158,22 @@ public List<Location> getSpawnPoints() * @param location The location to be removed. * @param precise If true, only the spawn points at the exact same location will be removed. * Else, the points in the same block. - * * @return true if something were removed. */ - public boolean removeSpawnPoint(Location location, boolean precise) - { + public boolean removeSpawnPoint(final Location location, final boolean precise) { final List<Location> toRemove = getSpawnPoints().stream() .filter(spawn -> location.getWorld().equals(spawn.getWorld())) .filter(spawn -> precise - && location.getX() == spawn.getX() - && location.getZ() == spawn.getZ() || !precise - && location.getBlockX() == spawn.getBlockX() - && location.getBlockZ() == spawn.getBlockZ()) + && location.getX() == spawn.getX() + && location.getZ() == spawn.getZ() || !precise + && location.getBlockX() == spawn.getBlockX() + && location.getBlockZ() == spawn.getBlockZ()) .collect(Collectors.toCollection(LinkedList::new)); - for (Location spawnToRemove : toRemove) - { + for (Location spawnToRemove : toRemove) { // Used to remove all occurrences of the spawn point - while (spawnPoints.remove(spawnToRemove)) - ; + while (spawnPoints.remove(spawnToRemove)) { + } } return toRemove.size() != 0; @@ -178,34 +181,14 @@ public boolean removeSpawnPoint(Location location, boolean precise) /** * Removes all registered spawn points. - * + * <p> * CANNOT BE CANCELLED. */ - public void reset() - { + public void reset() { spawnPoints.clear(); } - /** - * Imports spawn points from the configuration. - * - * @return The number of spawn points imported. - */ - public int importSpawnPointsFromConfig() - { - int spawnCount = 0; - - for (Vector position: UHConfig.SPAWN_POINTS) - { - addSpawnPoint(position); - ++spawnCount; - } - - return spawnCount; - } - - /** * Generates spawn points with the given generator. * @@ -222,19 +205,18 @@ public int importSpawnPointsFromConfig() * region where the points will be generated. * @param zCenter The z coordinate of the point in the center of the * region where the points will be generated. - * * @throws CannotGenerateSpawnPointsException In case of fail. * @throws UnknownGeneratorException If no generator was found by the given name. */ - public void generateSpawnPoints(String generatorName, World world, int spawnCount, int regionDiameter, int minimalDistanceBetweenTwoPoints, double xCenter, double zCenter) throws CannotGenerateSpawnPointsException, UnknownGeneratorException - { + public void generateSpawnPoints(final String generatorName, final World world, final int spawnCount, + final int regionDiameter, final int minimalDistanceBetweenTwoPoints, + final double xCenter, final double zCenter) + throws CannotGenerateSpawnPointsException, UnknownGeneratorException { Generator generator = Generator.fromString(generatorName); - if (generator != null) - { - generateSpawnPoints(generator, world, spawnCount, regionDiameter, minimalDistanceBetweenTwoPoints, xCenter, zCenter); - } - else - { + if (generator != null) { + generateSpawnPoints(generator, world, spawnCount, regionDiameter, minimalDistanceBetweenTwoPoints, xCenter, + zCenter); + } else { throw new UnknownGeneratorException("The generator '" + generatorName + "' does not exists."); } } @@ -255,12 +237,14 @@ public void generateSpawnPoints(String generatorName, World world, int spawnCoun * region where the points will be generated. * @param zCenter The z coordinate of the point in the center of the * region where the points will be generated. - * * @throws CannotGenerateSpawnPointsException In case of fail. */ - public void generateSpawnPoints(Generator generator, World world, int spawnCount, int regionDiameter, int minimalDistanceBetweenTwoPoints, double xCenter, double zCenter) throws CannotGenerateSpawnPointsException - { - generateSpawnPoints(generator.getInstance(), world, spawnCount, regionDiameter, minimalDistanceBetweenTwoPoints, xCenter, zCenter); + public void generateSpawnPoints(final Generator generator, final World world, final int spawnCount, + final int regionDiameter, final int minimalDistanceBetweenTwoPoints, + final double xCenter, final double zCenter) + throws CannotGenerateSpawnPointsException { + generateSpawnPoints(generator.getInstance(), world, spawnCount, regionDiameter, minimalDistanceBetweenTwoPoints, + xCenter, zCenter); } /** @@ -279,13 +263,84 @@ public void generateSpawnPoints(Generator generator, World world, int spawnCount * region where the points will be generated. * @param zCenter The z coordinate of the point in the center of the * region where the points will be generated. - * * @throws CannotGenerateSpawnPointsException In case of fail. */ - public void generateSpawnPoints(SpawnPointsGenerator generator, World world, int spawnCount, int regionDiameter, int minimalDistanceBetweenTwoPoints, double xCenter, double zCenter) throws CannotGenerateSpawnPointsException - { - final Set<Location> spawnPoints = generator.generate(world, spawnCount, regionDiameter, minimalDistanceBetweenTwoPoints, xCenter, zCenter, AVOID_WATER); + public void generateSpawnPoints(final SpawnPointsGenerator generator, final World world, final int spawnCount, + final int regionDiameter, final int minimalDistanceBetweenTwoPoints, + final double xCenter, final double zCenter) + throws CannotGenerateSpawnPointsException { + generator.generate( + world, spawnCount, + regionDiameter, minimalDistanceBetweenTwoPoints, + xCenter, zCenter, Config.AVOID_WATER.get() + ).forEach(this::addSpawnPoint); + } + + + /** + * Generates on the fly missing spawn points when the game starts. + */ + @EventHandler + public void beforeTeleportationPhase(final BeforeTeleportationPhaseEvent ev) { + final GameModule game = QSG.module(GameModule.class); + + final World normalWorld = QSG.get().getWorld(World.Environment.NORMAL); + + final int regionDiameter = QSG.module(BorderModule.class).getCurrentBorderDiameter(); + final int playersWithoutTeam = (int) Bukkit.getOnlinePlayers().stream() + .filter(player -> QuartzTeams.get().getTeamForPlayer(player) == null) + .count(); + + int spawnsNeeded = 0; + + switch (game.getTeleportationMode()) { + case NORMAL: + spawnsNeeded = QuartzTeams.get().countTeams() + playersWithoutTeam; + break; + + case IGNORE_TEAMS: + spawnsNeeded = QuartzTeams.get().getTeams().stream().mapToInt(team -> team.getPlayers().size()).sum() + + playersWithoutTeam; + break; + } + + spawnsNeeded -= spawnPoints.size(); // We don't need what we already have. + + if (spawnsNeeded <= 0) { + return; + } + + Exception error = null; + + for (int i = 0; i < 6; i++) { + try { + generateSpawnPoints( + Generator.RANDOM, + normalWorld, + spawnsNeeded, + regionDiameter - 25, + (int) Math.floor(regionDiameter / Math.max(spawnsNeeded * 1.4, 10)), + normalWorld.getSpawnLocation().getX(), + normalWorld.getSpawnLocation().getZ() + ); - spawnPoints.forEach(this::addSpawnPoint); + error = null; + } + catch (final CannotGenerateSpawnPointsException e) { + error = e; + continue; + } + + break; + } + + if (error == null) { + log().info("Randomly generated {0} missing spawn points on the fly. See /uh spawn for details.", + spawnsNeeded); + } else { + log().error( + "There where {0} missing spawn points but we weren''t able to generate them automatically, even after 6 tries. Try to generate them yourself using /uh spawns generate, or to add them manually with /uh spawns add.", + error, spawnsNeeded); + } } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/commands/SpawnsCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/commands/SpawnsCommand.java new file mode 100644 index 0000000..5926bcc --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/commands/SpawnsCommand.java @@ -0,0 +1,502 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.BorderModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.SpawnsModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.exceptions.CannotGenerateSpawnPointsException; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.exceptions.UnknownGeneratorException; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.SpectatorsModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzteams.QuartzTeam; +import fr.zcraft.quartzteams.QuartzTeams; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.World.Environment; +import org.bukkit.command.BlockCommandSender; +import org.bukkit.entity.Player; + + +@CommandInfo( + name = "spawns", + usageParameters = "[generate | add [<x> <z>] | remove [<x> <z>] | dump | help]", + aliases = {"spawn", "s"} +) +public class SpawnsCommand extends Command { + @Override + protected void run() throws CommandException { + if (args.length == 0) { + list(); + return; + } + + switch (args[0].toLowerCase()) { + case "list": + list(); + return; + + case "dump": + dump(); + return; + + case "add": + add(); + return; + + case "remove": + remove(); + return; + + case "generate": + generate(); + return; + + case "reset": + reset(); + + default: + help(); + } + } + + protected void help() { + info(I.t("{blue}{bold}Command help for {cc}{bold}/uh spawns")); + info(I.t("{cc}/uh spawns list {ci}: lists the registered spawn points.")); + info(I.t( + "{cc}/uh spawns dump {ci}: displays the registered spawn points in an exportable format. {gray}Use this to plot the spawn points, as example.")); + info(I.t( + "{cc}/uh spawns add {ci}: adds a spawn point for a team or a player, at the current location of the sender or at the provided coordinates.")); + info(I.t( + "{cc}/uh spawns remove [<x> <z>] {ci}: removes the spawn points at the specified coordinates, or at the current location if the sender without coordinates.")); + info(I.t( + "{cc}/uh spawns generate {ci}: automagically generates spawn points. See /uh spawns generate for details.")); + info(I.t("{cc}/uh spawns reset {ci}: removes all registered spawn points.")); + } + + protected void list() { + final List<Location> spawnPoints = QSG.module(SpawnsModule.class).getSpawnPoints(); + + if (spawnPoints.size() == 0) { + if (sender instanceof Player) { + info(""); + } + info(I.t("{ce}There isn't any registered spawn point.")); + + if (args.length == 0) { + info(""); + help(); + } + } else { + if (sender instanceof Player) { + info(""); + } + info(I.t("{ci}There are {0} registered spawn points.", String.valueOf(spawnPoints.size()))); + + // We want one list per world + final Map<World, List<Location>> spawnsInWorlds = new HashMap<>(); + spawnPoints.forEach(spawn -> { + spawnsInWorlds.putIfAbsent(spawn.getWorld(), new LinkedList<>()); + spawnsInWorlds.get(spawn.getWorld()).add(spawn); + }); + + for (Map.Entry<World, List<Location>> spanwsInWorld : spawnsInWorlds.entrySet()) { + if (spanwsInWorld.getValue().size() == 0) { + continue; + } + + info(""); + info(I.t("{lightpurple}World {0}", spanwsInWorld.getKey().getName())); + + + // Displaying this number of spawn points per line + final int spawnsPerLine = 5; + + for (int j = 0; j < Math.ceil((double) spanwsInWorld.getValue().size() / spawnsPerLine); j++) { + final StringBuilder line = new StringBuilder(); + + for (int k = 0; k < spawnsPerLine; k++) { + if (spanwsInWorld.getValue().size() > j * spawnsPerLine + k) { + line.append( + getSpawnItem( + spanwsInWorld.getValue().get(j * spawnsPerLine + k).getBlockX(), + spanwsInWorld.getValue().get(j * spawnsPerLine + k).getBlockZ(), + spanwsInWorld.getKey().getEnvironment() + ) + ).append(" "); + } + } + + info(line.toString()); + } + } + } + } + + protected void dump() { + // We want one list per world + final Map<World, List<Location>> spawnsInWorlds = new HashMap<>(); + + QSG.module(SpawnsModule.class) + .getSpawnPoints() + .forEach(spawn -> { + spawnsInWorlds.putIfAbsent(spawn.getWorld(), new LinkedList<>()); + spawnsInWorlds.get(spawn.getWorld()).add(spawn); + }); + + StringBuilder dump = new StringBuilder(); + + for (Map.Entry<World, List<Location>> spawnsInWorld : spawnsInWorlds.entrySet()) { + if (spawnsInWorld.getValue().size() == 0) { + continue; + } + + dump.append("\n* ").append(spawnsInWorld.getKey().getName()).append("\n"); + + for (Location spawn : spawnsInWorld.getValue()) { + dump.append(spawn.getBlockX()).append(",").append(spawn.getBlockZ()).append("\n"); + } + } + + sender.sendMessage(dump.toString()); + } + + protected void add() throws CommandException { + // World? + final World world; + if (sender instanceof Player) { + world = ((Player) sender).getWorld(); + } else if (sender instanceof BlockCommandSender) { + world = ((BlockCommandSender) sender).getBlock().getWorld(); + } else if (args.length >= 4) { + world = Bukkit.getWorld(args[3]); + + if (world == null) { + throwInvalidArgument(I.t("There is no world named {0}.", args[3])); + } + } else { + world = QSG.get().getWorld(Environment.NORMAL); + } + + // /uh spawns add + if (args.length == 1) { + try { + QSG.module(SpawnsModule.class).addSpawnPoint(playerSender().getLocation()); + success(I.t("{cs}Spawn added in the world {0}: {1};{2}", world.getName(), + String.valueOf(playerSender().getLocation().getBlockX()), + String.valueOf(playerSender().getLocation().getBlockZ()))); + } + catch (IllegalArgumentException e) { + error(I.t("{ce}You cannot add a spawn point out of the borders.")); + } + catch (RuntimeException e) { + error(I.t("{ce}Unable to add this spawn point: no safe spot found in the Nether.")); + } + } + + // /uh spawns add <x>: Two coordinates needed! + else if (args.length == 2) { + throwInvalidArgument(I.t("{ce}You need to specify two coordinates.")); + } + + // /uh spawns add <x> <z> [world] + else { + try { + QSG.module(SpawnsModule.class) + .addSpawnPoint(world, Double.parseDouble(args[1]), Double.parseDouble(args[2])); + success(I.t("{cs}Spawn added in the world {0}: {1};{2}", world.getName(), args[1], args[2])); + } + catch (NumberFormatException e) { + throwInvalidArgument(I.t("{ce}This is not a number!")); + } + catch (IllegalArgumentException e) { + error(I.t("{ce}You cannot add a spawn point out of the borders.")); + } + catch (RuntimeException e) { + error(I.t("{ce}Unable to add this spawn point: no safe spot found in the Nether.")); + } + } + } + + protected void remove() throws CommandException { + // /uh spawns remove + if (args.length == 1) { + QSG.module(SpawnsModule.class).removeSpawnPoint(playerSender().getLocation(), false); + success(I + .t("{cs}The spawn point {1};{2} in the world {0} was removed.", playerSender().getWorld().getName(), + playerSender().getLocation().getBlockX(), playerSender().getLocation().getBlockZ())); + + } + + // /uh spawns add <x>: Two coordinates needed! + else if (args.length == 2) { + throwInvalidArgument(I.t("{ce}You need to specify two coordinates.")); + } + + // /uh spawns remove <x> <z> + else { + try { + final World world; + if (sender instanceof Player) { + world = ((Player) sender).getWorld(); + } else if (args.length >= 4) { + world = Bukkit.getWorld(args[3]); + if (world == null) { + throwInvalidArgument(I.t("There is no world named {0}.", args[3])); + } + } else { + world = QSG.get().getWorld(Environment.NORMAL); + } + + QSG.module(SpawnsModule.class).removeSpawnPoint( + new Location( + world, Double.parseDouble(args[1]), 0, Double.parseDouble(args[2]) + ), + true + ); + success(I.t("{cs}The spawn point {1};{2} in the world {0} was removed.", world, args[1], args[2])); + } + catch (NumberFormatException e) { + throwInvalidArgument(I.t("{ce}This is not a number!")); + } + } + } + + protected void reset() { + QSG.module(SpawnsModule.class).reset(); + success(I.t("{cs}All the spawn points were removed.")); + } + + protected void generate() throws CommandException { + // /uh spawns generate + if (args.length == 1) { + if (sender instanceof Player) { + info(""); + } + + info(I.t("{aqua}Command")); + info(I.t( + "{cc}/uh spawns generate <circular|grid|random> [size] [distanceMin] [count] [xCenter] [zCenter] [world]")); + info(""); + info(I.t("{aqua}Shapes")); + info(I.t( + " - {cc}random{ci}: generates random spawn points on the map, with a minimal distance between them.")); + info(I.t( + " - {cc}grid{ci}: generates the spawn points on concentric squares, with a constant distance between two generated points.")); + info(I.t( + " - {cc}circular{ci}: generates the spawn points on concentric circles, with a minimal distance between two generated points. In each circle, the angle (and the distance) between two spawn points is constant.")); + info(""); + info(I.t("{aqua} Arguments ")); + info(I.t( + " - {cc}size{ci}: the size of the region where the spawn points will be generated. Squared or circular, following the shape of the map. Default: map' size.")); + info(I.t(" - {cc}distanceMin{ci}: the minimal distance between two spawn points. Default: 250 blocks.")); + info(I.t( + " - {cc}count{ci}: the number of spawn points to generate. Default: the number of players or teams.")); + info(I.t( + " - {cc}xCenter{ci}, {cc}zCenter{ci}: the center of the region where the points are generated. Default: world' spawn point.")); + info(I.t(" - {cc}world{ci}: the world where the spawn points will be generated.")); + + return; + } + + final String generationMethod = args[1]; + + // Default values + int size = QSG.module(BorderModule.class).getCurrentBorderDiameter() - + 25; // Avoid spawn points being too close to the border + int distanceMinBetweenTwoPoints = 250; + World world = QSG.get().getWorld(Environment.NORMAL); + double xCenter = world.getSpawnLocation().getX(); + double zCenter = world.getSpawnLocation().getZ(); + + int spawnsCount = 0; + for (final QuartzTeam team : QuartzTeams.get().getTeams()) { + if (!team.isEmpty()) { + spawnsCount++; + } + } + + if (args.length < 8) { + if (sender instanceof Player) { + world = ((Player) sender).getWorld(); + } else if (sender instanceof BlockCommandSender) { + world = ((BlockCommandSender) sender).getBlock().getWorld(); + } + + xCenter = world.getSpawnLocation().getX(); + zCenter = world.getSpawnLocation().getZ(); + } + + // What if the game is in solo, or some players are out of all team? + // Only if the spawn count is not provided of course. Else, we don't care, this count + // will be overwritten. + if (args.length < 6) { + // Solo mode? + if (spawnsCount == 0) { + spawnsCount = Bukkit.getServer().getOnlinePlayers().size() - + QSG.module(SpectatorsModule.class).getSpectators().size(); + info(I.t("{ci}No team found: assuming the game is a solo game.")); + } else { + // Trying to find players without team + int playersWithoutTeam = 0; + for (Player player : Bukkit.getServer().getOnlinePlayers()) { + if (QuartzTeams.get().getTeamForPlayer(player) == null) { + playersWithoutTeam++; + } + } + + if (playersWithoutTeam != 0) { + spawnsCount += playersWithoutTeam; + info(I.t("{ci}Some players are not in a team; their number was added to the spawn count.")); + } + } + } + + try { + // size included + if (args.length >= 3) { + size = Integer.parseInt(args[2]); + + // distance minimal included + if (args.length >= 4) { + distanceMinBetweenTwoPoints = Integer.parseInt(args[3]); + + // spawn count included + if (args.length >= 5) { + spawnsCount = Integer.parseInt(args[4]); + + // xCenter included + if (args.length >= 6) { + xCenter = Double.parseDouble(args[5]); + + // zCenter included + if (args.length >= 7) { + zCenter = Double.parseDouble(args[6]); + + // world included + if (args.length >= 8) { + final World inputWorld = Bukkit.getServer().getWorld(args[7]); + + if (inputWorld != null) { + world = inputWorld; + } else { + error(I.t("{ce}The world {0} doesn't exists.", args[7])); + } + } + } + } + } + } + } + } + catch (NumberFormatException e) { + info(I.t("{ce}This is not a number!")); + info(I.t( + "{cc}/uh spawns generate <circular|grid|random> [size] [distanceMin] [count] [xCenter] [zCenter] [world]")); + return; + } + + + if (spawnsCount <= 0) { + sender.sendMessage(I.t("{ci}You asked for a void generation. Thus, the generation is empty.")); + return; + } + + + try { + QSG.module(SpawnsModule.class) + .generateSpawnPoints(generationMethod, world, spawnsCount, size, distanceMinBetweenTwoPoints, + xCenter, zCenter); + } + catch (UnknownGeneratorException e) { + throwInvalidArgument(I.t("{ce}The generation method “{0}” is not (yet?) supported.", generationMethod)); + + } + catch (CannotGenerateSpawnPointsException e) { + error(I.t( + "{ce}You asked for the impossible: there are too many spawn points on a too small surface. Decrease the spawn count or the minimal distance between two points.")); + } + + + success(I.t("{cs}Successfully generated the asked spawn points.")); + } + + @Override + protected List<String> complete() throws CommandException { + if (args.length == 1) { + return getMatchingSubset(args[0], "add", "remove", "generate", "list", "dump", "reset"); + } else if (args.length == 2 && args[0].equalsIgnoreCase("generate")) { + return getMatchingSubset(args[1], "circular", "grid", "random"); + } else if (args.length == 4 && (args[0].equalsIgnoreCase("add") || args[0].equalsIgnoreCase("remove"))) { + return getMatchingSubset(Bukkit.getWorlds().stream().map(World::getName).collect(Collectors.toList()), + args[3]); + } else if (args.length == 8 && args[0].equalsIgnoreCase("generate")) { + return getMatchingSubset(Bukkit.getWorlds().stream().map(World::getName).collect(Collectors.toList()), + args[7]); + } else { + return null; + } + } + + + private String getSpawnItem(int x, int z, Environment environment) { + switch (environment) { + case NORMAL: + /// A spawn point in the /uh spawns list command (in the overworld) + return I.t("{green}{0}{darkgreen};{green}{1}", x, z); + + case NETHER: + /// A spawn point in the /uh spawns list command (in the Nether) + return I.t("{red}{0}{darkred};{red}{1}", x, z); + + case THE_END: + /// A spawn point in the /uh spawns list command (in the End) + return I.t("{yellow}{0}{gold};{yellow}{1}", x, z); + + default: + /// A spawn point in the /uh spawns list command (in a custom world) + return I.t("{gray}{0}{darkgray};{gray}{1}", x, z); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/exceptions/CannotGenerateSpawnPointsException.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/exceptions/CannotGenerateSpawnPointsException.java similarity index 92% rename from src/main/java/eu/carrade/amaury/UHCReloaded/spawns/exceptions/CannotGenerateSpawnPointsException.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/exceptions/CannotGenerateSpawnPointsException.java index b8289c8..761600b 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/exceptions/CannotGenerateSpawnPointsException.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/exceptions/CannotGenerateSpawnPointsException.java @@ -30,14 +30,12 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.spawns.exceptions; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.exceptions; -public class CannotGenerateSpawnPointsException extends Exception -{ +public class CannotGenerateSpawnPointsException extends Exception { - public CannotGenerateSpawnPointsException(String message) - { + public CannotGenerateSpawnPointsException(String message) { super(message); } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/exceptions/UnknownGeneratorException.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/exceptions/UnknownGeneratorException.java similarity index 89% rename from src/main/java/eu/carrade/amaury/UHCReloaded/spawns/exceptions/UnknownGeneratorException.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/exceptions/UnknownGeneratorException.java index 1ab5892..763e31e 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/exceptions/UnknownGeneratorException.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/exceptions/UnknownGeneratorException.java @@ -29,13 +29,12 @@ * 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.spawns.exceptions; -public class UnknownGeneratorException extends Exception -{ +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.exceptions; - public UnknownGeneratorException(String message) - { +public class UnknownGeneratorException extends Exception { + + public UnknownGeneratorException(String message) { super(message); } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/generators/CircularSpawnPointsGenerator.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/generators/CircularSpawnPointsGenerator.java similarity index 79% rename from src/main/java/eu/carrade/amaury/UHCReloaded/spawns/generators/CircularSpawnPointsGenerator.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/generators/CircularSpawnPointsGenerator.java index 10aa435..4775803 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/generators/CircularSpawnPointsGenerator.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/generators/CircularSpawnPointsGenerator.java @@ -30,25 +30,24 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.spawns.generators; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.generators; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.spawns.exceptions.CannotGenerateSpawnPointsException; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.BorderModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.exceptions.CannotGenerateSpawnPointsException; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import java.util.HashSet; -import java.util.Random; -import java.util.Set; - -public class CircularSpawnPointsGenerator implements SpawnPointsGenerator -{ - private final UHCReloaded p = UHCReloaded.get(); +public class CircularSpawnPointsGenerator implements SpawnPointsGenerator { + private final BorderModule borderModule = QSG.module(BorderModule.class); /** * Generates spawn points in concentric circles. @@ -62,14 +61,13 @@ public class CircularSpawnPointsGenerator implements SpawnPointsGenerator * @param xCenter The x coordinate of the point in the center of the region where the points will be generated. * @param zCenter The z coordinate of the point in the center of the region where the points will be generated. * @param avoidWater True if the generation have to avoid the water. - * * @return The spawn points generated. - * * @throws CannotGenerateSpawnPointsException In case of fail. */ @Override - public Set<Location> generate(final World world, final int spawnCount, final int regionDiameter, final int minimalDistanceBetweenTwoPoints, final double xCenter, final double zCenter, final boolean avoidWater) throws CannotGenerateSpawnPointsException - { + public Set<Location> generate(final World world, final int spawnCount, final int regionDiameter, + final int minimalDistanceBetweenTwoPoints, final double xCenter, final double zCenter, + final boolean avoidWater) throws CannotGenerateSpawnPointsException { // We starts the generation on a smaller grid, to avoid false outside tests if the point is on the edge final int usedRegionDiameter = regionDiameter - 1; @@ -80,8 +78,7 @@ public Set<Location> generate(final World world, final int spawnCount, final int // The generation loop. Each step generates a circle. generationLoop: - while (currentCircleDiameter >= minimalDistanceBetweenTwoPoints) - { + while (currentCircleDiameter >= minimalDistanceBetweenTwoPoints) { // First step. We want to know if all the points left can be in one circle. // We calculates the maximal number of points in a circle, taking into account the // minimal distance between two points. @@ -91,21 +88,20 @@ public Set<Location> generate(final World world, final int spawnCount, final int // a = 2 Arcsin((d/2)/R) // (Just draw the situation, you'll see.) - final double denseCircleAngle = 2 * Math.asin(((double) minimalDistanceBetweenTwoPoints / 2) / ((double) currentCircleDiameter / 2)); + final double denseCircleAngle = 2 * + Math.asin(((double) minimalDistanceBetweenTwoPoints / 2) / ((double) currentCircleDiameter / 2)); final int pointsPerDenseCircles = (int) Math.floor(2 * Math.PI / denseCircleAngle); final double angleBetweenTwoPoints; // Not all the points can be in this circle. We generate the densest circle. - if (pointsPerDenseCircles < spawnCount - countGeneratedPoints) - { + if (pointsPerDenseCircles < spawnCount - countGeneratedPoints) { angleBetweenTwoPoints = 2 * Math.PI / ((double) pointsPerDenseCircles); } // All the remaining points can be in this circle. We generates the less dense circle with // these points. - else - { + else { angleBetweenTwoPoints = 2 * Math.PI / ((double) (spawnCount - countGeneratedPoints)); } @@ -113,8 +109,7 @@ public Set<Location> generate(final World world, final int spawnCount, final int final double startAngle = (new Random()).nextDouble() * 2 * Math.PI; double currentAngle = startAngle; - while (currentAngle <= 2 * Math.PI - angleBetweenTwoPoints + startAngle) - { + while (currentAngle <= 2 * Math.PI - angleBetweenTwoPoints + startAngle) { // The coordinates of a point in the circle. // Cf. your trigonometry! ;) Location point = new Location( @@ -127,8 +122,7 @@ public Set<Location> generate(final World world, final int spawnCount, final int currentAngle += angleBetweenTwoPoints; // Just in case - if (!p.getBorderManager().isInsideBorder(point, regionDiameter)) - { + if (!borderModule.isInsideBorder(point, regionDiameter)) { continue; } @@ -136,16 +130,16 @@ public Set<Location> generate(final World world, final int spawnCount, final int final Block surfaceBlock = surfaceAirBlock.getRelative(BlockFace.DOWN); // Safe spot available? - if (!UHUtils.isSafeSpot(surfaceAirBlock.getLocation())) - { + if ((world.getEnvironment() == World.Environment.NORMAL || + world.getEnvironment() == World.Environment.THE_END) && !QSGUtils + .isSafeSpot(surfaceAirBlock.getLocation()) + || QSGUtils.searchSafeSpot(point) == null) { continue; // not safe: nope } // Not above the water? - if (avoidWater) - { - if (surfaceBlock.getType() == Material.WATER || surfaceBlock.getType() == Material.STATIONARY_WATER) - { + if (avoidWater) { + if (surfaceBlock.getType() == Material.WATER || surfaceBlock.getType() == Material.WATER) { continue; } } @@ -153,8 +147,7 @@ public Set<Location> generate(final World world, final int spawnCount, final int generatedPoints.add(point); countGeneratedPoints++; - if (countGeneratedPoints >= spawnCount) - { + if (countGeneratedPoints >= spawnCount) { break generationLoop; } } @@ -166,13 +159,11 @@ public Set<Location> generate(final World world, final int spawnCount, final int // Generation done or failed (not enough space)? - if (generatedPoints.size() < spawnCount) - { + if (generatedPoints.size() < spawnCount) { // Failed! - throw new CannotGenerateSpawnPointsException("Cannot generate the spawn point in circles: not enough space"); - } - else - { + throw new CannotGenerateSpawnPointsException( + "Cannot generate the spawn point in circles: not enough space"); + } else { return generatedPoints; } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/generators/GridSpawnPointsGenerator.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/generators/GridSpawnPointsGenerator.java similarity index 80% rename from src/main/java/eu/carrade/amaury/UHCReloaded/spawns/generators/GridSpawnPointsGenerator.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/generators/GridSpawnPointsGenerator.java index 4cc6763..475eef6 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/generators/GridSpawnPointsGenerator.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/generators/GridSpawnPointsGenerator.java @@ -29,25 +29,25 @@ * 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.spawns.generators; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.borders.MapShape; -import eu.carrade.amaury.UHCReloaded.spawns.exceptions.CannotGenerateSpawnPointsException; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.generators; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.BorderModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.MapShape; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.exceptions.CannotGenerateSpawnPointsException; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import java.util.HashSet; +import java.util.Set; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import java.util.HashSet; -import java.util.Set; - -public class GridSpawnPointsGenerator implements SpawnPointsGenerator -{ - private final UHCReloaded p = UHCReloaded.get(); +public class GridSpawnPointsGenerator implements SpawnPointsGenerator { + private final BorderModule borderModule = QSG.module(BorderModule.class); /** * Generates spawn points in a grid. @@ -65,13 +65,13 @@ public class GridSpawnPointsGenerator implements SpawnPointsGenerator * @param zCenter The z coordinate of the point in the center of the * region where the points will be generated. * @param avoidWater True if the generation have to avoid the water. - * * @return The spawn points generated. * @throws CannotGenerateSpawnPointsException In case of fail. */ @Override - public Set<Location> generate(final World world, final int spawnCount, final int regionDiameter, final int minimalDistanceBetweenTwoPoints, final double xCenter, final double zCenter, final boolean avoidWater) throws CannotGenerateSpawnPointsException - { + public Set<Location> generate(final World world, final int spawnCount, final int regionDiameter, + final int minimalDistanceBetweenTwoPoints, final double xCenter, final double zCenter, + final boolean avoidWater) throws CannotGenerateSpawnPointsException { // We starts the generation on a smaller grid, to avoid false outside tests if the point is on the edge final int usedRegionDiameter = regionDiameter - 1; @@ -81,8 +81,7 @@ public Set<Location> generate(final World world, final int spawnCount, final int // The points are on a grid int neededColumnsCount = (int) Math.ceil(Math.sqrt(spawnCount)); - if (p.getBorderManager().getMapShape() == MapShape.CIRCULAR) - { + if (borderModule.getMapShape() == MapShape.CIRCULAR) { // If the border is circular, the distance between two points needs to be decreased. // The space available is divided by PI/4, so the column count is multiplied by // this number. @@ -90,8 +89,7 @@ public Set<Location> generate(final World world, final int spawnCount, final int } // IS impossible. - if (neededColumnsCount > maxColumnsCount) - { + if (neededColumnsCount > maxColumnsCount) { throw new CannotGenerateSpawnPointsException("Cannot generate spawn points on a grid: not enough space."); } @@ -104,8 +102,7 @@ public Set<Location> generate(final World world, final int spawnCount, final int final int distanceBetweenTwoPoints = (int) ((double) usedRegionDiameter / ((double) (neededColumnsCount))); // Check related to the case the column count was increased. - if (distanceBetweenTwoPoints < minimalDistanceBetweenTwoPoints) - { + if (distanceBetweenTwoPoints < minimalDistanceBetweenTwoPoints) { throw new CannotGenerateSpawnPointsException("Cannot generate spawn points on a grid: not enough space."); } @@ -129,35 +126,30 @@ public Set<Location> generate(final World world, final int spawnCount, final int // We generates the points until there isn't any point left to place. The loop will be broken. // On each step of this loop, a square is generated. generationLoop: - while (true) - { + while (true) { currentPoint = currentSquareStartPoint.clone(); // First point - if (p.getBorderManager().isInsideBorder(currentPoint, regionDiameter) && UHUtils.searchSafeSpot(currentPoint) != null) - { + if (borderModule.isInsideBorder(currentPoint, regionDiameter) + && QSGUtils.searchSafeSpot(currentPoint) != null) { generatedPoints.add(currentPoint.clone()); countGeneratedPoints++; - if (countGeneratedPoints >= spawnCount) - { + if (countGeneratedPoints >= spawnCount) { break; } } // A step for each side, j is the side (see addOnSide). - for (int j = 0; j < 4; j++) - { + for (int j = 0; j < 4; j++) { int plottedSize = 0; - while (plottedSize < currentSquareSize) - { + while (plottedSize < currentSquareSize) { currentPoint.add(addOnSide[j]); plottedSize += distanceBetweenTwoPoints; // Inside the border? - if (!p.getBorderManager().isInsideBorder(currentPoint, regionDiameter)) - { + if (!borderModule.isInsideBorder(currentPoint, regionDiameter)) { continue; } @@ -165,16 +157,16 @@ public Set<Location> generate(final World world, final int spawnCount, final int final Block surfaceBlock = surfaceAirBlock.getRelative(BlockFace.DOWN); // Safe spot available? - if (!UHUtils.isSafeSpot(surfaceAirBlock.getLocation())) - { + if ((world.getEnvironment() == World.Environment.NORMAL + || world.getEnvironment() == World.Environment.THE_END) && !QSGUtils + .isSafeSpot(surfaceAirBlock.getLocation()) + || (QSGUtils.searchSafeSpot(currentPoint) == null)) { continue; // not safe: nope } // Not above the water? - if (avoidWater) - { - if (surfaceBlock.getType() == Material.WATER || surfaceBlock.getType() == Material.STATIONARY_WATER) - { + if (avoidWater) { + if (surfaceBlock.getType() == Material.WATER || surfaceBlock.getType() == Material.WATER) { continue; } } @@ -182,8 +174,7 @@ public Set<Location> generate(final World world, final int spawnCount, final int generatedPoints.add(currentPoint.clone()); countGeneratedPoints++; - if (countGeneratedPoints >= spawnCount) - { + if (countGeneratedPoints >= spawnCount) { break generationLoop; } } @@ -193,8 +184,7 @@ public Set<Location> generate(final World world, final int spawnCount, final int currentSquareSize -= 2 * distanceBetweenTwoPoints; currentSquareStartPoint.add(new Location(world, -distanceBetweenTwoPoints, 0, distanceBetweenTwoPoints)); - if (currentSquareSize < distanceBetweenTwoPoints) - { + if (currentSquareSize < distanceBetweenTwoPoints) { // This may happens if we generates the points for a circular world break; } @@ -202,13 +192,10 @@ public Set<Location> generate(final World world, final int spawnCount, final int // If the generation was broken (circular world, not enough positions), // the generation was incomplete. - if (countGeneratedPoints >= spawnCount) - { + if (countGeneratedPoints >= spawnCount) { // Generation OK return generatedPoints; - } - else - { + } else { throw new CannotGenerateSpawnPointsException("Cannot generate the spawn points: not enough space."); } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/generators/RandomSpawnPointsGenerator.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/generators/RandomSpawnPointsGenerator.java similarity index 75% rename from src/main/java/eu/carrade/amaury/UHCReloaded/spawns/generators/RandomSpawnPointsGenerator.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/generators/RandomSpawnPointsGenerator.java index a17a764..8a00a08 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/generators/RandomSpawnPointsGenerator.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/generators/RandomSpawnPointsGenerator.java @@ -30,30 +30,29 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.spawns.generators; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.generators; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.borders.MapShape; -import eu.carrade.amaury.UHCReloaded.spawns.exceptions.CannotGenerateSpawnPointsException; -import eu.carrade.amaury.UHCReloaded.utils.UHUtils; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.BorderModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.MapShape; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.exceptions.CannotGenerateSpawnPointsException; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import java.util.HashSet; -import java.util.Random; -import java.util.Set; - /** * Generates the spawn points randomly. */ -public class RandomSpawnPointsGenerator implements SpawnPointsGenerator -{ +public class RandomSpawnPointsGenerator implements SpawnPointsGenerator { private final Random random = new Random(); - private final UHCReloaded p = UHCReloaded.get(); + private final BorderModule borderModule = QSG.module(BorderModule.class); /** * Generates randomly some spawn points in the map, with a minimal distance. @@ -67,14 +66,13 @@ public class RandomSpawnPointsGenerator implements SpawnPointsGenerator * @param xCenter The x coordinate of the point in the center of the region where the points will be generated. * @param zCenter The z coordinate of the point in the center of the region where the points will be generated. * @param avoidWater True if the generation have to avoid the water. - * * @return The spawn points generated. - * * @throws CannotGenerateSpawnPointsException In case of fail */ @Override - public Set<Location> generate(final World world, final int spawnCount, final int regionDiameter, final int minimalDistanceBetweenTwoPoints, final double xCenter, final double zCenter, final boolean avoidWater) throws CannotGenerateSpawnPointsException - { + public Set<Location> generate(final World world, final int spawnCount, final int regionDiameter, + final int minimalDistanceBetweenTwoPoints, final double xCenter, final double zCenter, + final boolean avoidWater) throws CannotGenerateSpawnPointsException { final double minimalDistanceBetweenTwoPointsSquared = Math.pow(minimalDistanceBetweenTwoPoints, 2); @@ -84,27 +82,25 @@ public Set<Location> generate(final World world, final int spawnCount, final int // around each spawn point (a circle with, as radius, the minimal distance between two spawn // points), the generation will fail. - final double surfacePrivatePartsAroundSpawnPoints = (int) (spawnCount * (Math.PI * minimalDistanceBetweenTwoPointsSquared)); + final double surfacePrivatePartsAroundSpawnPoints = + (int) (spawnCount * (Math.PI * minimalDistanceBetweenTwoPointsSquared)); final double surfaceRegion; - if (p.getBorderManager().getMapShape() == MapShape.CIRCULAR) - { + if (borderModule.getMapShape() == MapShape.CIRCULAR) { surfaceRegion = (Math.PI * Math.pow(regionDiameter, 2)) / 4; - } - else - { + } else { surfaceRegion = Math.pow(regionDiameter, 2); } final double packingDensity = surfacePrivatePartsAroundSpawnPoints / surfaceRegion; - // According to Lagrange and Thue's works on circle packagings, the highest density possible is + // According to Lagrange and Thue's works on circles packaging, the highest density possible is // approximately 0.9069 (with an hexagonal arrangement of the circles). // Even with a packaging density very close to this limit, the generation time is correct. // So we uses this as a limit. - if (packingDensity >= 0.9069) - { - throw new CannotGenerateSpawnPointsException("Unable to generate spawn points randomly: packing density too high"); + if (packingDensity >= 0.9069) { + throw new CannotGenerateSpawnPointsException( + "Unable to generate spawn points randomly: packing density of " + packingDensity + " too high"); } /* *** Generation *** */ @@ -118,14 +114,13 @@ public Set<Location> generate(final World world, final int spawnCount, final int // of other ones, we restarts all the generation. int currentErrorCount = 0; - // With the "avoid above water" option, if there's a lot of water, the genaration may + // With the "avoid above water" option, if there's a lot of water, the generation may // fail even if the surface seems to be ok to host the requested spawn points. // So, after 2*{points requested} points above the water, we cancels the generation. int pointsAboveWater = 0; generationLoop: - while (generatedSpawnPoints != spawnCount) - { + while (generatedSpawnPoints != spawnCount) { // "Too many fails" test if (currentErrorCount >= 16) // restart { @@ -135,8 +130,7 @@ public Set<Location> generate(final World world, final int spawnCount, final int } // "Too many points above the water" test - if (pointsAboveWater >= 2 * spawnCount) - { + if (pointsAboveWater >= 2 * spawnCount) { throw new CannotGenerateSpawnPointsException("Too many spawn points above the water."); } @@ -146,13 +140,14 @@ public Set<Location> generate(final World world, final int spawnCount, final int // excluded when his presence inside the region will be checked. Location randomPoint = new Location(world, - random((int) (xCenter - Math.floor(regionDiameter / 2)), (int) (xCenter + (int) Math.floor(regionDiameter / 2))), + random((int) (xCenter - Math.floor(regionDiameter / 2)), + (int) (xCenter + (int) Math.floor(regionDiameter / 2))), 0, - random((int) (zCenter - Math.floor(regionDiameter / 2)), (int) (zCenter + (int) Math.floor(regionDiameter / 2)))); + random((int) (zCenter - Math.floor(regionDiameter / 2)), + (int) (zCenter + (int) Math.floor(regionDiameter / 2)))); // Inside the region? - if (!p.getBorderManager().isInsideBorder(randomPoint, regionDiameter)) - { + if (!borderModule.isInsideBorder(randomPoint, regionDiameter)) { continue; // outside: nope } @@ -160,26 +155,24 @@ public Set<Location> generate(final World world, final int spawnCount, final int final Block surfaceBlock = surfaceAirBlock.getRelative(BlockFace.DOWN); // Safe spot available? - if (!UHUtils.isSafeSpot(surfaceAirBlock.getLocation())) - { + if ((world.getEnvironment() == World.Environment.NORMAL || + world.getEnvironment() == World.Environment.THE_END) && !QSGUtils + .isSafeSpot(surfaceAirBlock.getLocation()) + || QSGUtils.searchSafeSpot(randomPoint) == null) { continue; // not safe: nope } // Not above the water? - if (avoidWater) - { - if (surfaceBlock.getType() == Material.WATER || surfaceBlock.getType() == Material.STATIONARY_WATER) - { + if (avoidWater) { + if (surfaceBlock.getType() == Material.WATER) { pointsAboveWater++; continue; } } // Is that point at a correct distance of the other ones? - for (Location spawn : randomSpawnPoints) - { - if (spawn.distanceSquared(randomPoint) < minimalDistanceBetweenTwoPointsSquared) - { + for (Location spawn : randomSpawnPoints) { + if (spawn.distanceSquared(randomPoint) < minimalDistanceBetweenTwoPointsSquared) { currentErrorCount++; continue generationLoop; // too close: nope } @@ -204,10 +197,8 @@ public Set<Location> generate(final World world, final int spawnCount, final int * @param max The maximum value. May be negative. Inclusive. * @return A random number between these two points. */ - public Integer random(int min, int max) - { - if (min == max) - { + public Integer random(int min, int max) { + if (min == max) { return min; } @@ -218,15 +209,11 @@ public Integer random(int min, int max) min = min - max; } - if (min >= 0 && max >= 0) - { + if (min >= 0 && max >= 0) { return random.nextInt(max - min + 1) + min; - } - else if (min <= 0 && max <= 0) - { + } else if (min <= 0 && max <= 0) { return -1 * (random.nextInt(Math.abs(min - max)) + Math.abs(max)); - } - else // min <= 0 && max >= 0 + } else // min <= 0 && max >= 0 { return random.nextInt(Math.abs(min) + Math.abs(max)) - Math.abs(min); } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/generators/SpawnPointsGenerator.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/generators/SpawnPointsGenerator.java similarity index 85% rename from src/main/java/eu/carrade/amaury/UHCReloaded/spawns/generators/SpawnPointsGenerator.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/generators/SpawnPointsGenerator.java index 3342a25..94d2ce4 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/spawns/generators/SpawnPointsGenerator.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spawns/generators/SpawnPointsGenerator.java @@ -29,24 +29,23 @@ * 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.spawns.generators; -import eu.carrade.amaury.UHCReloaded.spawns.exceptions.CannotGenerateSpawnPointsException; -import org.bukkit.Location; -import org.bukkit.World; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.generators; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spawns.exceptions.CannotGenerateSpawnPointsException; import java.util.Set; +import org.bukkit.Location; +import org.bukkit.World; /** * Represents a spawn points generator. * * <p> - * A zero-arguments constructor is needed. + * A zero-arguments constructor is needed. * </p> */ -public interface SpawnPointsGenerator -{ +public interface SpawnPointsGenerator { /** * Generates the spawn points. * @@ -59,10 +58,10 @@ public interface SpawnPointsGenerator * @param xCenter The x coordinate of the point in the center of the region where the points will be generated. * @param zCenter The z coordinate of the point in the center of the region where the points will be generated. * @param avoidWater True if the generation have to avoid the water. - * * @return The spawn points generated. - * * @throws CannotGenerateSpawnPointsException In case of fail. */ - Set<Location> generate(final World world, final int spawnCount, final int regionDiameter, final int minimalDistanceBetweenTwoPoints, final double xCenter, final double zCenter, final boolean avoidWater) throws CannotGenerateSpawnPointsException; + Set<Location> generate(final World world, final int spawnCount, final int regionDiameter, + final int minimalDistanceBetweenTwoPoints, final double xCenter, final double zCenter, + final boolean avoidWater) throws CannotGenerateSpawnPointsException; } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/Config.java new file mode 100644 index 0000000..e5c019b --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/Config.java @@ -0,0 +1,52 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + +public class Config extends ConfigurationInstance { + static public final ConfigurationItem<Boolean> SPECTATORS_CAN_JOIN = item("spectators-can-join", true); + static public final ConfigurationItem<Boolean> UNKNOWN_SPECTATORS_CAN_JOIN = + item("unknown-spectators-can-join", true); + static public final ConfigurationItem<Boolean> NOTIFY_ON_UNKNOWN_SPECTATORS_TRYING_TO_JOIN = + item("notify-on-unknown-spectators-trying-to-join", true); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHSpectatorPlusIntegration.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/SpectatorPlusDependency.java similarity index 65% rename from src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHSpectatorPlusIntegration.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/SpectatorPlusDependency.java index e6ff484..fcd6efb 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHSpectatorPlusIntegration.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/SpectatorPlusDependency.java @@ -30,84 +30,61 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.integration; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators; import com.pgcraft.spectatorplus.SpectateAPI; import com.pgcraft.spectatorplus.SpectatorPlus; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import fr.zcraft.zlib.tools.PluginLogger; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; +import fr.zcraft.quartzlib.external.ExternalPluginComponent; +import fr.zcraft.quartzlib.tools.PluginLogger; -public class UHSpectatorPlusIntegration -{ - private SpectatorPlus sp = null; +public class SpectatorPlusDependency extends ExternalPluginComponent<SpectatorPlus> { private SpectateAPI spAPI = null; - public UHSpectatorPlusIntegration() - { - Plugin spTest = Bukkit.getServer().getPluginManager().getPlugin("SpectatorPlus"); - if (spTest == null || !spTest.isEnabled()) - { - UHCReloaded.get().getLogger().warning("SpectatorPlus is not present, so the integration was disabled."); - return; - } - - this.sp = (SpectatorPlus) spTest; - + public SpectatorPlusDependency() { + super("SpectatorPlus"); + } - try - { + @Override + public void onLoad() { + try { Class.forName("com.pgcraft.spectatorplus.SpectateAPI"); - if (sp.getDescription().getVersion().equals("1.9.1")) - { + if (get().getDescription().getVersion().equals("1.9.1")) { // The API of SpectatorPlus 1.9.1 was not working. throw new ClassNotFoundException(); } } - catch (ClassNotFoundException e) - { + catch (ClassNotFoundException e) { PluginLogger.warning("SpectatorPlus is available, but the version you are using is too old."); - PluginLogger.warning("This plugin is tested and works with SpectatorPlus 1.9.2 or later. The SpectateAPI is needed."); + PluginLogger.warning( + "This plugin is tested and works with SpectatorPlus 1.9.2 or later. The SpectateAPI is needed."); - this.sp = null; + setEnabled(false); return; } // All is OK, let's integrate. - try - { - spAPI = sp.getAPI(); + try { + spAPI = get().getAPI(); PluginLogger.info("Successfully hooked into SpectatorPlus."); } // Generic catch block to catch any kind of exception (logged, anyway), including e.g. // NoSuchMethodError, if the API change, so the plugin is not broken. - catch (Throwable e) - { + catch (Throwable e) { PluginLogger.error("Cannot hook into SpectatorPlus, is this version compatible?", e); - - spAPI = null; - sp = null; + setEnabled(false); } } - public boolean isSPIntegrationEnabled() - { - return !(this.sp == null); - } - - public SpectatorPlus getSP() - { - return this.sp; + public SpectatorPlus getSP() { + return get(); } - public SpectateAPI getSPAPI() - { + public SpectateAPI getSPAPI() { return this.spAPI; } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/SpectatorsModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/SpectatorsModule.java new file mode 100644 index 0000000..616ad8d --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/SpectatorsModule.java @@ -0,0 +1,252 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.PlayerResurrectedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.commands.SpectatorsCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.managers.SpectatorsManager; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.Commands; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.components.rawtext.RawText; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerLoginEvent; + + +@ModuleInfo( + name = "Spectators Manager", + description = "Handles non-playing players.", + when = ModuleLoadTime.POST_WORLD, + category = ModuleCategory.CORE, + icon = Material.ENDER_EYE, + settings = Config.class, + can_be_unloaded = false +) +public class SpectatorsModule extends QSGModule { + /** + * Lists players allowed to spectate. Also used for initial spectators: players who will + * never play, only spectate. + */ + private final Set<UUID> spectators = new HashSet<>(); + /** + * When external spectators are disallowed, a message is sent once to inform administrators + * how to accept them if they wish to. + */ + private final Set<UUID> broadcastedUnknownSpectators = new HashSet<>(); + private SpectatorsManager manager; + private SpectatorPlusDependency spectatorPlusDependency; + + @Override + protected void onEnable() { + manager = SpectatorsManager.getInstance(); + } + + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(SpectatorsCommand.class); + } + + /** + * @return The manager instance to use to handle spectators. + */ + public SpectatorsManager getManager() { + return manager; + } + + /** + * @return The allowed spectators. + */ + public Set<UUID> getSpectators() { + return spectators; + } + + public boolean isSpectator(final UUID playerID) { + return spectators.contains(playerID); + } + + public boolean isSpectator(final OfflinePlayer player) { + return spectators.contains(player.getUniqueId()); + } + + /** + * Adds a spectator. + * + * @param playerID The spectator's ID. + */ + public void addSpectator(final UUID playerID) { + spectators.add(playerID); + + if (QSG.module(GameModule.class).getPhase() != GamePhase.WAIT) { + RunTask.nextTick(() -> manager.setSpectating(playerID, true)); + } + } + + /** + * Adds a spectator. + * + * @param player The spectator. + */ + public void addSpectator(final OfflinePlayer player) { + addSpectator(player.getUniqueId()); + } + + /** + * Removes a spectator. + * + * @param playerID The spectator's ID. + */ + public void removeSpectator(final UUID playerID) { + spectators.remove(playerID); + + if (QSG.module(GameModule.class).getPhase() != GamePhase.WAIT) { + RunTask.nextTick(() -> manager.setSpectating(playerID, false)); + } + } + + /** + * Removes a spectator. + * + * @param player The spectator. + */ + public void removeSpectator(final OfflinePlayer player) { + removeSpectator(player.getUniqueId()); + } + + /** + * Ensures all players are in specator mode. + * + * @param strict If true, all spectating players not in our list are removed from the spectator mode. + * Else, only players in our list are placed into spectator mode. + */ + private void ensureSpectatorMode(final boolean strict) { + if (strict) { + Bukkit.getOnlinePlayers().forEach(player -> manager.setSpectating(player, isSpectator(player))); + } else { + spectators.forEach(spectator -> manager.setSpectating(spectator, true)); + } + } + + @EventHandler + public void onGameStart(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() != GamePhase.IN_GAME) { + return; + } + + ensureSpectatorMode(true); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerDeath(final AlivePlayerDeathEvent ev) { + addSpectator(ev.getPlayer()); + } + + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerResurrects(final PlayerResurrectedEvent ev) { + removeSpectator(ev.getPlayer()); + } + + @EventHandler + public void onPlayerLogin(final PlayerLoginEvent ev) { + final GameModule game = QSG.module(GameModule.class); + + if (game.currentPhaseBefore(GamePhase.IN_GAME)) { + return; + } + + // TODO Permissions + if (ev.getPlayer().isOp()) { + ev.allow(); + return; + } + + if (!Config.SPECTATORS_CAN_JOIN.get() && !game.isAlive(ev.getPlayer())) { + ev.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, I.t("Spectators are not allowed for this game.")); + return; + } else if (!Config.UNKNOWN_SPECTATORS_CAN_JOIN.get() && + !(game.isAlive(ev.getPlayer()) || isSpectator(ev.getPlayer()))) { + ev.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, + I.t("External spectators are not allowed for this game.")); + + if (Config.NOTIFY_ON_UNKNOWN_SPECTATORS_TRYING_TO_JOIN.get() && + broadcastedUnknownSpectators.add(ev.getPlayer().getUniqueId())) { + final String command = + Commands.getCommandInfo(SpectatorsCommand.class).build("add", ev.getPlayer().getName()); + + log().broadcastAdministrative( + new RawText( + I.t("{gray}The unknown player {0} just tried to join. To allow him to spectate, execute {cc}{1} or click here.", + ev.getPlayer().getName(), command)) + .hover(I.t("Click here to execute\n{0}", command)) + .command(command) + ); + } + + return; + } + + // Here the spectator is allowed. If it's new, we add it to the list. + if (!game.isAlive(ev.getPlayer()) && !isSpectator(ev.getPlayer())) { + addSpectator(ev.getPlayer()); + } + } + + @EventHandler + public void onPlayerJoin(final PlayerJoinEvent ev) { + if (QSG.module(GameModule.class).getPhase().ordinal() >= GamePhase.IN_GAME.ordinal()) { + manager.setSpectating(ev.getPlayer(), isSpectator(ev.getPlayer())); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/commands/SpectatorsCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/commands/SpectatorsCommand.java new file mode 100644 index 0000000..19d17b7 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/commands/SpectatorsCommand.java @@ -0,0 +1,162 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.SpectatorsModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.OfflinePlayersLoader; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.CommandSender; + + +@CommandInfo(name = "spectators", usageParameters = "[add <player>] [remove <player>]", aliases = {"spec", "sp"}) +public class SpectatorsCommand extends Command { + @Override + protected void run() throws CommandException { + // /uh spec + if (args.length == 0) { + final Set<String> spectators = QSG.module(SpectatorsModule.class) + .getSpectators().stream() + .map(uuid -> Bukkit.getOfflinePlayer(uuid).getName()) + .collect(Collectors.toSet()); + + if (spectators.size() == 0) { + error(I.t("{ce}There isn't any spectator to list.")); + } else { + info(""); + info(I.tn("{ci}{0} registered spectator.", "{ci}{0} registered spectators.", spectators.size())); + + /// A list item in the startup spectators list + spectators.stream().map(spectator -> I.tc("startup_specs", "{lightpurple} - {0}", spectator)) + .forEach(this::info); + } + } else { + switch (args[0].toLowerCase()) { + case "add": + case "a": + // /uh spec add + if (args.length == 1) { + throwInvalidArgument(I.t("Please add the player you want to register as spectator.")); + } + + // /uh spec add <player> + else { + final CommandSender finalSender = sender; + + OfflinePlayersLoader.loadPlayer(args[1], player -> { + if (player == null) { + finalSender.sendMessage(I.t("{ce}Unable to retrieve the player {0}.")); + + if (!Bukkit.getOnlineMode()) { + finalSender.sendMessage( + I.t("{ce}In offline mode, you cannot add players if they never came to this server.")); + } + + return; + } + + QSG.module(SpectatorsModule.class).addSpectator(player); + finalSender.sendMessage(I.t("{cs}The player {0} is now a spectator.", player.getName())); + }); + } + + break; + + case "remove": + case "r": + // /uh spec remove + if (args.length == 1) { + throwInvalidArgument(I.t("Please add the player you want to unregister from spectators.")); + } + + // /uh spec remove <player> + else { + final OfflinePlayer oldSpectator = OfflinePlayersLoader.getOfflinePlayer(args[1]); + if (oldSpectator == null) { + error(I.t("{ce}The player {0} was not found.", args[1])); + } else { + QSG.module(SpectatorsModule.class).removeSpectator(oldSpectator); + success(I.t("{cs}The player {0} is now a player.", args[1])); + } + } + + break; + } + } + } + + @Override + protected List<String> complete() { + if (args.length == 1) { + return getMatchingSubset(args[0], "add", "remove"); + } else if (args.length == 2) { + switch (args[0].toLowerCase()) { + case "add": + case "a": + return getMatchingSubset( + Arrays.stream(Bukkit.getOfflinePlayers()) + .filter(player -> !QSG.module(SpectatorsModule.class).isSpectator(player)) + .map(OfflinePlayer::getName) + .collect(Collectors.toList()), + args[1] + ); + + case "remove": + case "r": + return getMatchingSubset( + Arrays.stream(Bukkit.getOfflinePlayers()) + .filter(player -> QSG.module(SpectatorsModule.class).isSpectator(player)) + .map(OfflinePlayer::getName) + .collect(Collectors.toList()), + args[1] + ); + + default: + return null; + } + } else { + return null; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SPlusSpectatorsManager.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/managers/SPlusSpectatorsManager.java similarity index 72% rename from src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SPlusSpectatorsManager.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/managers/SPlusSpectatorsManager.java index 6541aca..98f3880 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SPlusSpectatorsManager.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/managers/SPlusSpectatorsManager.java @@ -29,36 +29,33 @@ * 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; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.managers; + +import com.pgcraft.spectatorplus.SpectateAPI; import org.bukkit.entity.Player; /** * Spectators managed through the SpectatorsPlus Bukkit plugin by PGMann and AmauryPi. */ -public class SPlusSpectatorsManager extends SpectatorsManager -{ - private UHCReloaded p; +public class SPlusSpectatorsManager extends SpectatorsManager { + private final SpectateAPI api; + + public SPlusSpectatorsManager(final SpectateAPI api) { - public SPlusSpectatorsManager() - { - p = UHCReloaded.get(); + this.api = api; } @Override - public void setSpectating(final Player player, final boolean spectating) - { - if (player != null && p.getSpectatorPlusIntegration().isSPIntegrationEnabled()) - p.getSpectatorPlusIntegration().getSPAPI().setSpectating(player, spectating); + public void setSpectating(final Player player, final boolean spectating) { + if (player != null) { + api.setSpectating(player, spectating); + } } @Override - public boolean isSpectating(Player player) - { - return player != null - && p.getSpectatorPlusIntegration().isSPIntegrationEnabled() - && p.getSpectatorPlusIntegration().getSPAPI().isSpectator(player); + public boolean isSpectating(final Player player) { + return player != null && api.isSpectator(player); } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SpectatorsManager.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/managers/SpectatorsManager.java similarity index 81% rename from src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SpectatorsManager.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/managers/SpectatorsManager.java index 8acba07..61d8e1a 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/SpectatorsManager.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/managers/SpectatorsManager.java @@ -29,20 +29,38 @@ * 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; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.managers; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.SpectatorPlusDependency; +import fr.zcraft.quartzlib.core.QuartzLib; import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; /** * Represents a spectator manager, able to put players in or remove players from spectator mode. */ -public abstract class SpectatorsManager -{ +public abstract class SpectatorsManager { + private final static SpectatorPlusDependency spectatorPlusDependency; + + static { + spectatorPlusDependency = QuartzLib.loadComponent(SpectatorPlusDependency.class); + } + + /** + * @return an instance of a {@link SpectatorsManager}: {@link SPlusSpectatorsManager} if the + * SpectatorPlus plugin is available; {@link VanillaSpectatorsManager} else. + */ + public static SpectatorsManager getInstance() { + if (spectatorPlusDependency.isEnabled()) { + return new SPlusSpectatorsManager(spectatorPlusDependency.getSPAPI()); + } else { + return new VanillaSpectatorsManager(); + } + } + /** * Changes the spectating mode of a player. * @@ -55,7 +73,6 @@ public abstract class SpectatorsManager * Checks if the given player is currently spectating. * * @param player The player. - * * @return {@code true} if spectating. */ public abstract boolean isSpectating(final Player player); @@ -66,8 +83,7 @@ public abstract class SpectatorsManager * @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) - { + public void setSpectating(final UUID playerID, final boolean spectating) { setSpectating(Bukkit.getPlayer(playerID), spectating); } @@ -75,24 +91,9 @@ public void setSpectating(final UUID playerID, final boolean 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) - { + 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/quartzsurvivalgames/modules/core/spectators/managers/VanillaSpectatorsManager.java similarity index 79% rename from src/main/java/eu/carrade/amaury/UHCReloaded/spectators/VanillaSpectatorsManager.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/managers/VanillaSpectatorsManager.java index 81d175c..a9e7c4b 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/spectators/VanillaSpectatorsManager.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/spectators/managers/VanillaSpectatorsManager.java @@ -29,55 +29,47 @@ * 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; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.managers; -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; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; /** * Vanilla spectator mode */ -public class VanillaSpectatorsManager extends SpectatorsManager -{ +public class VanillaSpectatorsManager extends SpectatorsManager { /** * Stores the previous gamemodes of the players. */ - private Map<UUID, GameMode> oldGameModes = new HashMap<>(); + private final Map<UUID, GameMode> oldGameModes = new HashMap<>(); @Override - public void setSpectating(final Player player, final boolean spectating) - { - if (player == null) + public void setSpectating(final Player player, final boolean spectating) { + if (player == null) { return; + } - if (spectating) - { - if (player.getGameMode() != GameMode.SPECTATOR) - { + 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()); - + } else { + player.setGameMode(oldGameModes.getOrDefault(player.getUniqueId(), Bukkit.getDefaultGameMode())); oldGameModes.remove(player.getUniqueId()); } } @Override - public boolean isSpectating(Player player) - { + public boolean isSpectating(Player player) { return player != null && player.getGameMode() == GameMode.SPECTATOR; } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/teams/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/teams/Config.java new file mode 100644 index 0000000..0735828 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/teams/Config.java @@ -0,0 +1,127 @@ +/* + * 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.quartzsurvivalgames.modules.core.teams; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.section; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.configuration.ConfigurationSection; +import fr.zcraft.quartzlib.tools.items.ColorableMaterial; +import java.io.File; + + +public class Config extends ConfigurationInstance { + static public final ConfigurationItem<Boolean> CAN_SEE_FRIENDLY_INVISIBLES = + item("can-see-friendly-invisibles", true); + static public final ConfigurationItem<Boolean> ALLOW_FRIENDLY_FIRE = item("allow-friendly-fire", true); + static public final ConfigurationItem<Integer> MAX_PLAYERS_PER_TEAM = item("max-players-per-team", 0); + static public final ConfigurationItem<Boolean> COLORIZE_CHAT = item("colorize-chat", true); + static public final BannerSection BANNER = section("banner", BannerSection.class); + static public final ChestGuiSection GUI = section("gui", ChestGuiSection.class); + static public final TeamChatSection TEAM_CHAT = section("team-chat", TeamChatSection.class); + static public final SidebarSection SIDEBAR = section("sidebar", SidebarSection.class); + + public Config(File file) { + super(file); + } + + static public class BannerSection extends ConfigurationSection { + public final ShapeSection SHAPE = section("shape", ShapeSection.class); + public final GiveSection GIVE = section("give", GiveSection.class); + public final ShieldSection SHIELDS = section("shields", ShieldSection.class); + + static public class ShapeSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> WRITE_LETTER = item("write-letter", true); + public final ConfigurationItem<Boolean> ADD_BORDER = item("add-border", true); + } + + static public class GiveSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> PLACE_ON_SPAWN = item("place-on-spawn", true); + public final ConfigurationItem<Boolean> GIVE_IN_HOTBAR = item("give-in-hotbar", false); + public final ConfigurationItem<Boolean> GIVE_ON_HEAD = item("give-on-head", false); + } + + static public class ShieldSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ADD_ON_SHIELDS = item("add-on-shields", true); + } + } + + static public class ChestGuiSection extends ConfigurationSection { + public final DisplaySection DISPLAY = section("display", DisplaySection.class); + + static public class DisplaySection extends ConfigurationSection { + public final ConfigurationItem<ColorableMaterial> TEAM_ITEM = item("team-item", ColorableMaterial.BANNER); + public final ConfigurationItem<Boolean> GLOW_ON_SELECTED_TEAM = item("glow-on-selected-team", true); + } + } + + static public class TeamChatSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> DISABLE_LOCK_ON_DEATH = item("disable-lock-on-death", true); + public final ConfigurationItem<Boolean> LOG = item("log", false); + } + + static public class SidebarSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ENABLED = item("enabled", true); + + public final TitleSection TITLE = section("title", TitleSection.class); + public final ContentSection CONTENT = section("content", ContentSection.class); + + static public class TitleSection extends ConfigurationSection { + public final ConfigurationItem<String> COLOR = item("color", ""); + public final ConfigurationItem<Boolean> USE_TEAM_NAME = item("use-team-name", false); + } + + static public class ContentSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> DISPLAY_HEARTS = item("display-hearts", true); + public final ConfigurationItem<Boolean> COLOR_NAME = item("color-name", false); + public final ConfigurationItem<Boolean> STRIKE_DEAD_PLAYERS = item("strike-dead-players", false); + + public final LoginStateSection LOGIN_STATE = section("login-state", LoginStateSection.class); + public final DisplayMetPlayersOnlySection DISPLAY_MET_PLAYERS_ONLY = + section("display-met-players-only", DisplayMetPlayersOnlySection.class); + + static public class LoginStateSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ITALIC = item("italic", true); + public final ConfigurationItem<String> SUFFIX = item("suffix", "➥"); + } + + static public class DisplayMetPlayersOnlySection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ENABLED = item("enabled", false); + public final ConfigurationItem<Double> DISPLAYED_WHEN_CLOSER_THAN = + item("displayed-when-closer-than", 10d); + } + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/teams/TeamsModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/teams/TeamsModule.java new file mode 100644 index 0000000..f2deade --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/teams/TeamsModule.java @@ -0,0 +1,371 @@ +/* + * 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.quartzsurvivalgames.modules.core.teams; + +import com.google.common.collect.ImmutableMap; +import eu.carrade.amaury.quartzsurvivalgames.QuartzSurvivalGames; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.teams.sidebar.SidebarCacheListener; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.teams.sidebar.SidebarPlayerCache; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.core.QuartzLib; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import fr.zcraft.quartzteams.QuartzTeam; +import fr.zcraft.quartzteams.QuartzTeams; +import fr.zcraft.quartzteams.commands.GlobalChatCommand; +import fr.zcraft.quartzteams.commands.MyTeamCommand; +import fr.zcraft.quartzteams.commands.TeamChatCommand; +import fr.zcraft.quartzteams.commands.TeamsCommand; +import fr.zcraft.quartzteams.commands.TeamsGuiCommand; +import fr.zcraft.quartzteams.commands.ToggleChatCommand; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.UUID; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.block.Banner; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.inventory.PrepareItemCraftEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.meta.BannerMeta; +import org.bukkit.inventory.meta.BlockStateMeta; + + +@ModuleInfo( + name = "Teams", + description = "Manages the teams and related commands.", + category = ModuleCategory.CORE, + icon = Material.NETHER_STAR, + settings = Config.class, + internal = true, + can_be_unloaded = false +) +public class TeamsModule extends QSGModule { + private final String HEART = "\u2764"; + private final Map<UUID, SidebarPlayerCache> sidebarCache = new HashMap<>(); + private double TEAMMATES_DISTANCE_SQUARED; + private GameModule game = null; + + @Override + protected void onEnable() { + QuartzLib.loadComponent(QuartzTeams.class); + + QuartzTeams.settings() + .setScoreboard(QuartzSurvivalGames.get().getScoreboard()) + .setTeamsOptions( + Config.CAN_SEE_FRIENDLY_INVISIBLES.get(), + Config.ALLOW_FRIENDLY_FIRE.get(), + Config.COLORIZE_CHAT.get(), + false + ) + .setTeamsChatOptions( + Config.TEAM_CHAT.LOG.get() + ) + .setBannerOptions( + Config.BANNER.SHAPE.WRITE_LETTER.get(), + Config.BANNER.SHAPE.ADD_BORDER.get() + ) + .setGUIOptions( + Config.GUI.DISPLAY.TEAM_ITEM.get(), + Config.GUI.DISPLAY.GLOW_ON_SELECTED_TEAM.get() + ) + .setMaxPlayersPerTeam(Config.MAX_PLAYERS_PER_TEAM.get()); + + TEAMMATES_DISTANCE_SQUARED = + Math.pow(Config.SIDEBAR.CONTENT.DISPLAY_MET_PLAYERS_ONLY.DISPLAYED_WHEN_CLOSER_THAN.get(), 2d); + } + + @EventHandler + public void onGameStarting(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() != GamePhase.STARTING) { + return; + } + QuartzLib.registerEvents(new SidebarCacheListener()); + } + + @Override + public List<Class<? extends Command>> getCommands() { + return Arrays.asList( + TeamsCommand.class, + TeamChatCommand.class, + GlobalChatCommand.class, + ToggleChatCommand.class, + TeamsGuiCommand.class, + MyTeamCommand.class + ); + } + + @Override + public Map<String, Class<? extends Command>> getCommandsAliases() { + return ImmutableMap.of( + "t", TeamChatCommand.class, + "g", GlobalChatCommand.class, + "togglechat", ToggleChatCommand.class, + "teams", TeamsGuiCommand.class, + "team", MyTeamCommand.class + ); + } + + @Override + public void injectIntoSidebar(final Player player, final SidebarInjector injector) { + if (game == null) { + game = QSG.module(GameModule.class); + } + if (game == null) { + return; // Module not ready + } + + if (!game.isTeamsGame() || !Config.SIDEBAR.ENABLED.get() || + game.getPhase().ordinal() < GamePhase.IN_GAME.ordinal()) { + return; + } + + final QuartzTeam team = QuartzTeams.get().getTeamForPlayer(player); + + if (team == null) { + return; + } + + + /* *** TEAM NAME *** */ + + injector.injectLines( + true, false, + (Config.SIDEBAR.TITLE.COLOR.get().isEmpty() ? team.getColorOrWhite().toChatColor() : + Config.SIDEBAR.TITLE.COLOR.get()) + + (Config.SIDEBAR.TITLE.USE_TEAM_NAME.get() ? ChatColor.BOLD + team.getName() : + I.t("{bold}Your team")) + ); + + + /* *** TEAM PLAYERS: WHICH ONES *** */ + + final Set<OfflinePlayer> displayedPlayers = new TreeSet<>((player1, player2) -> { + if (player1.equals(player2)) { + return 0; + } + if (game.isAlive(player1) != game.isAlive(player2)) { + return game.isAlive(player1) ? -1 : 1; + } + return player1.getName().toLowerCase().compareTo(player2.getName().toLowerCase()); + }); + + final SidebarPlayerCache playerCache = getSidebarPlayerCache(player.getUniqueId()); + + if (Config.SIDEBAR.CONTENT.DISPLAY_MET_PLAYERS_ONLY.ENABLED.get()) { + playerCache.updateTeammatesDisplayed(TEAMMATES_DISTANCE_SQUARED, player.getLocation(), team); + displayedPlayers.addAll(playerCache.getMetTeammates()); + } else { + displayedPlayers.addAll(team.getPlayers()); + } + + + /* *** TEAM PLAYERS: DISPLAY *** */ + + final List<String> playersSidebar = new ArrayList<>(); + + displayedPlayers.forEach(displayedPlayer -> { + final SidebarPlayerCache cache = getSidebarPlayerCache(displayedPlayer.getUniqueId()); + final boolean alive = game.isAlive(displayedPlayer); + + final String strike = + Config.SIDEBAR.CONTENT.STRIKE_DEAD_PLAYERS.get() && !alive ? ChatColor.STRIKETHROUGH.toString() : + ""; + final ChatColor aliveColor = alive ? ChatColor.WHITE : ChatColor.GRAY; + + final String heart = + Config.SIDEBAR.CONTENT.DISPLAY_HEARTS.get() ? cache.getHealthColor() + strike + HEART + " " : ""; + final String name = (Config.SIDEBAR.CONTENT.COLOR_NAME.get() ? cache.getHealthColor() : aliveColor) + + strike + + (Config.SIDEBAR.CONTENT.LOGIN_STATE.ITALIC.get() && !cache.isOnline() ? ChatColor.ITALIC : "") + + cache.getPlayerName() + + (!cache.isOnline() ? ChatColor.RESET + "" + + (Config.SIDEBAR.CONTENT.COLOR_NAME.get() ? cache.getHealthColor() : aliveColor) + " " + + Config.SIDEBAR.CONTENT.LOGIN_STATE.SUFFIX.get() : ""); + + playersSidebar.add(heart + name); + }); + + injector.injectLines(false, true, playersSidebar); + } + + /** + * Returns the cached data about the given player. + * + * @param id The player's UUID. + * @return The cached data, created on the fly if needed. + */ + public SidebarPlayerCache getSidebarPlayerCache(final UUID id) { + return sidebarCache.computeIfAbsent(id, SidebarPlayerCache::new); + } + + @EventHandler + public void onGameStart(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() != GamePhase.IN_GAME || !ev.isRunningForward()) { + return; + } + + if (Config.BANNER.GIVE.GIVE_IN_HOTBAR.get() || Config.BANNER.GIVE.GIVE_ON_HEAD.get() || + Config.BANNER.GIVE.PLACE_ON_SPAWN.get()) { + RunTask.later(() -> + QuartzTeams.get().getTeams().stream().filter(team -> !team.isEmpty()).forEach(team -> + { + final ItemStack banner = team.getBanner(); + + team.getOnlinePlayers().forEach(player -> + { + if (Config.BANNER.GIVE.GIVE_IN_HOTBAR.get()) { + player.getInventory().setItem(8, banner.clone()); + } + + if (Config.BANNER.GIVE.GIVE_ON_HEAD.get()) { + player.getInventory().setHelmet(banner.clone()); + } + + if (Config.BANNER.GIVE.PLACE_ON_SPAWN.get()) { + final Block place = player.getWorld().getHighestBlockAt(player.getLocation()); + final Block under = place.getRelative(BlockFace.DOWN); + + // We don't want a stack of banners + if (!under.getType().name().endsWith("_BANNER")) { + if (!under.getType().isSolid()) { + under.setType(Material.STRIPPED_OAK_WOOD); + } + + place.setType(banner.getType()); + + Banner bannerBlock = (Banner) place.getState(); + BannerMeta bannerMeta = (BannerMeta) banner.getItemMeta(); + + bannerBlock.setPatterns(bannerMeta.getPatterns()); + + bannerBlock.update(); + } + } + }); + }), 5L); + } + } + + /** + * Adds the team banner on crafted shields. + * <p> + * Done indirectly because the plugin must be able to run + * on Minecraft 1.8. + */ + @EventHandler(ignoreCancelled = true) + public void onShieldPreCraft(final PrepareItemCraftEvent ev) { + if (!Config.BANNER.SHIELDS.ADD_ON_SHIELDS.get()) { + return; + } + + // The viewers list is empty for crafts from the small crafting + // grid in the inventory. In this case we use another data source. + final Player player = + !ev.getViewers().isEmpty() ? (Player) ev.getViewers().get(0) : (Player) ev.getView().getPlayer(); + if (player == null) { + return; + } + + final QuartzTeam team = QuartzTeams.get().getTeamForPlayer(player); + if (team == null || team.getBanner() == null) { + return; + } + + final Recipe recipe = ev.getRecipe(); + if (recipe == null) { + return; + } + + final ItemStack result = recipe.getResult(); + if (result == null) { + return; + } + + final Material MATERIAL_SHIELD = Material.getMaterial("SHIELD"); + if (MATERIAL_SHIELD == null) { + return; // MC 1.8 + } + + if (result.getType() == MATERIAL_SHIELD) { + try { + final BannerMeta banner = (BannerMeta) team.getBanner().getItemMeta(); + + final BlockStateMeta bsMeta = (BlockStateMeta) result.getItemMeta(); + final Banner shieldBanner = (Banner) bsMeta.getBlockState(); + + shieldBanner.setBaseColor(banner.getBaseColor()); + shieldBanner.setPatterns(banner.getPatterns()); + + shieldBanner.update(); + + bsMeta.setBlockState(shieldBanner); + result.setItemMeta(bsMeta); + + ev.getInventory().setResult(result); + } + catch (ClassCastException | NullPointerException ignored) { + // Bad Minecraft version (1.8) + } + } + } + + @EventHandler + public void onPlayerDeath(final AlivePlayerDeathEvent ev) { + // Disables the team-chat-lock if needed + if (Config.TEAM_CHAT.DISABLE_LOCK_ON_DEATH.get()) { + if (QuartzTeams.chatManager().isTeamChatEnabled(ev.getPlayer().getUniqueId())) { + QuartzTeams.chatManager().toggleChatForPlayer(ev.getPlayer().getUniqueId()); + } + } + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/ScoreboardListener.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/teams/sidebar/SidebarCacheListener.java similarity index 59% rename from src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/ScoreboardListener.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/teams/sidebar/SidebarCacheListener.java index ef97f3d..6a07532 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/ScoreboardListener.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/teams/sidebar/SidebarCacheListener.java @@ -29,12 +29,15 @@ * 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.scoreboard; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.events.UHPlayerDeathEvent; -import eu.carrade.amaury.UHCReloaded.events.UHPlayerResurrectedEvent; -import fr.zcraft.zlib.tools.runners.RunTask; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.teams.sidebar; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.PlayerResurrectedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.teams.TeamsModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.tools.runners.RunTask; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -46,79 +49,68 @@ import org.bukkit.event.player.PlayerQuitEvent; -public class ScoreboardListener implements Listener -{ +public class SidebarCacheListener implements Listener { + private final static GameModule game = QSG.module(GameModule.class); + private final static TeamsModule teams = QSG.module(TeamsModule.class); + @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerJoin(PlayerJoinEvent ev) - { - final SidebarPlayerCache cache = UHCReloaded.get().getScoreboardManager().getSidebarPlayerCache(ev.getPlayer().getUniqueId()); + public void onPlayerJoin(PlayerJoinEvent ev) { + final SidebarPlayerCache cache = teams.getSidebarPlayerCache(ev.getPlayer().getUniqueId()); cache.updateName(ev.getPlayer().getName()); cache.updateOnlineStatus(true); + + // To be sure (and if the player was killed/resurrected while offline) + onPlayerHealthChange(ev.getPlayer()); } @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerQuit(PlayerQuitEvent ev) - { + public void onPlayerQuit(PlayerQuitEvent ev) { onPlayerQuit(ev.getPlayer()); } @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerQuit(PlayerKickEvent ev) - { + public void onPlayerQuit(PlayerKickEvent ev) { onPlayerQuit(ev.getPlayer()); } @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerRegainHealth(EntityRegainHealthEvent ev) - { - if (ev.getEntity() instanceof Player) + public void onPlayerRegainHealth(EntityRegainHealthEvent ev) { + if (ev.getEntity() instanceof Player) { onPlayerHealthChange((Player) ev.getEntity()); + } } @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerLoseHealth(EntityDamageEvent ev) - { - if (ev.getEntity() instanceof Player) + public void onPlayerLoseHealth(EntityDamageEvent ev) { + if (ev.getEntity() instanceof Player) { onPlayerHealthChange((Player) ev.getEntity()); + } } @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerDeath(UHPlayerDeathEvent ev) - { - onPlayerHealthChange(ev.getPlayer()); - - if (ev.getPlayerDeathEvent().getEntity().getKiller() != null) - { - UHCReloaded.get().getScoreboardManager() - .getSidebarPlayerCache(ev.getPlayerDeathEvent().getEntity().getKiller().getUniqueId()) - .getPlayersKilled().add(ev.getPlayer().getUniqueId()); + public void onPlayerDeath(AlivePlayerDeathEvent ev) { + if (ev.getPlayer().isOnline()) { + onPlayerHealthChange(ev.getPlayer().getPlayer()); } } @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerResurrect(UHPlayerResurrectedEvent ev) - { - onPlayerHealthChange(ev.getPlayer()); - - for (SidebarPlayerCache cache : UHCReloaded.get().getScoreboardManager().getAllSidebarPlayerCache().values()) - { - if (cache.getPlayersKilled().remove(ev.getPlayer().getUniqueId())) - break; + public void onPlayerResurrect(PlayerResurrectedEvent ev) { + if (ev.getPlayer().isOnline()) { + onPlayerHealthChange(ev.getPlayer().getPlayer()); } } - private void onPlayerQuit(Player player) - { - UHCReloaded.get().getScoreboardManager().getSidebarPlayerCache(player.getUniqueId()).updateOnlineStatus(false); + private void onPlayerQuit(Player player) { + teams.getSidebarPlayerCache(player.getUniqueId()).updateOnlineStatus(false); } - private void onPlayerHealthChange(final Player player) - { + private void onPlayerHealthChange(final Player player) { // One tick later to use the updated health value. RunTask.nextTick(() -> { - final SidebarPlayerCache cache = UHCReloaded.get().getScoreboardManager().getSidebarPlayerCache(player.getUniqueId()); - cache.updateHealth(UHCReloaded.get().getGameManager().isPlayerDead(player.getUniqueId()) ? 0d : player.getHealth()); + final SidebarPlayerCache cache = teams.getSidebarPlayerCache(player.getUniqueId()); + cache.updateHealth(game.isAlive(player.getUniqueId()) ? player.getHealth() : 0d); }); } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/teams/sidebar/SidebarPlayerCache.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/teams/sidebar/SidebarPlayerCache.java new file mode 100644 index 0000000..a375ffb --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/teams/sidebar/SidebarPlayerCache.java @@ -0,0 +1,174 @@ +/* + * 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.quartzsurvivalgames.modules.core.teams.sidebar; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.OfflinePlayersLoader; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzteams.QuartzTeam; +import fr.zcraft.quartzteams.QuartzTeams; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + + +/** + * This class stores the data displayed in the sidebar for a player, like the color, the health, the name... + */ +public class SidebarPlayerCache { + private final Set<UUID> metTeammates = new HashSet<>(); + private final UUID playerID; + private String playerName; + private ChatColor healthColor = ChatColor.WHITE; + private boolean isOnline; + + + public SidebarPlayerCache(final UUID id) { + playerID = id; + + final OfflinePlayer player = Bukkit.getOfflinePlayer(id); + + if (player != null) { + playerName = player.getName(); + isOnline = player.isOnline(); + + if (isOnline) { + updateHealth(player.getPlayer().getHealth()); + } + } else { + playerName = null; + isOnline = false; + } + } + + public void updateName(String name) { + playerName = name; + } + + public void updateHealth(double health) { + if (health <= 0) { + healthColor = ChatColor.GRAY; + } else if (health <= 4.1) { + healthColor = ChatColor.DARK_RED; + } else if (health <= 8.1) { + healthColor = ChatColor.RED; + } else if (health <= 12.1) { + healthColor = ChatColor.YELLOW; + } else if (health <= 16.1) { + healthColor = ChatColor.GREEN; + } else { + healthColor = ChatColor.DARK_GREEN; + } + } + + public void updateOnlineStatus(boolean isOnline) { + this.isOnline = isOnline; + } + + public UUID getPlayerID() { + return playerID; + } + + public String getPlayerName() { + if (playerName != null && !playerName.isEmpty()) { + return playerName; + } + + final OfflinePlayer player = OfflinePlayersLoader.getOfflinePlayer(playerID); + if (player != null && player.getName() != null && !player.getName().isEmpty()) { + playerName = player.getName(); + return playerName; + } + + /// Default nick name when a player cannot be recognized. + return I.t("Unknown"); + } + + public ChatColor getHealthColor() { + return healthColor; + } + + public boolean isOnline() { + return isOnline; + } + + public Set<OfflinePlayer> getMetTeammates() { + return metTeammates.stream() + .map(Bukkit::getOfflinePlayer) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + public void updateTeammatesDisplayed(final double distanceThreshold) { + final Player player = Bukkit.getPlayer(playerID); + if (player != null) { + updateTeammatesDisplayed( + distanceThreshold * distanceThreshold, + player.getLocation(), + QuartzTeams.get().getTeamForPlayer(playerID) + ); + } + } + + public void updateTeammatesDisplayed(final double distanceThresholdSquared, final Location reference, + final QuartzTeam team) { + final GameModule game = QSG.module(GameModule.class); + + // For each non-encountered online teammate, we check if they are close + team.getOnlinePlayers().stream() + .filter(p -> !metTeammates.contains(p.getUniqueId())) + .filter(game::isAlive) + .forEach(p -> { + if (p.getWorld() == null) { + return; + } + if (!p.getWorld().equals(reference.getWorld())) { + return; + } + if (p.getLocation().distanceSquared(reference) > distanceThresholdSquared) { + return; + } + + // Close enough + metTeammates.add(p.getUniqueId()); + }); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/TimeDelta.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/TimeDelta.java new file mode 100644 index 0000000..173fbfc --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/TimeDelta.java @@ -0,0 +1,207 @@ +/* + * 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.quartzsurvivalgames.modules.core.timers; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationParseException; +import fr.zcraft.quartzlib.components.configuration.ConfigurationValueHandler; +import fr.zcraft.quartzlib.components.configuration.ConfigurationValueHandlers; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Objects; + + +public class TimeDelta { + private static final NumberFormat formatter = new DecimalFormat("00"); + + static { + ConfigurationValueHandlers.registerHandlers(TimeDelta.class); + } + + private final long seconds; + + /** + * Constructs a time delta. + * + * @param seconds The number of seconds in this delta. + */ + public TimeDelta(long seconds) { + this.seconds = seconds; + } + + /** + * Constructs a time delta. + * + * @param hours The number of hours. + * @param minutes The number of minutes. + * @param seconds The number of seconds. + */ + public TimeDelta(long hours, long minutes, long seconds) { + this(seconds + minutes * 60 + hours * 3600); + } + + /** + * Constructs a time delta from a raw string representing a time. + * + * <p>Allowed formats: + * + * <ul> + * <li><tt>mm</tt> – number of minutes;</li> + * <li><tt>mm:ss</tt> – minutes and seconds;</li> + * <li><tt>hh:mm:ss</tt> – hours, minutes and seconds.</li> + * </ul> + * + * @param rawTime The raw time text. + * @throws IllegalArgumentException if the text is not formatted as above. + * @throws NumberFormatException if the text between the colons cannot be + * converted in integers. + */ + public TimeDelta(final String rawTime) throws IllegalArgumentException, NumberFormatException { + final String[] split = rawTime.split(":"); + + if (rawTime.isEmpty() || split.length > 3) { + throw new IllegalArgumentException( + "Badly formatted string in TimeDelta(String); formats allowed are mm, mm:ss or hh:mm:ss."); + } + + if (split.length == 1) // "mm" + { + this.seconds = Integer.valueOf(split[0]) * 60; + } else if (split.length == 2) // "mm:ss" + { + this.seconds = Integer.valueOf(split[0]) * 60 + Integer.valueOf(split[1]); + } else // "hh:mm:ss" + { + this.seconds = + Integer.valueOf(split[0]) * 3600 + Integer.valueOf(split[1]) * 60 + Integer.valueOf(split[2]); + } + } + + @ConfigurationValueHandler + public static TimeDelta handleTimeDelta(String rawDelta) throws ConfigurationParseException { + try { + return new TimeDelta(rawDelta); + } + catch (IllegalArgumentException e) { + throw new ConfigurationParseException("Invalid time delta format", rawDelta); + } + } + + /** + * @return The total number of seconds in this time delta. + */ + public long getSeconds() { + return seconds; + } + + /** + * @param other Another {@link TimeDelta}. + * @return {@code true} if the duration in this {@link TimeDelta} is less than + * (or equal to) the duration in the other one. + */ + public boolean lessThan(final TimeDelta other) { + return this.getSeconds() <= other.getSeconds(); + } + + /** + * @param other Another {@link TimeDelta}. + * @return {@code true} if the duration in this {@link TimeDelta} is greater + * than (or equal to) the duration in the other one. + */ + public boolean greaterThan(final TimeDelta other) { + return this.getSeconds() >= other.getSeconds(); + } + + /** + * @param other Another {@link TimeDelta} + * @return A new {@link TimeDelta} instance representing the sum of the two + * {@link TimeDelta deltas}. + */ + public TimeDelta add(final TimeDelta other) { + return new TimeDelta(this.getSeconds() + other.getSeconds()); + } + + /** + * @param other Another {@link TimeDelta} + * @return A new {@link TimeDelta} instance representing the subtraction of + * the two {@link TimeDelta deltas}. + */ + public TimeDelta subtract(final TimeDelta other) { + return new TimeDelta(this.getSeconds() - other.getSeconds()); + } + + /** + * @param factor A factor. + * @return A new {@link TimeDelta} instance representing the duration of this + * {@link TimeDelta delta} multiplied by the given factor. + */ + public TimeDelta multiply(final long factor) { + return new TimeDelta(this.getSeconds() * factor); + } + + /** + * @param factor A factor. + * @return A new {@link TimeDelta} instance representing the duration of this + * {@link TimeDelta delta} divided by the given factor. + */ + public TimeDelta divide(final long factor) { + return new TimeDelta(this.getSeconds() / factor); + } + + /** + * @return A string representation using the format “mm:ss” or “hh:mm:ss” if + * longer than one hour. + */ + @Override + public String toString() { + final long secondsLeft = seconds % 60; + final long minutesLeft = (seconds % 3600) / 60; + final long hoursLeft = (long) Math.floor(seconds / 3600.0); + + if (hoursLeft != 0) { + return formatter.format(hoursLeft) + ":" + formatter.format(minutesLeft) + ":" + + formatter.format(secondsLeft); + } else { + return formatter.format(minutesLeft) + ":" + formatter.format(secondsLeft); + } + } + + @Override + public boolean equals(Object o) { + return this == o || o != null && getClass() == o.getClass() && seconds == ((TimeDelta) o).seconds; + } + + @Override + public int hashCode() { + return Objects.hash(seconds); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/Timer.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/Timer.java new file mode 100644 index 0000000..d378cf5 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/Timer.java @@ -0,0 +1,357 @@ +/* + * 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.quartzsurvivalgames.modules.core.timers; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.events.TimerEndsEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.events.TimerStartsEvent; +import fr.zcraft.quartzlib.components.i18n.I; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.UUID; +import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; + + +/** + * Represents a timer. + * + * @author Amaury Carrade + */ +public class Timer { + private static final NumberFormat formatter = new DecimalFormat("00"); + + private final UUID id; + private final String name; + private Boolean registered = false; + private Boolean running = false; + private Boolean displayed = false; + private Boolean nameDisplayed = true; + + private Long startTime = 0L; + private Integer duration = 0; // seconds + + // Pause + private Boolean paused = false; + private Long pauseTime = 0L; + private Integer elapsedWhenPaused = 0; + + private Boolean system = false; + + + public Timer(String name) { + Validate.notNull(name, "The name cannot be null"); + + this.id = UUID.randomUUID(); // only used as a hashCode. + this.name = name; + } + + public Timer(final String name, final int seconds) { + this(name); + setDuration(seconds); + } + + public Timer(final String name, final TimeDelta duration) { + this(name, Math.toIntExact(duration.getSeconds())); + } + + /** + * Formats a given number of seconds into [hh:]mm:ss. + * + * @param seconds The number of seconds. + * @return The formatted time (includes color codes). + */ + public static String formatTime(final int seconds) { + final int secondsLeft = seconds % 60; + final int minutesLeft = (seconds % 3600) / 60; + final int hoursLeft = (int) Math.floor(seconds / 3600); + + if (hoursLeft != 0) { + /// Timer. {0} = hours; {1} = minutes; {2} = seconds. + return ChatColor.WHITE + I.t("{0}{gray}:{white}{1}{gray}:{white}{2}", formatter.format(hoursLeft), + formatter.format(minutesLeft), formatter.format(secondsLeft)); + } else { + /// Timer. {0} = minutes; {1} = seconds. + return ChatColor.WHITE + + I.t("{white}{0}{gray}:{white}{1}", formatter.format(minutesLeft), formatter.format(secondsLeft)); + } + } + + /** + * Starts this timer. + * <p> + * If this is called while the timer is running, the timer is restarted. + */ + public void start() { + this.running = true; + this.startTime = System.currentTimeMillis(); + + Bukkit.getServer().getPluginManager().callEvent(new TimerStartsEvent(this)); + } + + /** + * Stops this timer. + */ + public void stop() { + stop(false); + } + + /** + * Stops this timer. + * + * @param wasUp If true, the timer was stopped because the timer was up. + */ + private void stop(boolean wasUp) { + final TimerEndsEvent event = new TimerEndsEvent(this, wasUp); + Bukkit.getServer().getPluginManager().callEvent(event); + + if (isRegistered()) { + if (event.getRestart()) { + start(); + } else { + running = false; + startTime = 0L; + } + } + } + + /** + * Updates the timer to check if it is up and terminate it. + */ + public void update() { + if (running && !paused && getElapsed() >= getDuration()) { + stop(true); + } + } + + /** + * Pauses (or restarts after a pause) the timer. + * <p> + * If the timer is not running, nothing is done. + * + * @param pause If true the timer will be paused. + */ + public void setPaused(boolean pause) { + if (running) { + // The pause is only set once (as example if the user executes /uh freeze all twice). + if (pause != paused) { + if (pause) { + elapsedWhenPaused = getElapsed(); + + paused = true; + pauseTime = System.currentTimeMillis(); + } else { + // We have to add to the time of the start of the episode the elapsed time + // during the pause. + startTime += (System.currentTimeMillis() - pauseTime); + pauseTime = 0L; + + paused = false; + elapsedWhenPaused = 0; + } + } + } + } + + /** + * Checks if the timer is registered in the TimersModule. + * + * @return true if the timer is registered. + */ + public Boolean isRegistered() { + return registered; + } + + /** + * Marks a timer as registered, or not. + * + * @param registered true if the timer is now registered. + */ + protected void setRegistered(Boolean registered) { + this.registered = registered; + } + + /** + * Returns the name of the timer. + * + * @return The name. + */ + public String getName() { + return name; + } + + /** + * Returns the display name of the timer. + * <p> + * The display name is the name with all &-based color codes replaced by §-based ones. + * + * @return The name. + */ + public String getDisplayName() { + return ChatColor.translateAlternateColorCodes('&', name); + } + + /** + * Checks if the timer is currently running. + * + * @return true if the timer is running. + */ + public Boolean isRunning() { + return running; + } + + /** + * Checks if the timer is currently displayed in the sidebar. + * + * @return {@code true} if displayed. + */ + public Boolean isDisplayed() { + return displayed; + } + + /** + * Display or hide this timer in/from the sidebar. + * + * @param displayed {@code true} to display, and {@code false} to hide. + */ + public void setDisplayed(Boolean displayed) { + this.displayed = displayed; + } + + /** + * Checks if the name of this timer should be displayed in the sidebar. + * + * @return {@code true} if name displayed. + */ + public Boolean isNameDisplayed() { + return nameDisplayed; + } + + /** + * Displays or hides the timer's name in/from the sidebar. + * + * @param nameDisplayed {@code true} to display, and {@code false} to hide. + */ + public void setNameDisplayed(Boolean nameDisplayed) { + this.nameDisplayed = nameDisplayed; + } + + /** + * @return {@code true} if this is a system timer that cannot be altered by the user. + */ + public Boolean isSystem() { + return system; + } + + /** + * Sets if this timer is a system timer that cannot be altered by the user. + * + * @param system {@code true} if this timer is an internal system timer. + */ + public void setSystem(Boolean system) { + this.system = system; + } + + /** + * Returns the duration of the timer, in seconds. + * + * @return The duration. + */ + public Integer getDuration() { + return duration; + } + + /** + * Sets the duration of the timer, in seconds. + * + * @param seconds The duration. + */ + public void setDuration(int seconds) { + this.duration = seconds; + } + + /** + * Sets the duration of the timer. + * + * @param duration The duration. + */ + public void setDuration(TimeDelta duration) { + this.duration = Math.toIntExact(duration.getSeconds()); + } + + /** + * @return The elapsed time since the beginning of the timer (not including pauses), in seconds. + */ + public int getElapsed() { + if (isRunning()) { + if (isPaused()) { + return elapsedWhenPaused; + } else { + return (int) Math.floor((System.currentTimeMillis() - startTime) / 1000); + } + } else { + return 0; + } + } + + /** + * @return The number of seconds left before this timer is up. + */ + public int getTimeLeft() { + return getDuration() - getElapsed(); + } + + /** + * Checks if this timer is paused. + * + * @return true if the timer is paused. + */ + public Boolean isPaused() { + return paused; + } + + @Override + public String toString() { + return formatTime(getTimeLeft()); + } + + @Override + public boolean equals(Object other) { + return other instanceof Timer && ((Timer) other).getName().equals(this.getName()); + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/TimersModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/TimersModule.java new file mode 100644 index 0000000..05a4b41 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/TimersModule.java @@ -0,0 +1,219 @@ +/* + * 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.quartzsurvivalgames.modules.core.timers; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.commands.TimersCommand; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.stream.Collectors; +import org.bukkit.Material; +import org.bukkit.entity.Player; + + +@ModuleInfo( + name = "Timers", + description = "The timekeeper of the whole Quartz Survival Games plugin & companions.", + category = ModuleCategory.CORE, + icon = Material.CLOCK, + internal = true, + can_be_unloaded = false +) +public class TimersModule extends QSGModule { + private final Set<Timer> timers = new CopyOnWriteArraySet<>(); + + /** + * Cached list of the running timers + */ + private Set<Timer> runningTimers = new CopyOnWriteArraySet<>(); + + /** + * List of the timers to resume if running timers are paused. + * + * @see #pauseAllRunning(boolean) + */ + private final Set<Timer> timersToResume = new CopyOnWriteArraySet<>(); + + /** + * Sidebar cache. + */ + private List<AbstractMap.SimpleImmutableEntry<String, String>> sidebarInjection = new LinkedList<>(); + + + @Override + protected void onEnable() { + RunTask.timer(() -> timers.forEach(Timer::update), 1L, 20L); + } + + + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(TimersCommand.class); + } + + + @Override + public void prepareInjectionIntoSidebar() { + sidebarInjection.clear(); + sidebarInjection = timers.stream() + .filter(Timer::isDisplayed) + .map(timer -> new AbstractMap.SimpleImmutableEntry<>( + timer.isNameDisplayed() ? timer.getDisplayName() : null, timer.toString())) + .collect(Collectors.toList()); + } + + @Override + public void injectIntoSidebar(Player player, SidebarInjector injector) { + sidebarInjection.forEach(timer -> { + final List<String> lines; + + if (timer.getKey() == null) { + lines = Collections.singletonList(timer.getValue()); + } else { + lines = Arrays.asList(timer.getKey(), timer.getValue()); + } + + injector.injectLines(SidebarInjector.SidebarPriority.VERY_BOTTOM, true, lines); + }); + } + + /** + * Registers a timer. + * + * @param timer The timer to register. + * @throws IllegalArgumentException if a timer with the same name is already registered. + */ + public void registerTimer(final Timer timer) { + if (timers.contains(timer)) { + throw new IllegalArgumentException("The timer " + timer.getName() + " is already registered."); + } + + timers.add(timer); + + timer.setRegistered(true); + } + + /** + * Unregisters a timer. + * <p> + * If the timer was not registered, nothing is done. + * + * @param timer The timer to unregister. + */ + public void unregisterTimer(final Timer timer) { + timers.remove(timer); + runningTimers.remove(timer); + + timer.setRegistered(false); + } + + /** + * Updates the internal list of started timers. + */ + public void updateStartedTimersList() { + runningTimers = timers.stream().filter(Timer::isRunning).collect(Collectors.toSet()); + } + + /** + * Returns a timer by his name. + * + * @param name The name of the timer. + * @return The first timer with this name, or null if there isn't any timer with this name. + */ + public Timer getTimer(final String name) { + return timers.stream().filter(timer -> timer.getName().equals(name)).findFirst().orElse(null); + } + + /** + * Returns a collection containing the registered timers. + * + * @return The collection. + */ + public Collection<Timer> getTimers() { + return Collections.unmodifiableSet(timers); + } + + /** + * Returns a collection containing the running timers. + * + * @return The collection. + */ + public Collection<Timer> getRunningTimers() { + return Collections.unmodifiableSet(runningTimers); + } + + /** + * Pauses (or resumes) all the running timers. + * + * @param paused If true, all the timers will be paused. Else, resumed. + */ + public void pauseAll(boolean paused) { + getRunningTimers().forEach(timer -> timer.setPaused(paused)); + + if (!paused) { + // If we restart all the timers regardless to their previous state, + // this data is meaningless. + timersToResume.clear(); + } + } + + /** + * Pauses (or resumes) all the running timers. + * <p> + * This method will only resume the previously-running timers. + * + * @param paused If true, all the timers will be paused. Else, resumed. + */ + public void pauseAllRunning(boolean paused) { + if (paused) { + getRunningTimers().stream().filter(timer -> !timer.isPaused()).forEach(timer -> { + timer.setPaused(true); + timersToResume.add(timer); + }); + } else { + timersToResume.forEach(timer -> timer.setPaused(false)); + timersToResume.clear(); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/commands/TimersCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/commands/TimersCommand.java new file mode 100644 index 0000000..5949714 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/commands/TimersCommand.java @@ -0,0 +1,403 @@ +/* + * 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.quartzsurvivalgames.modules.core.timers.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.Timer; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimersModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.commands.WithFlags; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.components.rawtext.RawText; +import fr.zcraft.quartzlib.components.rawtext.RawTextPart; +import fr.zcraft.quartzlib.tools.text.MessageSender; +import java.util.Collection; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + + +@CommandInfo(name = "timers", usageParameters = "[add|display|hide|list|pause|resume|remove|set|start|stop|help]", aliases = { + "timer"}) +@WithFlags +public class TimersCommand extends Command { + private final TimersModule timersModule = QSG.module(TimersModule.class); + + @Override + protected void run() throws CommandException { + if (args.length == 0) { + list(); + return; + } + + switch (args[0].toLowerCase()) { + case "add": + add(); + break; + + case "display": + display(); + break; + + case "hide": + hide(); + break; + + case "list": + list(); + break; + + case "pause": + pause(); + break; + + case "resume": + resume(); + break; + + case "remove": + remove(); + break; + + case "set": + set(); + break; + + case "start": + start(); + break; + + case "stop": + stop(); + break; + + case "help": + default: + help(); + } + } + + private void help() { + info(I.t("{blue}{bold}Command help for {cc}{bold}/uh timers")); + info(I.t("{cc}/uh timers add <duration> <title ...> {ci}: adds a timer.")); + info(I.t( + "{cc}/uh timers display <title ...> [--without-name] {ci}: displays a timer in the scoreboard. Automatic when a timer is started.")); + info(I.t("{cc}/uh timers hide <title ...> {ci}: removes a timer from the scoreboard. Don't stops the timer.")); + info(I.t("{cc}/uh timers list {ci}: lists the registered timers.")); + info(I.t("{cc}/uh timers pause <title ...> {ci}: pauses a timer.")); + info(I.t("{cc}/uh timers resume <title ...> {ci}: resumes a timer.")); + info(I.t("{cc}/uh timers remove <title ...> {ci}: deletes a timer.")); + info(I.t("{cc}/uh timers set <duration> <title ...> {ci}: sets the duration of a timer.")); + info(I.t("{cc}/uh timers start <title ...> {ci}: starts a timer.")); + info(I.t( + "{cc}/uh timers stop <title ...> {ci}: stops a timer. The timer will be removed from the scoreboard.")); + } + + private void add() throws CommandException { + if (args.length < 3) { + throwInvalidArgument(I.t("You must specify both a duration and a name.")); + } + + final String name = QSGUtils.getStringFromCommandArguments(args, 2); + + if (timersModule.getTimer(name) != null) { + throwInvalidArgument(I.t("{ce}A timer called {0}{ce} already exists; please choose another name.", name)); + } + + final Timer timer = new Timer(name, getTimeDeltaParameter(1)); + timersModule.registerTimer(timer); + + success(I.t("{cs}The timer {0}{cs} (duration {1}) has been registered.", timer.getDisplayName(), args[1])); + } + + private void display() throws CommandException { + final Timer timer = getTimerParameter(1); + + timer.setDisplayed(true); + timer.setNameDisplayed(!hasFlag("without-name")); + + reply(I.t("{cs}The timer {0}{cs} is now displayed.", timer.getDisplayName())); + } + + private void hide() throws CommandException { + final Timer timer = getTimerParameter(1); + + timer.setDisplayed(false); + + reply(I.t("{cs}The timer {0}{cs} is now hidden.", timer.getDisplayName())); + } + + private void list() { + final Collection<Timer> timers = timersModule.getTimers(); + + info(""); + info(I.tn("{ci}{0} timer is registered.", "{ci}{0} timers are registered.", timers.size())); + + for (final Timer timer : timers) { + final RawTextPart timerText = new RawText() + .then(" • ") + .color(timer.isRunning() ? (timer.isPaused() ? ChatColor.YELLOW : ChatColor.GREEN) : ChatColor.RED) + .then(timer.getDisplayName()) + .hover( + new RawText() + .then(timer.getDisplayName()) + .then("\n") + .then(timer.isRunning() ? (timer.isPaused() ? I.t("Paused") : I.t("Running")) : + I.t("Not started")) + .then("\n\n") + .then(timer.toString() + (timer.isRunning() ? " " + + I.t("{gray}(total: {0}{gray})", Timer.formatTime(timer.getDuration())) : + "")) + .then(timer.isSystem() ? "\n\n" + I.t("{gray}{bold}System timer") : "") + .then(timer.isSystem() ? "\n" + + I.t("{gray}This timer is a system timer, it cannot be modified (you can still display or hide it to/from the sidebar).") : + "") + ) + .then(" ") + .then("[ \u272F ]") + .color(timer.isDisplayed() ? ChatColor.DARK_PURPLE : ChatColor.LIGHT_PURPLE) + .hover( + new RawText() + .then(timer.getDisplayName()) + .then("\n") + .then(timer.isDisplayed() ? I.t("{white}Hide this timer from the sidebar") : + I.t("{white}Show this timer in the sidebar")) + ) + .command(TimersCommand.class, timer.isDisplayed() ? "hide" : "display", timer.getName(), + "--from-list-command") + .then(" "); + + if (!timer.isSystem()) { + if (!timer.isRunning()) { + timerText + .then("[ \u25B6 ]") + .style(ChatColor.GREEN) + .hover( + new RawText() + .then(timer.getDisplayName()) + .then("\n").then(I.t("{white}Start this timer")) + ) + .command(TimersCommand.class, "start", timer.getName(), "--from-list-command"); + } else { + timerText + .then("[ \u2B1B ]") + .style(ChatColor.RED) + .hover( + new RawText() + .then(timer.getDisplayName()) + .then("\n").then(I.t("{white}Stop this timer")) + ) + .command(TimersCommand.class, "stop", timer.getName(), "--from-list-command"); + } + + timerText.then(" "); + + if (timer.isRunning()) { + timerText + .then("[ \u2759 \u2759 ]") + .style(timer.isPaused() ? ChatColor.GOLD : ChatColor.YELLOW) + .hover( + new RawText() + .then(timer.getDisplayName()) + .then("\n").then(timer.isPaused() ? I.t("{white}Resume this timer") : + I.t("{white}Pause this timer")) + ) + .command(TimersCommand.class, timer.isPaused() ? "resume" : "pause", timer.getName(), + "--from-list-command") + .then(" "); + } + + timerText + .then("[ × ]") + .style(ChatColor.DARK_RED) + .hover( + new RawText() + .then(timer.getDisplayName()) + .then("\n").then(I.t("{white}Delete this timer")) + ) + .command(TimersCommand.class, "remove", timer.getName(), "--from-list-command"); + } + + send(timerText.build()); + } + + if (sender instanceof Player) { + send( + /// Button in /uh timers + new RawText(I.t("[ Create a new timer ]")) + .color(ChatColor.GREEN) + .hover(I.t("{white}Click here to create a timer\n{gray}/uh timers add mm:ss <name>")) + .suggest(TimersCommand.class, "add", "") + + /// Button in /uh timers + .then(" ").then(I.t("[ Display Help ]")) + .color(ChatColor.YELLOW) + .hover(I.t("{white}Get some help about the commands\n{gray}/uh timers help")) + .command(TimersCommand.class, "help") + .build() + ); + } + } + + private void pause() throws CommandException { + final Timer timer = getTimerParameter(1); + + if (timer.isSystem()) { + throwNotAuthorized(); + } + + timer.setPaused(true); + + reply(I.t("{cs}The timer {0}{cs} is now paused.", timer.getDisplayName())); + } + + private void resume() throws CommandException { + final Timer timer = getTimerParameter(1); + + if (timer.isSystem()) { + throwNotAuthorized(); + } + + timer.setPaused(false); + + reply(I.t("{cs}The timer {0}{cs} was resumed.", timer.getDisplayName())); + } + + private void remove() throws CommandException { + final Timer timer = getTimerParameter(1); + + if (timer.isSystem()) { + throwNotAuthorized(); + } + + timer.stop(); + timersModule.unregisterTimer(timer); + + reply(I.t("{cs}The timer {0}{cs} has been deleted.", timer.getDisplayName())); + } + + private void set() throws CommandException { + if (args.length < 3) { + throwInvalidArgument(I.t("You must specify both a duration and a name.")); + } + + final Timer timer = getTimerParameter(2); + if (timer.isSystem()) { + throwNotAuthorized(); + } + + timer.setDuration(getTimeDeltaParameter(1)); + + success(I.t("{cs}The duration of the timer {0}{cs} is now {1}.", timer.getDisplayName(), args[1])); + } + + private void start() throws CommandException { + final Timer timer = getTimerParameter(1); + + if (timer.isSystem()) { + throwNotAuthorized(); + } + + if (!hasFlag("--hidden")) { + timer.setDisplayed(true); + timer.setNameDisplayed(!hasFlag("without-name")); + } + + if (timer.isRunning()) { + timer.stop(); + } + timer.start(); + + reply(I.t("{cs}The timer {0}{cs} was started.", timer.getDisplayName())); + } + + private void stop() throws CommandException { + final Timer timer = getTimerParameter(1); + + if (timer.isSystem()) { + throwNotAuthorized(); + } + + timer.stop(); + + reply(I.t("{cs}The timer {0}{cs} was stopped.", timer.getDisplayName())); + } + + + private void reply(final String reply) throws CommandException { + if (hasFlag("from-list-command") && sender instanceof Player) { + MessageSender.sendActionBarMessage(playerSender(), reply); + list(); + } else { + success(reply); + } + } + + + private Timer getTimerParameter(int index) throws CommandException { + try { + final String timerName = QSGUtils.getStringFromCommandArguments(args, index); + final Timer timer = timersModule.getTimer(timerName); + + if (timer == null) { + throwInvalidArgument(I.t("{ce}This timer is not registered.", timerName)); + } + + return timer; + } + catch (IllegalArgumentException e) { + throwInvalidArgument(I.t("A timer name is required as argument #{0}", index + 1)); + return null; + } + } + + private TimeDelta getTimeDeltaParameter(final int index) throws CommandException { + try { + return new TimeDelta(args[index]); + } + catch (final ArrayIndexOutOfBoundsException e) { + throwInvalidArgument( + I.t("A duration is required as argument #{0}. Format: “mm”, “mm:ss” or “hh:mm:ss”.", index + 1)); + return new TimeDelta(0); // Dummy value never reached to avoid “can be null” lint warnings + } + catch (final IllegalArgumentException e) { + throwInvalidArgument( + I.t("The duration provided as argument #{0} is invalid. Format: “mm”, “mm:ss” or “hh:mm:ss”.", + index + 1)); + return new TimeDelta(0); // Dummy value never reached to avoid “can be null” lint warnings + } + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/events/TimerEndsEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/events/TimerEndsEvent.java similarity index 83% rename from src/main/java/eu/carrade/amaury/UHCReloaded/events/TimerEndsEvent.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/events/TimerEndsEvent.java index c170d2c..8bfe3d6 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/events/TimerEndsEvent.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/events/TimerEndsEvent.java @@ -30,9 +30,9 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.events; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.events; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.Timer; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; @@ -42,27 +42,28 @@ * <p> * It is fired before all the values of the timer are reset. */ -public final class TimerEndsEvent extends Event -{ - private UHTimer timer; +public final class TimerEndsEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + private final Timer timer; private Boolean timerWasUp = false; private Boolean restart = false; - - public TimerEndsEvent(UHTimer timer, Boolean timerUp) - { + public TimerEndsEvent(Timer timer, Boolean timerUp) { this.timer = timer; this.timerWasUp = timerUp; } + public static HandlerList getHandlerList() { + return handlers; + } + /** * Returns the timer. * * @return the timer. */ - public UHTimer getTimer() - { + public Timer getTimer() { return timer; } @@ -71,43 +72,30 @@ public UHTimer getTimer() * * @return true if the timer was stopped because it was up. */ - public boolean wasTimerUp() - { + public boolean wasTimerUp() { return timerWasUp; } /** - * If true, the timer will be restarted. + * Return true if the timer will be restarted. * - * @param restart true if the timer needs to be restarted. + * @return {@code true} if the timer needs to be restarted. */ - public void setRestart(boolean restart) - { - this.restart = restart; + public boolean getRestart() { + return this.restart; } /** - * Return true if the timer will be restarted. + * If true, the timer will be restarted. * - * @return {@code true} if the timer needs to be restarted. + * @param restart true if the timer needs to be restarted. */ - public boolean getRestart() - { - return this.restart; + public void setRestart(boolean restart) { + this.restart = restart; } - - - private static final HandlerList handlers = new HandlerList(); - @Override - public HandlerList getHandlers() - { - return handlers; - } - - public static HandlerList getHandlerList() - { + public HandlerList getHandlers() { return handlers; } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/events/TimerStartsEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/events/TimerStartsEvent.java similarity index 83% rename from src/main/java/eu/carrade/amaury/UHCReloaded/events/TimerStartsEvent.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/events/TimerStartsEvent.java index 2476221..9be07ff 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/events/TimerStartsEvent.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/core/timers/events/TimerStartsEvent.java @@ -30,9 +30,9 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.events; +package eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.events; -import eu.carrade.amaury.UHCReloaded.timers.UHTimer; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.Timer; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; @@ -42,36 +42,29 @@ * * @author Amaury Carrade */ -public final class TimerStartsEvent extends Event -{ - private UHTimer timer; +public final class TimerStartsEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + private final Timer timer; - public TimerStartsEvent(UHTimer timer) - { + public TimerStartsEvent(Timer timer) { this.timer = timer; } + public static HandlerList getHandlerList() { + return handlers; + } + /** * Returns the timer. * * @return */ - public UHTimer getTimer() - { + public Timer getTimer() { return timer; } - - private static final HandlerList handlers = new HandlerList(); - @Override - public HandlerList getHandlers() - { - return handlers; - } - - public static HandlerList getHandlerList() - { + public HandlerList getHandlers() { return handlers; } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/GameDurationModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/GameDurationModule.java new file mode 100644 index 0000000..9b54042 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/GameDurationModule.java @@ -0,0 +1,69 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import org.bukkit.Material; +import org.bukkit.entity.Player; + + +@ModuleInfo( + name = "Game Duration", + description = "Displays the game duration in the sidebar.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.COSMETICS, + icon = Material.CLOCK +) +public class GameDurationModule extends QSGModule { + private long beginning = 0; + + @Override + protected void onEnable() { + this.beginning = System.currentTimeMillis(); + } + + @Override + public void injectIntoSidebar(final Player player, final SidebarInjector injector) { + injector.injectLines( + SidebarInjector.SidebarPriority.BOTTOM, true, + new TimeDelta((System.currentTimeMillis() - beginning) / 1000).toString() + ); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/KillsCountModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/KillsCountModule.java new file mode 100644 index 0000000..2a104ff --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/KillsCountModule.java @@ -0,0 +1,89 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.PlayerResurrectedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + + +@ModuleInfo( + name = "Kills Count", + description = "Displays the player's kills count in the sidebar.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.COSMETICS, + icon = Material.DIAMOND_SWORD +) +public class KillsCountModule extends QSGModule { + private final Map<UUID, Set<UUID>> kills = new HashMap<>(); + + @Override + public void injectIntoSidebar(final Player player, final SidebarInjector injector) { + injector.injectLines( + SidebarInjector.SidebarPriority.BOTTOM, true, + I.tn("{white}{0}{gray} player killed", "{white}{0}{gray} players killed", + getKillsFor(player.getUniqueId()).size()) + ); + } + + private Set<UUID> getKillsFor(final UUID playerID) { + return kills.computeIfAbsent(playerID, uuid -> new HashSet<>()); + } + + @EventHandler + public void onPlayerDeath(final AlivePlayerDeathEvent ev) { + if (ev.getPlayer().isOnline() && ev.getPlayer().getPlayer().getKiller() != null) { + getKillsFor(ev.getPlayer().getPlayer().getKiller().getUniqueId()).add(ev.getPlayer().getUniqueId()); + } + } + + @EventHandler + public void onPlayerResurrect(final PlayerResurrectedEvent ev) { + kills.values().forEach(playerKills -> playerKills.remove(ev.getPlayer().getUniqueId())); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/ListHealthModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/ListHealthModule.java new file mode 100644 index 0000000..d9fbd1a --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/ListHealthModule.java @@ -0,0 +1,105 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.scoreboard.Criterias; +import org.bukkit.scoreboard.DisplaySlot; +import org.bukkit.scoreboard.Objective; + + +@ModuleInfo( + name = "Health in Players List", + description = "Displays the health of players in the overlay list displayed with <TAB>.", + when = ModuleLoadTime.ON_GAME_STARTING, + category = ModuleCategory.COSMETICS, + icon = Material.DETECTOR_RAIL +) +public class ListHealthModule extends QSGModule { + private final String objectiveID = UUID.randomUUID().toString().substring(0, 16); + + @Override + protected void onEnable() { + // Initialization of the scoreboard (health in players' list) + final Objective healthObjective = QSG.get().getScoreboard().registerNewObjective(objectiveID, Criterias.HEALTH); + healthObjective.setDisplayName("Health"); + healthObjective.setDisplaySlot(DisplaySlot.PLAYER_LIST); + + // Sometimes, the health is initialized to 0. This is used to fix this. + updateHealthScore(); + } + + @Override + protected void onDisable() { + QSG.get().getScoreboard().clearSlot(DisplaySlot.PLAYER_LIST); + QSG.get().getScoreboard().getObjective(objectiveID).unregister(); + } + + /** + * Updates the health score for all players. + */ + public void updateHealthScore() { + Bukkit.getOnlinePlayers().forEach(this::updateHealthScore); + } + + /** + * Updates the health score for the given player. + * + * @param player The player to update. + */ + public void updateHealthScore(final Player player) { + if (player.getHealth() != 1d) // Prevents killing the player + { + player.setHealth(player.getHealth() - 1d); + + RunTask.later(() -> + { + if (player.getHealth() <= player.getMaxHealth() - 1d) // Avoids an IllegalArgumentException + { + player.setHealth(player.getHealth() + 1d); + } + }, 3L); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/episodes/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/episodes/Config.java new file mode 100644 index 0000000..43bdd8f --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/episodes/Config.java @@ -0,0 +1,52 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.episodes; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + + +public class Config extends ConfigurationInstance { + static public final ConfigurationItem<TimeDelta> LENGTH = item("length", new TimeDelta(0, 20, 0)); + static public final ConfigurationItem<Boolean> DISPLAY_TITLE = item("display-title", true); + static public final ConfigurationItem<Boolean> DISPLAY_IN_SIDEBAR = item("display-in-sidebar", true); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/episodes/EpisodesModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/episodes/EpisodesModule.java new file mode 100644 index 0000000..eb2ed28 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/episodes/EpisodesModule.java @@ -0,0 +1,196 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.episodes; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector.SidebarPriority; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.Timer; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimersModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.events.TimerEndsEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.episodes.commands.ShiftCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.episodes.events.EpisodeChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.episodes.events.EpisodeChangedEvent.EpisodeChangedCause; +import eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.playerListHeaderFooter.PlayerListHeaderFooterModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.text.Titles; +import java.util.Collections; +import java.util.List; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + + +@ModuleInfo( + name = "Episodes", + description = "Displays time marks every 20 minutes (by default), e.g. to divide a recording for diffusion.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.COSMETICS, + icon = Material.BELL, + settings = Config.class, + can_be_loaded_late = false +) +public class EpisodesModule extends QSGModule { + private final GameModule game = QSG.game(); + private final TimersModule timers = QSG.module(TimersModule.class); + + private Timer episodesTimer; + private int episode = 1; + + @Override + protected void onEnable() { + episodesTimer = new Timer("Episodes"); + episodesTimer.setDuration(Config.LENGTH.get()); + episodesTimer.setSystem(true); + + timers.registerTimer(episodesTimer); + + episodesTimer.setDisplayed(true); + episodesTimer.setNameDisplayed(false); + + episodesTimer.start(); + + QSG.ifLoaded(PlayerListHeaderFooterModule.class, headFoot -> { + headFoot.registerPlaceholder("episodeText", () -> I.t("Episode {0}", episode)); + headFoot.registerPlaceholder("episodeNumber", () -> String.valueOf(episode)); + }); + } + + @Override + protected void onDisable() { + episodesTimer.setDisplayed(false); + timers.unregisterTimer(episodesTimer); + } + + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(ShiftCommand.class); + } + + @Override + public void injectIntoSidebar(Player player, SidebarInjector injector) { + if (!Config.DISPLAY_IN_SIDEBAR.get() || game.currentPhaseBefore(GamePhase.IN_GAME)) { + return; + } + + injector.injectLines(SidebarPriority.VERY_TOP, true, I.t("{gray}Episode {white}{0}", episode)); + } + + @EventHandler + public void onTimerEnds(final TimerEndsEvent ev) { + if (!ev.getTimer().equals(episodesTimer)) { + return; + } + + ev.setRestart(true); + shift(false, null, episode + 1); + } + + /** + * Used to broadcast the episode change. + */ + @EventHandler + public void onEpisodeChange(final EpisodeChangedEvent ev) { + final String message; + + if (ev.getCause() == EpisodeChangedEvent.EpisodeChangedCause.SHIFTED) { + final String shifterName = + ev.getShifter() instanceof ConsoleCommandSender ? I.t("the console") : ev.getShifter().getName(); + message = + I.t("{aqua}-------- End of episode {0} [forced by {1}] --------", ev.getOldEpisode(), shifterName); + } else { + message = I.t("{aqua}-------- End of episode {0} --------", String.valueOf(ev.getOldEpisode())); + } + + Bukkit.broadcastMessage(message); + + + // Broadcasts title + if (Config.DISPLAY_TITLE.get()) { + Titles.broadcastTitle( + 5, 32, 8, + "", + /// The title displayed when the episode change. {0} = new episode number; {1} = old. + I.t("{darkaqua}Episode {aqua}{0}", ev.getNewEpisode(), ev.getOldEpisode()) + ); + } + + + // Update headers & footers + QSG.ifLoaded(PlayerListHeaderFooterModule.class, PlayerListHeaderFooterModule::update); + } + + public int getEpisode() { + return episode; + } + + public void shift(final CommandSender shifter, final int newEpisode) { + shift(true, shifter != null ? shifter : Bukkit.getConsoleSender(), newEpisode); + } + + public void shift(final CommandSender shifter) { + shift(shifter, episode + 1); + } + + private void shift(final boolean forced, final CommandSender shifter, final int newEpisode) { + final int oldEpisode = episode; + episode = newEpisode; + + // If not forced, the timer is restarted in the event, else we have to restart + // it manually. + if (forced) { + episodesTimer.start(); + } + + Bukkit.getPluginManager().callEvent( + new EpisodeChangedEvent( + episode, + oldEpisode, + forced ? EpisodeChangedCause.SHIFTED : EpisodeChangedCause.FINISHED, + shifter + ) + ); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/episodes/commands/ShiftCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/episodes/commands/ShiftCommand.java new file mode 100644 index 0000000..04d2daa --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/episodes/commands/ShiftCommand.java @@ -0,0 +1,62 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.episodes.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.episodes.EpisodesModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; + + +@CommandInfo(name = "shift", usageParameters = "[next episode number]", aliases = {"shift-episode"}) +public class ShiftCommand extends Command { + @Override + protected void run() throws CommandException { + if (QSG.module(GameModule.class).currentPhaseBefore(GamePhase.IN_GAME)) { + error(I.t("{ce}You can't shift the current episode because the game is not started.")); + } + + try { + QSG.module(EpisodesModule.class).shift(sender, Integer.parseInt(args[0])); + } + catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { + QSG.module(EpisodesModule.class).shift(sender); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/events/UHEpisodeChangedEvent.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/episodes/events/EpisodeChangedEvent.java similarity index 65% rename from src/main/java/eu/carrade/amaury/UHCReloaded/events/UHEpisodeChangedEvent.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/episodes/events/EpisodeChangedEvent.java index 94a5473..c551035 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/events/UHEpisodeChangedEvent.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/episodes/events/EpisodeChangedEvent.java @@ -30,8 +30,9 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.events; +package eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.episodes.events; +import org.bukkit.command.CommandSender; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; @@ -39,64 +40,79 @@ /** * Called when an episode changes. */ -public class UHEpisodeChangedEvent extends Event -{ - private int newEpisode; - private EpisodeChangedCause cause; - private String shifter; +public class EpisodeChangedEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + private final int newEpisode; + private final int oldEpisode; + private final EpisodeChangedCause cause; + private final CommandSender shifter; - public UHEpisodeChangedEvent(int newEpisode, EpisodeChangedCause cause, String shifter) - { + public EpisodeChangedEvent(int newEpisode, int oldEpisode, EpisodeChangedCause cause, CommandSender shifter) { this.newEpisode = newEpisode; + this.oldEpisode = oldEpisode; + this.cause = cause; this.shifter = shifter; } + public static HandlerList getHandlerList() { + return handlers; + } + /** * Returns the new episode. * * @return The new episode. */ - public int getNewEpisode() - { + public int getNewEpisode() { return newEpisode; } + /** + * Returns the old episode. + * + * @return The old episode. + */ + public int getOldEpisode() { + return oldEpisode; + } + /** * Why the episode changed? * * @return The cause. - * * @see EpisodeChangedCause */ - public EpisodeChangedCause getCause() - { + public EpisodeChangedCause getCause() { return cause; } /** - * Returns the name of the shifter (the one that executed the /uh shift command, or "" if + * Returns the shifter (the one that executed the /uh shift command, or {@code null} if * the episode was shifted because the previous one was finished). * * @return The shifter. */ - public String getShifter() - { + public CommandSender getShifter() { return shifter; } - - - private static final HandlerList handlers = new HandlerList(); - @Override - public HandlerList getHandlers() - { + public HandlerList getHandlers() { return handlers; } - public static HandlerList getHandlerList() - { - return handlers; + + public enum EpisodeChangedCause { + /** + * The episode changed because the previous episode was finished. + */ + FINISHED, + + /** + * The episode changed because the previous episode was shifted by someone using + * the {@code /uh shift} command. + */ + SHIFTED } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/hardcoreHearts/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/hardcoreHearts/Config.java new file mode 100644 index 0000000..0c193fe --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/hardcoreHearts/Config.java @@ -0,0 +1,57 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.hardcoreHearts; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.section; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.configuration.ConfigurationSection; +import java.io.File; + +public class Config extends ConfigurationInstance { + static public final ConfigurationItem<Boolean> HARDCORE_HEARTS = item("hardcore-hearts", true); + static public final AutoRespawnSection AUTO_RESPAWN = section("auto-respawn", AutoRespawnSection.class); + + public Config(File file) { + super(file); + } + + static public class AutoRespawnSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> DO = item("do", true); + public final ConfigurationItem<Integer> DELAY = item("delay", 6); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/hardcoreHearts/HardcoreHeartsModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/hardcoreHearts/HardcoreHeartsModule.java new file mode 100644 index 0000000..af3b04f --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/hardcoreHearts/HardcoreHeartsModule.java @@ -0,0 +1,68 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.hardcoreHearts; + +import com.comphenix.protocol.ProtocolLibrary; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import fr.zcraft.quartzlib.core.QuartzLib; +import org.bukkit.Material; + + +@ModuleInfo( + name = "Hardcore Hearts", + description = "Replaces hearts with hardcore hearts.", + depends = "ProtocolLib", + category = ModuleCategory.COSMETICS, + icon = Material.WITHER_ROSE, + settings = Config.class +) +public class HardcoreHeartsModule extends QSGModule { + @Override + protected void onEnable() { + final PacketsListener packetsListener = new PacketsListener(); + + if (Config.HARDCORE_HEARTS.get()) { + ProtocolLibrary.getProtocolManager().addPacketListener(packetsListener); + } + + if (Config.AUTO_RESPAWN.DO.get()) { + QuartzLib.registerEvents(packetsListener); + } + + log().info("Successfully hooked into ProtocolLib."); + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/PacketsListener.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/hardcoreHearts/PacketsListener.java similarity index 78% rename from src/main/java/eu/carrade/amaury/UHCReloaded/listeners/PacketsListener.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/hardcoreHearts/PacketsListener.java index c6187cd..99fe407 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/PacketsListener.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/hardcoreHearts/PacketsListener.java @@ -30,7 +30,7 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.listeners; +package eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.hardcoreHearts; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; @@ -40,29 +40,21 @@ import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.wrappers.EnumWrappers; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import fr.zcraft.zlib.tools.runners.RunTask; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import java.lang.reflect.InvocationTargetException; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.PlayerDeathEvent; -import java.lang.reflect.InvocationTargetException; - - -public class PacketsListener extends PacketAdapter implements Listener -{ - private UHCReloaded p; - private ProtocolManager pm = ProtocolLibrary.getProtocolManager(); +public class PacketsListener extends PacketAdapter implements Listener { + private final ProtocolManager pm = ProtocolLibrary.getProtocolManager(); private final PacketContainer respawnPacket; - public PacketsListener(UHCReloaded p) - { + public PacketsListener() { // This listener needs to listen on login packets only. - super(UHCReloaded.get(), ListenerPriority.NORMAL, PacketType.Play.Server.LOGIN); - - this.p = UHCReloaded.get(); + super(QSG.get(), ListenerPriority.NORMAL, PacketType.Play.Server.LOGIN); // The packet to send to automatically respawn the player. respawnPacket = pm.createPacket(PacketType.Play.Client.CLIENT_COMMAND); @@ -73,11 +65,9 @@ public PacketsListener(UHCReloaded p) * Used to present the server as an hardcore server, for the clients to display hardcore hearts. */ @Override - public void onPacketSending(PacketEvent ev) - { + public void onPacketSending(final PacketEvent ev) { // If its a login packet, write the hardcore flag (first boolean) to true. - if (ev.getPacketType().equals(PacketType.Play.Server.LOGIN)) - { + if (ev.getPacketType().equals(PacketType.Play.Server.LOGIN)) { ev.getPacket().getBooleans().write(0, true); } } @@ -86,21 +76,18 @@ public void onPacketSending(PacketEvent ev) * Used to automatically respawn the dead players. */ @EventHandler - public void onPlayerDeath(final PlayerDeathEvent ev) - { - if (UHConfig.AUTO_RESPAWN.DO.get()) - { + public void onPlayerDeath(final PlayerDeathEvent ev) { + if (Config.AUTO_RESPAWN.DO.get()) { RunTask.later(() -> { - try - { + try { pm.recieveClientPacket(ev.getEntity(), respawnPacket); } - catch (IllegalAccessException | InvocationTargetException e) - { - e.printStackTrace(); + catch (final IllegalAccessException | InvocationTargetException e) { + QSG.log(HardcoreHeartsModule.class) + .error("Unable to respawn player {0}", e, ev.getEntity().getName()); } - }, UHConfig.AUTO_RESPAWN.DELAY.get() * 20L); + }, Config.AUTO_RESPAWN.DELAY.get() * 20L); } } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/playerListHeaderFooter/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/playerListHeaderFooter/Config.java new file mode 100644 index 0000000..7ec30db --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/playerListHeaderFooter/Config.java @@ -0,0 +1,51 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.playerListHeaderFooter; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.configuration.ConfigurationMap; +import java.io.File; + +public class Config extends ConfigurationInstance { + public static final ConfigurationMap<GamePhase, String> HEADERS = + ConfigurationItem.map("headers", GamePhase.class, String.class); + public static final ConfigurationMap<GamePhase, String> FOOTERS = + ConfigurationItem.map("footers", GamePhase.class, String.class); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/playerListHeaderFooter/ListPlaceholdersCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/playerListHeaderFooter/ListPlaceholdersCommand.java new file mode 100644 index 0000000..84ea0ac --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/playerListHeaderFooter/ListPlaceholdersCommand.java @@ -0,0 +1,82 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.playerListHeaderFooter; + +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.commands.WithFlags; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.commands.PaginatedTextView; +import java.util.Map; +import java.util.function.Supplier; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; + +@CommandInfo(name = "list-hf-placeholders") +@WithFlags("page") +public class ListPlaceholdersCommand extends Command { + @Override + protected void run() throws CommandException { + final Map<String, Supplier<String>> placeholders = + QSG.module(PlayerListHeaderFooterModule.class).getPlaceholderSuppliers(); + final int page = args.length > 0 ? getIntegerParameter(0) : 1; + + new PlaceholdersList() + .setData(placeholders.entrySet().toArray(new Map.Entry[placeholders.entrySet().size()])) + .setCurrentPage(page) + .display(sender); + } + + private final class PlaceholdersList extends PaginatedTextView<Map.Entry<String, Supplier<String>>> { + @Override + protected void displayHeader(final CommandSender receiver) { + receiver.sendMessage(ChatColor.GREEN + "" + ChatColor.BOLD + + I.tn("{0} registered placeholder", "{0} registered placeholders", data().length)); + } + + @Override + protected void displayItem(final CommandSender receiver, final Map.Entry<String, Supplier<String>> item) { + receiver.sendMessage(String.format("%s{%s}%s\t« %s%s »", ChatColor.WHITE, item.getKey(), ChatColor.GRAY, + item.getValue().get(), ChatColor.GRAY)); + } + + @Override + protected String getCommandToPage(final int page) { + return build(String.valueOf(page)); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/playerListHeaderFooter/PlayerListHeaderFooterModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/playerListHeaderFooter/PlayerListHeaderFooterModule.java new file mode 100644 index 0000000..897510b --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/cosmetics/playerListHeaderFooter/PlayerListHeaderFooterModule.java @@ -0,0 +1,203 @@ +/* + * 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.quartzsurvivalgames.modules.cosmetics.playerListHeaderFooter; + +import eu.carrade.amaury.quartzsurvivalgames.QSGConfig; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.PlayerResurrectedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.SpectatorsModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import fr.zcraft.quartzteams.events.PlayerJoinedTeamEvent; +import fr.zcraft.quartzteams.events.PlayerLeftTeamEvent; +import fr.zcraft.quartzteams.events.TeamRegisteredEvent; +import fr.zcraft.quartzteams.events.TeamUnregisteredEvent; +import fr.zcraft.quartzteams.events.TeamUpdatedEvent; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; +import java.util.stream.Stream; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; + + +@ModuleInfo( + name = "Players List Header & Footer", + description = "Fills the players list header & footer with any text, that may contains infos related " + + "to the current game through placeholders. Other modules can add placeholders.", + when = ModuleLoadTime.POST_WORLD, + category = ModuleCategory.COSMETICS, + icon = Material.ACTIVATOR_RAIL, + settings = Config.class, + can_be_loaded_late = false +) +public class PlayerListHeaderFooterModule extends QSGModule { + private final Map<String, Supplier<String>> placeholderSuppliers = new HashMap<>(); + + @Override + protected void onEnable() { + registerPlaceholder("title", QSGConfig.TITLE::get); + registerPlaceholder("playersText", () -> I.tn("{0} player", "{0} players", QSG.game().countAlivePlayers())); + registerPlaceholder("playersCount", () -> String.valueOf(QSG.game().countAlivePlayers())); + registerPlaceholder("teamsText", () -> I.tn("{0} team", "{0} teams", QSG.game().countAliveTeams())); + registerPlaceholder("teamsCount", () -> String.valueOf(QSG.game().countAliveTeams())); + + RunTask.nextTick(this::update); + } + + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(ListPlaceholdersCommand.class); + } + + /** + * Registers a new placeholder for player list headers & footers. + * + * @param placeholderName The name of the placeholder. The module will lookup for {givenName} + * in the patterns. + * @param supplier The supplier returning the value to use for this placeholder. + */ + public void registerPlaceholder(final String placeholderName, final Supplier<String> supplier) { + placeholderSuppliers.put(placeholderName, supplier); + } + + public Map<String, Supplier<String>> getPlaceholderSuppliers() { + return Collections.unmodifiableMap(placeholderSuppliers); + } + + private String computeText(String pattern) { + return pattern.isEmpty() ? "" : ChatColor.translateAlternateColorCodes('&', replaceTags(pattern)); + } + + /** + * @param raw The raw text. + * @return The text, with tags replaced using the registered placeholders. + */ + private String replaceTags(String raw) { + for (Map.Entry<String, Supplier<String>> entry : placeholderSuppliers.entrySet()) { + raw = raw.replace("{" + entry.getKey() + "}", entry.getValue().get()); + } + + return raw; + } + + public void update() { + if (!isEnabled()) { + return; // Other modules may keep a reference if the module is disabled. + } + + final String headerPattern = Config.HEADERS.get(QSG.game().getPhase()); + final String footerPattern = Config.FOOTERS.get(QSG.game().getPhase()); + + if ((headerPattern != null && !headerPattern.isEmpty()) || + (footerPattern != null && !footerPattern.isEmpty())) { + final String header = headerPattern != null ? computeText(headerPattern) : ""; + final String footer = footerPattern != null ? computeText(footerPattern) : ""; + + final Stream<? extends Player> receivers; + + if (QSG.game().currentPhaseAfter(GamePhase.STARTING)) { + receivers = Stream.concat( + QSG.game().getAliveConnectedPlayers().stream(), + QSG.module(SpectatorsModule.class).getSpectators().stream().map(Bukkit::getPlayer) + .filter(Objects::nonNull) + ); + } else { + receivers = Bukkit.getOnlinePlayers().stream(); + } + + receivers.forEach(player -> player.setPlayerListHeaderFooter(header, footer)); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + protected void onGamePhaseChange(final GamePhaseChangedEvent ev) { + update(); + } + + @EventHandler(priority = EventPriority.MONITOR) + protected void onPlayerDeath(final AlivePlayerDeathEvent ev) { + update(); + } + + @EventHandler(priority = EventPriority.MONITOR) + protected void onPlayerResurrect(final PlayerResurrectedEvent ev) { + update(); + } + + @EventHandler(priority = EventPriority.MONITOR) + protected void onPlayerJoin(final PlayerJoinEvent ev) { + update(); + } + + @EventHandler(priority = EventPriority.MONITOR) + protected void onTeamsChange(final TeamUpdatedEvent ev) { + update(); + } + + @EventHandler(priority = EventPriority.MONITOR) + protected void onTeamsChange(final TeamRegisteredEvent ev) { + update(); + } + + @EventHandler(priority = EventPriority.MONITOR) + protected void onTeamsChange(final TeamUnregisteredEvent ev) { + update(); + } + + @EventHandler(priority = EventPriority.MONITOR) + protected void onTeamsChange(final PlayerJoinedTeamEvent ev) { + update(); + } + + @EventHandler(priority = EventPriority.MONITOR) + protected void onTeamsChange(final PlayerLeftTeamEvent ev) { + update(); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/EndAnnouncementModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/EndAnnouncementModule.java new file mode 100644 index 0000000..d7eea15 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/EndAnnouncementModule.java @@ -0,0 +1,123 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.end; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import fr.zcraft.quartzlib.tools.text.Titles; +import fr.zcraft.quartzteams.QuartzTeam; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; + +@ModuleInfo( + name = "End Announcement", + description = "Announces the winner's name to the whole server when the game ends.", + when = ModuleLoadTime.ON_GAME_END, + category = ModuleCategory.END, + icon = Material.ITEM_FRAME +) +public class EndAnnouncementModule extends QSGModule { + @Override + protected void onEnable() { + RunTask.later(() -> + { + if (QSG.game().getPhase() != GamePhase.END) { + return; + } + + final QuartzTeam winnerTeam = QSG.game().getWinner(); + + if (winnerTeam == null) { + return; // No winner + } + + Bukkit.broadcastMessage(""); + + if (QSG.game().isTeamsGame()) { + final StringBuilder winners = new StringBuilder(); + int j = 0; + + for (final OfflinePlayer winner : winnerTeam.getPlayers()) { + if (j != 0) { + if (j == winnerTeam.size() - 1) { + /// The "and" in the winners players list (like "player1, player2 and player3"). + winners.append(" ").append(I.tc("winners_list", "and")).append(" "); + } else { + winners.append(", "); + } + } + + winners.append(winner.getName()); + j++; + } + + Bukkit.broadcastMessage( + I.t("{darkgreen}{obfuscated}--{green} Congratulations to {0} (team {1}{green}) for their victory! {darkgreen}{obfuscated}--", + winners.toString(), winnerTeam.getDisplayName())); + } else { + Bukkit.broadcastMessage( + I.t("{darkgreen}{obfuscated}--{green} Congratulations to {0} for his victory! {darkgreen}{obfuscated}--", + winnerTeam.getName())); + } + + Bukkit.broadcastMessage(""); + + + final String title; + final String subtitle; + + if (QSG.game().isTeamsGame()) { + /// The main title of the /title displayed when a team wins the game. {0} becomes the team display name (with colors). + title = I.t("{darkgreen}{0}", winnerTeam.getDisplayName()); + /// The subtitle of the /title displayed when a team wins the game. {0} becomes the team display name (with colors). + subtitle = I.t("{green}This team wins the game!", winnerTeam.getDisplayName()); + } else { + /// The main title of the /title displayed when a player wins the game (in solo). {0} becomes the player display name (with colors). + title = I.t("{darkgreen}{0}", winnerTeam.getDisplayName()); + /// The subtitle of the /title displayed when a player wins the game (in solo). {0} becomes the player display name (with colors). + subtitle = I.t("{green}wins the game!", winnerTeam.getDisplayName()); + } + + Titles.broadcastTitle(5, 142, 21, title, subtitle); + }, 6 * 20L); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/FireworksModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/FireworksModule.java new file mode 100644 index 0000000..578aa64 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/FireworksModule.java @@ -0,0 +1,107 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.end; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import org.apache.commons.lang.math.RandomUtils; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.scheduler.BukkitRunnable; + + +@ModuleInfo( + name = "Fireworks", + description = "When the game ends, this module sends some fireworks from the winners o/", + when = ModuleLoadTime.ON_GAME_END, + category = ModuleCategory.END, + icon = Material.FIREWORK_ROCKET +) +public class FireworksModule extends QSGModule { + private final int area = 6; // Fireworks launched on a 6×6 area around the winners + private final TimeDelta duration = new TimeDelta(10); + + @Override + protected void onEnable() { + RunTask.later(() -> + { + if (QSG.game().getPhase() != GamePhase.END) { + return; + } + + final long start = System.currentTimeMillis(); + + RunTask.timer(new BukkitRunnable() { + @Override + public void run() { + if (QSG.game().getWinner() == null) { + return; + } + + QSG.game().getWinner().getOnlinePlayers().forEach(winner -> + { + final Location fireworkLocation = winner.getLocation(); + + fireworkLocation.add( + // a number between -area/2 and area/2 + RandomUtils.nextDouble() * area - (area >> 1), + + // y+2 for a clean vision of the winner. + 2, + + // a number between -area/2 and area/2 + RandomUtils.nextDouble() * area - (area >> 1) + ); + + QSGUtils.generateRandomFirework(fireworkLocation.add(4, 0, 4), 5, 15); + QSGUtils.generateRandomFirework(fireworkLocation.add(4, 0, 4), 5, 15); + }); + + if ((System.currentTimeMillis() - start) / 1000 > duration.getSeconds()) { + cancel(); + } + } + }, 0L, 30L); + + }, 5 * 20L); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/deathAnnouncement/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/deathAnnouncement/Config.java new file mode 100644 index 0000000..5313cda --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/deathAnnouncement/Config.java @@ -0,0 +1,55 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.end.deathAnnouncement; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGSound; +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + +public class Config extends ConfigurationInstance { + public static final ConfigurationItem<Boolean> NOTIFY_IF_TEAM_HAS_FALLEN = item("notify-if-team-has-fallen", true); + public static final ConfigurationItem<String> DEATH_MESSAGES_FORMAT = item("death-messages-format", "§6"); + public static final ConfigurationItem<String> TEAM_DEATH_MESSAGES_FORMAT = item("team-death-messages-format", "§6"); + public static final ConfigurationItem<Boolean> LIGHTNING_STRIKE = item("lightning-strike", false); + public static final ConfigurationItem<Boolean> PLAY_SOUND = item("play-sound", true); + public static final ConfigurationItem<QSGSound> SOUND = item("sound", new QSGSound("ENTITY_WITHER_SPAWN")); + + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/deathAnnouncement/DeathAnnouncementModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/deathAnnouncement/DeathAnnouncementModule.java new file mode 100644 index 0000000..a0aa8e8 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/deathAnnouncement/DeathAnnouncementModule.java @@ -0,0 +1,163 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.end.deathAnnouncement; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.TeamDeathEvent; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGSound; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.components.rawtext.RawText; +import fr.zcraft.quartzlib.components.rawtext.RawTextPart; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import fr.zcraft.quartzlib.tools.text.RawMessage; +import fr.zcraft.quartzteams.QuartzTeam; +import fr.zcraft.quartzteams.QuartzTeams; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.PlayerDeathEvent; + +@ModuleInfo( + name = "Death Announcements", + description = "Adds announcements for players & teams deaths.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.END, + icon = Material.BLAZE_ROD, + settings = Config.class +) +public class DeathAnnouncementModule extends QSGModule { + private QSGSound deathSound; + + @Override + protected void onEnable() { + deathSound = Config.SOUND.get(); + } + + @EventHandler + public void onPlayerDeath(final AlivePlayerDeathEvent ev) { + final PlayerDeathEvent pdev = ev.getPlayerDeathEvent(); + + // Highlights the death message in the console + Bukkit.getConsoleSender().sendMessage(ChatColor.GOLD + "-- Death of " + ev.getPlayer().getName() + + (pdev != null ? " (" + pdev.getDeathMessage() + ")" : "") + " --"); + + // If this is a real death + if (pdev != null) { + // We send a lightning strike. + + if (Config.LIGHTNING_STRIKE.get()) { + pdev.getEntity().getLocation().getWorld().strikeLightningEffect(pdev.getEntity().getLocation()); + } + } + + // If it is a death of an offline player + else { + Bukkit.broadcastMessage( + colorizePlayerInString(I.t("{0} died, following a game master's order.", ev.getPlayer().getName()), + ev.getPlayer())); + } + + + // Play sound + if (Config.PLAY_SOUND.get()) { + deathSound.broadcast(); + } + } + + @EventHandler + public void onTeamDeath(final TeamDeathEvent ev) { + if (Config.NOTIFY_IF_TEAM_HAS_FALLEN.get()) { + // Used to display this message after the death message. + RunTask.later(() -> + { + final QuartzTeam team = ev.getTeam(); + final String format = + ChatColor.translateAlternateColorCodes('&', Config.TEAM_DEATH_MESSAGES_FORMAT.get()); + + final RawTextPart<?> teamTooltip = new RawText() + .then(team.getName()).style(team.getColorOrWhite().toChatColor(), ChatColor.BOLD); + + for (final OfflinePlayer player : team.getPlayers()) { + teamTooltip.then("\n") + .then("- ").color(ChatColor.GRAY) + .then(player.getName()).color(ChatColor.WHITE); + } + + RawMessage.broadcast( + new RawText(I.t("{0}The team {1} has fallen!", format, team.getDisplayName() + format)) + .hover(teamTooltip) + ); + }, 1L); + } + } + + /** + * Colorizes each instance of the given player name in the string with its team color, + * if the player is in a team. + * + * @param str The string to colorize. + * @param player The player to look for in the string. + * @return The colorized string. + */ + private String colorizePlayerInString(final String str, final OfflinePlayer player) { + final QuartzTeam team = QuartzTeams.get().getTeamForPlayer(player); + if (team == null) { + return str; + } + + // We split the name to recompose the string with the colored name in each hole + final String[] strParts = str.split(player.getName()); + final ChatColor color = team.getColorOrWhite().toChatColor(); + final StringBuilder colorizedStr = new StringBuilder(); + + for (int i = 0; i < strParts.length; i++) { + colorizedStr.append(strParts[i]); + + if (i != strParts.length - 1) // If not the last one + { + final String previousStyles = ChatColor.getLastColors(colorizedStr.toString()); + colorizedStr.append(color).append(player.getName()).append(previousStyles); + } + } + + return colorizedStr.toString(); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/kick/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/kick/Config.java new file mode 100644 index 0000000..8e555f9 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/kick/Config.java @@ -0,0 +1,52 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.end.kick; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.i18n.I; +import java.io.File; + +public class Config extends ConfigurationInstance { + static public final ConfigurationItem<TimeDelta> DELAY = item("delay", new TimeDelta(30)); + static public final ConfigurationItem<String> MESSAGE = item("message", I.t("jayjay")); + + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/kick/KickModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/kick/KickModule.java new file mode 100644 index 0000000..c60102c --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/kick/KickModule.java @@ -0,0 +1,62 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.end.kick; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; + +@ModuleInfo( + name = "Kick On Death", + description = "Kicks players on death after a delay.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.END, + icon = Material.BARRIER, + settings = Config.class +) +public class KickModule extends QSGModule { + @EventHandler + public void onPlayerDeath(final AlivePlayerDeathEvent ev) { + if (ev.getPlayer().isOnline()) { + RunTask.later(() -> ev.getPlayer().getPlayer().kickPlayer(Config.MESSAGE.get()), + Config.DELAY.get().getSeconds() * 20L); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/xpToKillers/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/xpToKillers/Config.java new file mode 100644 index 0000000..3beb655 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/xpToKillers/Config.java @@ -0,0 +1,50 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.end.xpToKillers; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + +public class Config extends ConfigurationInstance { + public static final ConfigurationItem<Integer> LEVELS = item("levels", 2); + public static final ConfigurationItem<Boolean> ONLY_OTHER_TEAM = item("only-other-team", true); + + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/xpToKillers/XpToKillersModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/xpToKillers/XpToKillersModule.java new file mode 100644 index 0000000..54f9e41 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/end/xpToKillers/XpToKillersModule.java @@ -0,0 +1,75 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.end.xpToKillers; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import fr.zcraft.quartzteams.QuartzTeams; +import java.util.Objects; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +@ModuleInfo( + name = "XP to Killers", + description = "Gives a configurable amount of XP levels on player kill " + + "(optionally only for different team).", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.END, + icon = Material.EXPERIENCE_BOTTLE, + settings = Config.class +) +public class XpToKillersModule extends QSGModule { + @EventHandler + public void onPlayerDeath(final AlivePlayerDeathEvent ev) { + if (!ev.getPlayer().isOnline()) { + return; + } + + final Player killer = ev.getPlayer().getPlayer().getKiller(); + if (killer != null) { + boolean inSameTeam = Objects.equals(QuartzTeams.get().getTeamForPlayer(ev.getPlayer()), + QuartzTeams.get().getTeamForPlayer(killer)); + boolean onlyOtherTeam = Config.ONLY_OTHER_TEAM.get(); + + if (!onlyOtherTeam || !inSameTeam) { + killer.giveExpLevels(Config.LEVELS.get()); + } + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/dynmap/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/dynmap/Config.java new file mode 100644 index 0000000..4fa81cd --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/dynmap/Config.java @@ -0,0 +1,49 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.external.dynmap; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + +public class Config extends ConfigurationInstance { + static public final ConfigurationItem<Boolean> SHOW_SPAWN_LOCATIONS = item("show-spawn-locations", true); + static public final ConfigurationItem<Boolean> SHOW_DEATH_LOCATIONS = item("show-death-locations", true); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/dynmap/DynmapModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/dynmap/DynmapModule.java new file mode 100644 index 0000000..f30b29a --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/dynmap/DynmapModule.java @@ -0,0 +1,342 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.external.dynmap; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.PlayerResurrectedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start.PlayerSpawnPointSelectedEvent; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.core.QuartzLib; +import fr.zcraft.quartzteams.QuartzTeam; +import fr.zcraft.quartzteams.QuartzTeams; +import fr.zcraft.quartzteams.colors.TeamColor; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.dynmap.DynmapAPI; +import org.dynmap.markers.Marker; +import org.dynmap.markers.MarkerAPI; +import org.dynmap.markers.MarkerIcon; +import org.dynmap.markers.MarkerSet; + + +@ModuleInfo( + name = "Dynmap", + description = "Displays the spawn & death points on the dynmap.", + when = ModuleLoadTime.ON_GAME_STARTING, + category = ModuleCategory.EXTERNAL, + icon = Material.MAP, + settings = Config.class, + depends = "dynmap" +) +/* + * TODO: add the world border to the map. + */ +public class DynmapModule extends QSGModule { + private final DynmapAPI dynmapAPI = (DynmapAPI) Bukkit.getPluginManager().getPlugin("dynmap"); + private final MarkerAPI markerAPI = dynmapAPI.getMarkerAPI(); + + private MarkerSet markerSet = null; + + @Override + protected void onEnable() { + if (markerAPI == null) { + log().warning("Dynmap is available, but the markers API is not. The integration was disabled."); + QuartzLib.unregisterEvents(this); + return; + } + + markerSet = markerAPI.getMarkerSet("uhplugin.markerset"); + + if (markerSet == null) { + markerSet = markerAPI.createMarkerSet("uhplugin.markerset", "UHCReloaded", null, false); + } else { + markerSet.setMarkerSetLabel("UHCReloaded"); + } + } + + @Override + protected void onDisable() { + if (markerSet != null) { + markerSet.deleteMarkerSet(); + } + } + + + + /* *** DEATH LOCATIONS *** */ + + + /** + * Displays the death location of the given player. + * + * @param player The player. + */ + public void showDeathLocation(final Player player) { + if (!Config.SHOW_DEATH_LOCATIONS.get()) { + return; + } + + final String markerID = getDeathMarkerName(player); + /// Dynmap marker label of a death point + final String markerLabel = I.t("Death point of {0}", player.getName()); + final MarkerIcon icon = markerAPI.getMarkerIcon("skull"); + + final Marker marker = markerSet.createMarker( + markerID, markerLabel, true, + player.getLocation().getWorld().getName(), + player.getLocation().getX(), + player.getLocation().getY(), + player.getLocation().getZ(), + icon, false + ); + + if (marker == null) { + log().warning("Unable to create marker " + markerID); + } + } + + /** + * Hides the death location of the given player. + * + * @param player The player. + */ + public void hideDeathLocation(final OfflinePlayer player) { + if (!Config.SHOW_DEATH_LOCATIONS.get()) { + return; + } + + final Marker marker = markerSet.findMarker(getDeathMarkerName(player)); + if (marker != null) { + marker.deleteMarker(); + } + } + + /** + * Returns the internal ID of the marker of the death point of the given player. + * + * @param player The player. + * @return The ID. + */ + private String getDeathMarkerName(final OfflinePlayer player) { + return "uhplugin.death." + player.getName(); + } + + + + /* *** SPAWNS LOCATIONS *** */ + + + /** + * Displays the spawn point of the given player. + * + * <p> + * Used when the teleportation ignores the teams. + * </p> + * + * @param player The player. + * @param spawnPoint The location of the spawn point. + */ + public void showSpawnLocation(final OfflinePlayer player, final Location spawnPoint) { + if (!Config.SHOW_SPAWN_LOCATIONS.get()) { + return; + } + if (player == null) { + return; + } + + final QuartzTeam team = QuartzTeams.get().getTeamForPlayer(player); + if (team == null) { + return; + } + + final String markerLabel; + if (QSG.module(GameModule.class).isTeamsGame() && team.size() > 1) { + /// Dynmap marker label of a spawn point of a team. + markerLabel = I.t("Spawn point of the team {0}", team.getName()); + } else { + /// Dynmap marker label of a spawn point of a player, in solo. + markerLabel = I.t("Spawn point of {0}", team.getName()); + } + + showSpawnLocation( + spawnPoint, + team.getColor() == null ? TeamColor.GREEN : team.getColor(), + markerLabel, + getSpawnMarkerName(player) + ); + } + + /** + * Displays a spawn-point marker. + * + * @param spawnPoint The location of the spawn. + * @param color The color of the team (for the flag). + * @param label The label of the marker. + * @param markerID The ID of the marker. + */ + private void showSpawnLocation(final Location spawnPoint, final TeamColor color, final String label, + final String markerID) { + /* *** Icon *** */ + + final MarkerIcon icon; + + // Let's try to find the best icon + // Available flags: + // redflag, orangeflag, yellowflag, greenflag, blueflag, purpleflag, pinkflag, pirateflag (black) + // Ref. https://github.com/webbukkit/dynmap/wiki/Using-markers + + switch (color) { + case BLUE: + case DARK_BLUE: + case AQUA: + case DARK_AQUA: + icon = markerAPI.getMarkerIcon("blueflag"); + break; + + case GREEN: + case DARK_GREEN: + icon = markerAPI.getMarkerIcon("greenflag"); + break; + + case GOLD: + icon = markerAPI.getMarkerIcon("orangeflag"); + break; + + case YELLOW: + icon = markerAPI.getMarkerIcon("yellowflag"); + break; + + case RED: + case DARK_RED: + icon = markerAPI.getMarkerIcon("redflag"); + break; + + case DARK_PURPLE: + icon = markerAPI.getMarkerIcon("purpleflag"); + break; + + case LIGHT_PURPLE: + icon = markerAPI.getMarkerIcon("pinkflag"); + break; + + case BLACK: + case DARK_GRAY: + case GRAY: + icon = markerAPI.getMarkerIcon("pirateflag"); + break; + + case WHITE: // There is nothing better than pink I think... + default: + icon = markerAPI.getMarkerIcon("pinkflag"); + break; + } + + + /* *** Duplicate check *** */ + + // We check if there is already a spawn point with the same name + // at the same location. For teams games, with all players teleported + // to the same spot, this could occur. + + final Marker similarMarker = markerSet.findMarkerByLabel(label); + if (similarMarker != null + && similarMarker.getMarkerIcon().equals(icon) + && similarMarker.getX() == spawnPoint.getX() + && similarMarker.getY() == spawnPoint.getY() + && similarMarker.getZ() == spawnPoint.getZ()) { + return; + } + + + /* *** Registration *** */ + + final Marker marker = markerSet.createMarker( + markerID, + label, + true, + spawnPoint.getWorld().getName(), + spawnPoint.getX(), spawnPoint.getY(), spawnPoint.getZ(), + icon, + false + ); + + if (marker == null) { + log().warning("Unable to create marker {0}", markerID); + } + } + + /** + * Returns the internal ID of the marker of the spawn point of the given player. + * + * @param player The player. + * @return The ID. + */ + private String getSpawnMarkerName(final OfflinePlayer player) { + return "uhplugin.spawn." + player.getName(); + } + + + + /* *** EVENTS INTEGRATION *** */ + + + @EventHandler(priority = EventPriority.MONITOR) + public void onSpawnPointSelected(final PlayerSpawnPointSelectedEvent ev) { + showSpawnLocation(ev.getPlayer(), ev.getSpawnPoint()); + } + + @EventHandler + public void onPlayerDeath(final AlivePlayerDeathEvent ev) { + if (ev.getPlayer().isOnline()) { + showDeathLocation(ev.getPlayer().getPlayer()); + } + } + + @EventHandler + public void onPlayerResurrected(final PlayerResurrectedEvent ev) { + hideDeathLocation(ev.getPlayer()); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/hawk/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/hawk/Config.java new file mode 100644 index 0000000..f5f2731 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/hawk/Config.java @@ -0,0 +1,156 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.external.hawk; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.section; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.configuration.ConfigurationList; +import fr.zcraft.quartzlib.components.configuration.ConfigurationSection; +import java.io.File; +import java.util.Arrays; +import java.util.List; +import org.bukkit.Material; +import org.bukkit.Statistic; + +@SuppressWarnings("CheckStyle") +public class Config extends ConfigurationInstance { + public static final ConfigurationItem<String> REPORTS_API_BASE_URL = item("reports-api-base-url", ""); + public static final ConfigurationItem<Boolean> PUBLISH_REPORT = item("publish-report", true); + public static final ConfigurationItem<ReportBroadcastedTo> BROADCAST_REPORT_TO = + item("broadcast-report-to", ReportBroadcastedTo.ALL); + static public final ConfigurationItem<Boolean> DATE = item("date", true); + static public final ConfigurationItem<Boolean> PLAYERS_COUNT = item("players-count", true); + static public final ConfigurationItem<Boolean> WINNERS = item("winners", true); + static public final SummarySection SUMMARY = section("summary", SummarySection.class); + static public final DamagesSection DAMAGES = section("damages", DamagesSection.class); + static public final PlayersSection PLAYERS = section("players", PlayersSection.class); + + + public Config(File file) { + super(file); + } + + static public List<Statistic> defaultStatsHighlight() { + return Arrays.asList( + Statistic.DAMAGE_DEALT, + Statistic.DAMAGE_TAKEN, + Statistic.DAMAGE_RESISTED, + Statistic.DAMAGE_ABSORBED, + Statistic.CRAFT_ITEM, + Statistic.ITEM_ENCHANTED, + Statistic.BREWINGSTAND_INTERACTION, + Statistic.SPRINT_ONE_CM, + Statistic.HORSE_ONE_CM, + Statistic.SNEAK_TIME + ); + } + + static public List<Material> defaultUsedHighlight() { + return Arrays.asList( + Material.DIAMOND_SWORD, Material.DIAMOND_AXE, Material.DIAMOND_PICKAXE, Material.DIAMOND_HOE, + Material.IRON_SWORD, Material.IRON_AXE, Material.IRON_PICKAXE, Material.IRON_HOE, + Material.CAKE, Material.SADDLE, Material.GOLDEN_APPLE, Material.POTION, + Material.MUSIC_DISC_11, Material.MUSIC_DISC_13, Material.MUSIC_DISC_BLOCKS, Material.MUSIC_DISC_CAT, + Material.MUSIC_DISC_CHIRP, Material.MUSIC_DISC_FAR, Material.MUSIC_DISC_MALL, + Material.MUSIC_DISC_MELLOHI, + Material.MUSIC_DISC_STAL, Material.MUSIC_DISC_STRAD, Material.MUSIC_DISC_WAIT, Material.MUSIC_DISC_WARD + ); + } + + static public List<Material> defaultMinedHighlight() { + return Arrays.asList( + Material.DIAMOND, Material.DIAMOND_ORE, + Material.GOLD_INGOT, Material.GOLD_ORE, + Material.IRON_INGOT, Material.IRON_ORE, + Material.EMERALD, Material.EMERALD_ORE, + Material.OBSIDIAN, Material.NETHER_WART, + Material.SPAWNER, Material.STONE + ); + } + + static public List<Material> defaultPickedUpHighlight() { + return Arrays.asList( + Material.APPLE, + Material.BOW, Material.ENDER_PEARL, Material.GOLD_INGOT, + Material.PLAYER_HEAD, Material.CREEPER_HEAD, Material.DRAGON_HEAD, + Material.ZOMBIE_HEAD, Material.SKELETON_SKULL, Material.WITHER_SKELETON_SKULL + ); + } + + public enum ReportBroadcastedTo { + ALL, + ADMINISTRATORS, + CONSOLE + } + + static public class SummarySection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ENABLED = item("enabled", true); + public final ConfigurationItem<Boolean> HISTORY = item("history", true); + public final ConfigurationItem<Boolean> PLAYERS = item("players", true); + public final ConfigurationItem<Boolean> TEAMS = item("teams", true); + } + + static public class DamagesSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ENABLED = item("enabled", true); + public final ConfigurationItem<Boolean> DAMAGES_PER_PLAYERS = item("damages-per-players", true); + public final ConfigurationItem<Boolean> DAMAGES_PER_TEAMS = item("damages-per-teams", true); + public final ConfigurationItem<Boolean> DAMAGES_FROM_ENVIRONMENT = item("damages-from-environment", true); + public final ConfigurationItem<Boolean> DISPLAY_KILLER = item("display-killer", true); + } + + static public class PlayersSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ENABLED = item("enabled", true); + public final ConfigurationItem<Boolean> PLAY_TIME = item("play-time", true); + + public final ConfigurationItem<Boolean> GLOBAL_STATISTICS = item("global-statistics", true); + public final ConfigurationList<Statistic> STATISTICS_WHITELIST = list("statistics-whitelist", Statistic.class); + public final ConfigurationList<Statistic> STATISTICS_HIGHLIGHT = list("statistics-highlight", Statistic.class); + + public final ConfigurationItem<Boolean> USED = item("used", false); + public final ConfigurationList<Material> USED_WHITELIST = list("used-whitelist", Material.class); + public final ConfigurationList<Material> USED_HIGHLIGHT = list("used-highlight", Material.class); + + public final ConfigurationItem<Boolean> MINED = item("mined", true); + public final ConfigurationList<Material> MINED_WHITELIST = list("mined-whitelist", Material.class); + public final ConfigurationList<Material> MINED_HIGHLIGHT = list("mined-highlight", Material.class); + + public final ConfigurationItem<Boolean> PICKED_UP = item("picked-up", true); + public final ConfigurationList<Material> PICKED_UP_WHITELIST = list("picked-up-whitelist", Material.class); + public final ConfigurationList<Material> PICKED_UP_HIGHLIGHT = list("picked-up-highlight", Material.class); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/hawk/HawkModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/hawk/HawkModule.java new file mode 100644 index 0000000..97cb66c --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/hawk/HawkModule.java @@ -0,0 +1,611 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.external.hawk; + +import eu.carrade.amaury.quartzsurvivalgames.QSGConfig; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.PlayerResurrectedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.goldenHeads.GoldenHeadsModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.CommandUtils; +import fr.zcraft.quartzlib.components.events.FutureEventHandler; +import fr.zcraft.quartzlib.components.events.WrappedEvent; +import fr.zcraft.quartzlib.components.gui.GuiUtils; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.components.rawtext.RawText; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.reflection.Reflection; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import fr.zcraft.quartzlib.tools.text.RawMessage; +import fr.zcraft.quartzteams.QuartzTeam; +import fr.zcraft.quartzteams.QuartzTeams; +import fr.zcraft.quartzteams.events.PlayerJoinedTeamEvent; +import fr.zcraft.quartzteams.events.PlayerLeftTeamEvent; +import fr.zcraft.quartzteams.events.TeamRegisteredEvent; +import fr.zcraft.quartzteams.events.TeamUnregisteredEvent; +import fr.zcraft.quartzteams.events.TeamUpdatedEvent; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import me.cassayre.florian.hawk.ReportsManager; +import me.cassayre.florian.hawk.report.InvalidReportException; +import me.cassayre.florian.hawk.report.Report; +import me.cassayre.florian.hawk.report.ReportEvent; +import me.cassayre.florian.hawk.report.ReportTeam; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.SkullType; +import org.bukkit.World; +import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.enchantment.EnchantItemEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.inventory.BrewEvent; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; +import org.bukkit.scheduler.BukkitTask; + + +@ModuleInfo( + name = "Hawk Reports", + description = "Generates reports of the game, including history, damages, " + + "heals, statistics, etc., displayed on a web page, and gives the URL " + + "when the match ends.", + authors = "Florian Cassayre & Amaury Carrade through the Hawk Project", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.EXTERNAL, + icon = Material.KNOWLEDGE_BOOK, + settings = Config.class, + can_be_unloaded = false +) +public class HawkModule extends QSGModule { + private GameModule game; + + private Report report; + + /* + * Switches for some timeline's events. + */ + private boolean firstApple = false; + private boolean firstGold = false; + private boolean firstDiamond = false; + private boolean firstEnchant = false; + private boolean firstBrew = false; + private boolean firstNether = false; + private boolean firstEnd = false; + private boolean firstGoldenApple = false; + private boolean firstGoldenHead = false; + + /* + * Used to know who used the brewing stands last to know to who the “first + * brew” event should be attributed. + */ + private Map<Location, UUID> lastBrewingStandUsers = new HashMap<>(); + + /* + * After the end of the game, we wait a bit to handle late events + * (like final cross-kill, or fire-kill from fire aspect…). + */ + private BukkitTask waitAfterEndTask = null; + private final TimeDelta waitAfterEndDelay = new TimeDelta(30); + private boolean waitingAfterEnd = false; + + + @Override + protected void onEnable() { + game = QSG.module(GameModule.class); + + ReportsManager.init(QSG.get()); + + if (!Config.REPORTS_API_BASE_URL.get().isEmpty()) { + ReportsManager.get().setRemoteInstanceURL(Config.REPORTS_API_BASE_URL.get()); + } + + report = new Report() + .selfRegister() + .autoTrack(true) + .stopTrackOnDisconnection(false) + + // We'll manage theses ourselves. + .stopTrackOnDeath(false) + .autoTrackNewPlayers(false) + .addDefaultEvents(false) + + .autoCollectPreviousStatistics(true) + .registerPlayers(game.getAlivePlayers()) + + .title(QSGConfig.TITLE.get()) + + .settings() + .displayDate(Config.DATE.get()) + .displayPlayersCount(Config.PLAYERS_COUNT.get()) + .displayWinners(Config.WINNERS.get()) + .enableSummary( + Config.SUMMARY.HISTORY.get(), + Config.SUMMARY.PLAYERS.get(), + Config.SUMMARY.TEAMS.get() + ) + .enableDamages( + Config.DAMAGES.DAMAGES_PER_PLAYERS.get(), + Config.DAMAGES.DAMAGES_PER_TEAMS.get(), + Config.DAMAGES.DAMAGES_FROM_ENVIRONMENT.get(), + Config.DAMAGES.DISPLAY_KILLER.get() + ) + .enablePlayers( + Config.PLAYERS.PLAY_TIME.get(), + Config.PLAYERS.GLOBAL_STATISTICS.get(), + Config.PLAYERS.USED.get(), + Config.PLAYERS.MINED.get(), + Config.PLAYERS.PICKED_UP.get() + ) + .highlightingTheseStatistics( + Config.PLAYERS.STATISTICS_HIGHLIGHT.isDefined() + ? Config.PLAYERS.STATISTICS_HIGHLIGHT + : Config.defaultStatsHighlight() + ) + .highlightingTheseUsedItems( + Config.PLAYERS.USED_HIGHLIGHT.isDefined() + ? Config.PLAYERS.USED_HIGHLIGHT + : Config.defaultUsedHighlight() + ) + .highlightingTheseMinedBlocks( + Config.PLAYERS.MINED_HIGHLIGHT.isDefined() + ? Config.PLAYERS.MINED_HIGHLIGHT + : Config.defaultMinedHighlight() + ) + .highlightingThesePickedUpItems( + Config.PLAYERS.PICKED_UP_HIGHLIGHT.isDefined() + ? Config.PLAYERS.PICKED_UP_HIGHLIGHT + : Config.defaultPickedUpHighlight() + ) + .withTheseInGlobalStatisticsWhitelist(Config.PLAYERS.STATISTICS_WHITELIST) + .withTheseInUsedStatisticsWhitelist(Config.PLAYERS.USED_WHITELIST) + .withTheseInMinedStatisticsWhitelist(Config.PLAYERS.MINED_WHITELIST) + .withTheseInPickedUpStatisticsWhitelist(Config.PLAYERS.PICKED_UP_WHITELIST) + .withGenerator( + "Quartz Survival Games", + "https://www.spigotmc.org/resources/ultrahardcore-reloaded.1622/" + ) + .done(); + + if (!Config.SUMMARY.ENABLED.get()) { + report.settings().disableSummary(); + } + if (!Config.DAMAGES.ENABLED.get()) { + report.settings().disableDamages(); + } + if (!Config.PLAYERS.ENABLED.get()) { + report.settings().disablePlayers(); + } + + updateReportTeams(); + + RunTask.nextTick(() -> log().info("Hawk is now recording the game.")); + } + + public Report getReport() { + return report; + } + + private void updateReportTeams() { + report.resetTeams(); + + if (game.isTeamsGame()) { + QuartzTeams.get().getTeams().stream() + .map(team -> new ReportTeam(team.getName(), + team.getColor() != null ? team.getColor().toChatColor() : null, team.getPlayers())) + .forEach(report::registerTeam); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onGamePhaseChanged(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() == GamePhase.END) { + final QuartzTeam winner = game.getWinner(); + if (winner != null) { + report.setWinners(winner.getPlayers()); + } + + waitingAfterEnd = true; + + waitAfterEndTask = RunTask.later(() -> + { + waitingAfterEnd = false; + + report.autoTrack(false).title(QSGConfig.TITLE.get()); + + report.save( + saved -> + PluginLogger.info("The JSON report for this game has been written to {0}.", + saved.getAbsolutePath()), + error -> + PluginLogger + .error("Unable to save the JSON report for this game to the disk. There were backups, you may be lucky and find something there. If configured to do so, the report will still be published.", + error) + ); + + if (!Config.PUBLISH_REPORT.get()) { + return; + } + + report.publish( + uri -> { + switch (Config.BROADCAST_REPORT_TO.get()) { + case ALL: + Bukkit.getOnlinePlayers().forEach(CommandUtils::displaySeparator); + + Bukkit.broadcastMessage("\n " + GuiUtils.generatePrefixedFixedLengthString( + " ", + I.t("{aqua}{bold}Want a summary?") + ChatColor.RESET + "\n" + + I.t("{darkaqua}Click the link below to see (and share, if you want) the game timeline, events, damages summary, and other statistics!") + )); + + Bukkit.broadcastMessage(""); + + RawMessage.broadcast( + new RawText(" ").hover(I.t("Open {aqua}{0}", uri.toString())) + .then("»").style(ChatColor.DARK_AQUA, ChatColor.BOLD).uri(uri) + .then(" ").uri(uri) + .then(uri.toString()).style(ChatColor.AQUA).uri(uri) + .then(" ").uri(uri) + .then("«").style(ChatColor.DARK_AQUA, ChatColor.BOLD).uri(uri) + .build() + ); + + Bukkit.broadcastMessage(""); + Bukkit.getOnlinePlayers().forEach(CommandUtils::displaySeparator); + + break; + + case ADMINISTRATORS: + log().broadcastAdministrative(""); + log().broadcastAdministrative(I.t("{darkaqua}{bold}A game report was generated")); + log().broadcastAdministrative( + I.t("{darkaqua}You can share it using the following URL. It was not broadcast to other players.")); + log().broadcastAdministrative(""); + + log().broadcastAdministrative( + new RawText().uri(uri).hover(I.t("Open {aqua}{0}", uri.toString())) + .then("» ").style(ChatColor.DARK_AQUA, ChatColor.BOLD) + .then(uri.toString()).style(ChatColor.AQUA) + .build() + ); + + log().broadcastAdministrative(""); + break; + + case CONSOLE: + log().info( + "A game report was generated. You can share it using the following URL: {0} .", + uri); + break; + } + }, + error -> { + final String message; + + if (error instanceof IOException) { + message = I.t("I/O Error: {0}", error.getLocalizedMessage()); + } else if (error instanceof InvalidReportException) { + message = I.t("Invalid Report: {0} ({1})", error.getMessage(), + ((InvalidReportException) error).getCode()); + } else { + message = error.getMessage(); + } + + log().broadcastAdministrative(""); + log().broadcastAdministrative(I.t("{red}{bold}Unable to publish the game report")); + log().broadcastAdministrative(ChatColor.RED + message); + log().broadcastAdministrative(""); + } + ); + + }, waitAfterEndDelay.getSeconds() * 20L); + } else if (ev.getNewPhase() == GamePhase.IN_GAME && !ev.isRunningForward()) { + report.resetWinners(); + report.autoTrack(true); + + waitingAfterEnd = false; + + if (waitAfterEndTask != null) { + waitAfterEndTask.cancel(); + waitAfterEndTask = null; + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerDeath(final AlivePlayerDeathEvent ev) { + report + .untrack(ev.getPlayer()) + .record(ReportEvent.withPlayer( + ReportEvent.EventType.GOLD, + /// Title of the death event on the game report's timeline. + I.t("Death of {0}", ev.getPlayer().getName()), + ev.getPlayerDeathEvent() != null + && ev.getPlayerDeathEvent().getDeathMessage() != null + && !ev.getPlayerDeathEvent().getDeathMessage().isEmpty() + ? ev.getPlayerDeathEvent().getDeathMessage() + : null, + ev.getPlayer() + )); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerDeath(final PlayerDeathEvent ev) { + // Recording cross-kills and other deaths after the game end (e.g. from fire) + // during a 30-seconds period. + + if (!waitingAfterEnd) { + return; + } + + report + .untrack(ev.getEntity()) + .record(ReportEvent.withPlayer( + ReportEvent.EventType.GOLD, + /// Title of the death event on the game report's timeline. + I.t("Death of {0}", ev.getEntity().getName()), + !ev.getDeathMessage().isEmpty() ? ev.getDeathMessage() : null, + ev.getEntity() + )); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerResurrected(final PlayerResurrectedEvent ev) { + report + .track(ev.getPlayer()) + .record(ReportEvent.withPlayer( + ReportEvent.EventType.GREEN, + /// Title of the resurrection event on the game report's timeline. + I.t("{0} was resurrected", ev.getPlayer().getName()), + ev.getPlayer() + )); + updateReportTeams(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onTeamsChange(final TeamUpdatedEvent ev) { + updateReportTeams(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onTeamsChange(final TeamRegisteredEvent ev) { + updateReportTeams(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onTeamsChange(final TeamUnregisteredEvent ev) { + updateReportTeams(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onTeamsChange(final PlayerJoinedTeamEvent ev) { + updateReportTeams(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onTeamsChange(final PlayerLeftTeamEvent ev) { + updateReportTeams(); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onFirstEnchant(final EnchantItemEvent ev) { + if (firstEnchant || !game.isAlive(ev.getEnchanter())) { + return; + } + + report.record(ReportEvent.withIcon( + I.t("{0} enchants the first tool", ev.getEnchanter().getName()), + "item-book-enchanted" + )); + + firstEnchant = true; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBrewingStandUsed(final PlayerInteractEvent ev) { + if (firstBrew + || !game.isAlive(ev.getPlayer()) + || !ev.hasBlock() + || ev.getAction() != Action.RIGHT_CLICK_BLOCK + || ev.getClickedBlock().getType() != Material.BREWING_STAND) { + return; + } + + lastBrewingStandUsers.put(ev.getClickedBlock().getLocation(), ev.getPlayer().getUniqueId()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onFirstBrew(final BrewEvent ev) { + if (firstBrew) { + return; + } + + final UUID player = lastBrewingStandUsers.get(ev.getBlock().getLocation()); + if (player == null) { + return; + } + + report.record(ReportEvent.withIcon( + I.t("{0} brewed the first potion", Bukkit.getOfflinePlayer(player).getName()), + "item-brewing-stand" + )); + + firstBrew = true; + + lastBrewingStandUsers.clear(); + lastBrewingStandUsers = null; + } + + private void onFirstItemCollected(final Material item, final OfflinePlayer player) { + if (!game.isAlive(player)) { + return; + } + + if (!firstDiamond && (item == Material.DIAMOND || item == Material.DIAMOND_ORE)) { + report.record(ReportEvent.withIcon( + I.t("{0} finds the first diamond", player.getName()), + "item-diamond" + )); + + firstDiamond = true; + } else if (!firstGold && (item == Material.GOLD_INGOT || item == Material.GOLD_ORE)) { + report.record(ReportEvent.withIcon( + I.t("{0} finds the first gold ingot", player.getName()), + "item-gold-ingot" + )); + + firstGold = true; + } else if (!firstApple && item == Material.APPLE) { + report.record(ReportEvent.withIcon( + I.t("{0} harvested the first apple", player.getName()), + "item-apple" + )); + + firstApple = true; + } + } + + /* + * This event is deprecated. We load it as a future event, so when it will be removed, + * the plugin will not break. We conjointly listen for the new event below, also + * as a future event so the plugin can run in older Minecraft versions where the new + * event isn't there yet. + * + * The event will be called twice on intermediate versions, but the flag will ensure only + * one event will be recorded for each item. + */ + @FutureEventHandler(event = "entity.PlayerPickupItemEvent", priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onOldFirstItemCollected(final WrappedEvent ev) { + try { + onFirstItemCollected( + ((Item) Reflection.call(ev.getEvent(), "getItem")).getItemStack().getType(), + ((Player) Reflection.call(ev.getEvent(), "getPlayer")) + ); + } + catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + PluginLogger.error("Unable to retrieve picked-up item to build the report. Will be ignored.", e); + } + } + + @FutureEventHandler(event = "entity.EntityPickupItemEvent", priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onFirstItemCollected(final WrappedEvent ev) { + try { + LivingEntity entity = (LivingEntity) Reflection.call(ev.getEvent(), "getEntity"); + + if (entity instanceof Player) { + onFirstItemCollected( + ((Item) Reflection.call(ev.getEvent(), "getItem")).getItemStack().getType(), + (Player) entity + ); + } + } + catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + PluginLogger.error("Unable to retrieve picked-up item to build the report. Will be ignored.", e); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onWorldChange(final PlayerChangedWorldEvent ev) { + if (!game.isAlive(ev.getPlayer())) { + return; + } + + if (!firstNether && + ev.getPlayer().getWorld().getName().equals(QSG.get().getWorld(World.Environment.NETHER).getName())) { + report.record(ReportEvent.withIcon( + ReportEvent.EventType.RED, + I.t("{0} enters first the Nether", ev.getPlayer().getName()), + "block-portal" + )); + + firstNether = true; + } else if (!firstEnd && + ev.getPlayer().getWorld().getName().equals(QSG.get().getWorld(World.Environment.THE_END).getName())) { + report.record(ReportEvent.withIcon( + I.t("{0} enters first The End", ev.getPlayer().getName()), + "block-endframe" + )); + + firstEnd = true; + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onItemConsumed(final PlayerItemConsumeEvent ev) { + if (!game.isAlive(ev.getPlayer()) || ev.getItem().getType() != Material.GOLDEN_APPLE) { + return; + } + + final SkullType headType = + QSG.loaded(GoldenHeadsModule.class) ? QSG.module(GoldenHeadsModule.class).readHeadType(ev.getItem()) : + null; + + if (headType == SkullType.PLAYER && !firstGoldenHead) { + report.record(ReportEvent.withIcon( + I.t("{0} ate the first golden head", ev.getPlayer().getName()), + "item-apple-golden" + )); + + firstGoldenHead = true; + } else if (!firstGoldenApple) { + report.record(ReportEvent.withIcon( + I.t("{0} ate the first golden apple", ev.getPlayer().getName()), + "item-apple-golden" + )); + + firstGoldenApple = true; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/motd/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/motd/Config.java new file mode 100644 index 0000000..be7b94f --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/motd/Config.java @@ -0,0 +1,49 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.external.motd; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + +public class Config extends ConfigurationInstance { + static public final ConfigurationItem<Boolean> DISPLAY_MATCH_NAME = item("display-match-name", true); + static public final ConfigurationItem<String> MATCH_NAME_PREFIX = item("match-name-prefix", ""); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/motd/MotdModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/motd/MotdModule.java new file mode 100644 index 0000000..f87d182 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/external/motd/MotdModule.java @@ -0,0 +1,111 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.external.motd; + +import eu.carrade.amaury.quartzsurvivalgames.QSGConfig; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzteams.QuartzTeam; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.server.ServerListPingEvent; + + +@ModuleInfo( + name = "MOTD", + description = "Updates the MOTD according to the current game state.", + category = ModuleCategory.EXTERNAL, + icon = Material.DARK_OAK_SIGN, + settings = Config.class +) +public class MotdModule extends QSGModule { + private final GameModule game = QSG.module(GameModule.class); + + private String getMOTD() { + final String matchName; + + if (Config.DISPLAY_MATCH_NAME.get()) { + matchName = ChatColor.translateAlternateColorCodes('&', Config.MATCH_NAME_PREFIX.get()) + + QSGConfig.TITLE.get() + + ChatColor.RESET + "\n"; + } else { + matchName = ""; + } + + switch (game.getPhase()) { + case WAIT: + return matchName + I.t("Waiting for players..."); + + case STARTING: + return matchName + I.t("Starting in progress..."); + + case IN_GAME: + if (game.isTeamsGame()) { + /// Teams game running MOTD. {0} = players alive count. {1} = teams alive count. Plural based on players count. + return matchName + I.tn("Game running! {0} player alive in {1} team.", + "Game running! {0} players alive in {1} teams.", game.countAlivePlayers(), + game.countAlivePlayers(), game.countAliveTeams()); + } else { + /// Solo game running MOTD. {0} = players alive count. + return matchName + I.tn("Game running! {0} player alive.", "Game running! {0} players alive.", + game.countAlivePlayers()); + } + + case END: + default: + final QuartzTeam winner = game.getWinner(); + + if (game.isTeamsGame()) { + /// Game finished MOTD with team winner ({0} = team display name). + return matchName + I.t("Game finished; the team {0} wins this match!", + winner != null ? winner.getDisplayName() : "??"); + } else { + /// Game finished MOTD with solo winner ({0} = winner raw name). + return matchName + I.t("Game finished; congratulation to {0} for his victory!", + winner != null ? winner.getName() : "??"); + } + } + } + + @EventHandler + public void onServerListPing(final ServerListPingEvent ev) { + ev.setMotd(getMOTD()); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/NoEnderPearlDamagesModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/NoEnderPearlDamagesModule.java new file mode 100644 index 0000000..46f0b2b --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/NoEnderPearlDamagesModule.java @@ -0,0 +1,67 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +@ModuleInfo( + name = "No Ender Pearl Damages", + description = "Removes all damages from ender pearls, basically allowing players to use them.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.GAMEPLAY, + icon = Material.ENDER_PEARL +) +public class NoEnderPearlDamagesModule extends QSGModule { + @EventHandler(ignoreCancelled = true) + public void onPlayerTeleport(final PlayerTeleportEvent ev) { + if (ev.getCause() == TeleportCause.ENDER_PEARL) { + ev.setCancelled(true); + + // Technically its an ender pearl teleportation, but + // if we use that, an infinite loop will occur due to + // the event being re-captured and re-emitted. That's + // why PLUGIN is used instead. + ev.getPlayer().teleport(ev.getTo(), TeleportCause.PLUGIN); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/NoGhastTearsModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/NoGhastTearsModule.java new file mode 100644 index 0000000..8fd0c7d --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/NoGhastTearsModule.java @@ -0,0 +1,90 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import java.util.ArrayList; +import java.util.List; +import org.bukkit.Material; +import org.bukkit.entity.Ghast; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.inventory.ItemStack; + +@ModuleInfo( + name = "No Ghast Tears", + description = "Replaces ghast tears with gold, to disable regeneration " + + "potions while keeping a reward for the action.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.GAMEPLAY, + icon = Material.GHAST_TEAR +) +public class NoGhastTearsModule extends QSGModule { + /** + * Used to replace ghast tears with gold (if needed). + */ + @EventHandler(ignoreCancelled = true) + public void onEntityDeath(EntityDeathEvent ev) { + if (ev.getEntity() instanceof Ghast) { + final List<ItemStack> drops = new ArrayList<>(ev.getDrops()); + ev.getDrops().clear(); + + for (final ItemStack i : drops) { + if (i.getType() == Material.GHAST_TEAR) { + ev.getDrops().add(new ItemStack(Material.GOLD_INGOT, i.getAmount())); + } else { + ev.getDrops().add(i); + } + } + } + } + + /** + * Used to prevent the user to get a ghast tear. + */ + @EventHandler(ignoreCancelled = true) + public void onPlayerPickupItem(PlayerPickupItemEvent ev) { + if (ev.getItem().getItemStack().getType() == Material.GHAST_TEAR && + QSG.module(GameModule.class).isAlive(ev.getPlayer())) { + ev.setCancelled(true); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/NoOverpoweredSuspiciousStews.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/NoOverpoweredSuspiciousStews.java new file mode 100644 index 0000000..76a17e9 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/NoOverpoweredSuspiciousStews.java @@ -0,0 +1,68 @@ +/* + * Plugin UHCReloaded + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.inventory.PrepareItemCraftEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SuspiciousStewMeta; +import org.bukkit.potion.PotionEffectType; + + +@ModuleInfo( + name = "No Overpowered Suspicious Stews", + description = "Disables suspicious stews giving regeneration status effect.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.GAMEPLAY, + icon = Material.SUSPICIOUS_STEW +) +public class NoOverpoweredSuspiciousStews extends QSGModule { + @EventHandler + private void onPreCraft(final PrepareItemCraftEvent ev) { + if (ev.getInventory().getResult() != null && ev.getInventory().getResult().getType() == Material.SUSPICIOUS_STEW) { + final SuspiciousStewMeta stewMeta = (SuspiciousStewMeta) ev.getInventory().getResult().getItemMeta(); + if (stewMeta == null) return; + + if (stewMeta.hasCustomEffect(PotionEffectType.REGENERATION)) { + ev.getInventory().setResult(new ItemStack(Material.AIR)); + } + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/OnerousGlisteringMelon.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/OnerousGlisteringMelon.java new file mode 100644 index 0000000..837844d --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/OnerousGlisteringMelon.java @@ -0,0 +1,87 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.utils.RecipesUtils; +import fr.zcraft.quartzlib.tools.items.CraftingRecipes; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.inventory.PrepareItemCraftEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; + + +@ModuleInfo( + name = "Onerous Glistering Melon", + description = "Changes the vanilla recipe for glistering melon, replacing gold nuggets by gold ingots, to make healing potions harder to get.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.GAMEPLAY, + icon = Material.GLISTERING_MELON_SLICE +) +public class OnerousGlisteringMelon extends QSGModule { + private final Recipe VANILLA_RECIPE = CraftingRecipes.shaped( + "glistering_melon_vanilla", + new ItemStack(Material.GLISTERING_MELON_SLICE), + "AAA", + "ABA", + "AAA", + Material.GOLD_NUGGET, Material.MELON_SLICE + ); + + private final Recipe ONEROUS_RECIPE = CraftingRecipes.shaped( + "glistering_melon_with_ingots", + new ItemStack(Material.GLISTERING_MELON_SLICE), + "AAA", + "ABA", + "AAA", + Material.GOLD_INGOT, Material.MELON_SLICE + ); + + @Override + protected void onEnable() { + CraftingRecipes.add(ONEROUS_RECIPE); + } + + @EventHandler + private void onPreCraft(final PrepareItemCraftEvent ev) { + if (RecipesUtils.areSimilar(ev.getRecipe(), VANILLA_RECIPE)) { + ev.getInventory().setResult(new ItemStack(Material.AIR)); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/compass/CompassModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/compass/CompassModule.java new file mode 100644 index 0000000..bef2525 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/compass/CompassModule.java @@ -0,0 +1,261 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.compass; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGSound; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.components.i18n.I18n; +import fr.zcraft.quartzlib.components.rawtext.RawText; +import fr.zcraft.quartzlib.core.QuartzLib; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import fr.zcraft.quartzlib.tools.text.MessageSender; +import fr.zcraft.quartzteams.QuartzTeams; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Locale; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import org.apache.commons.lang.math.RandomUtils; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +@ModuleInfo( + name = "Compass", + description = "Compasses in the game can be used to point to the nearest player, " + + "and/or give the distance to them, at a configurable fee. The compass' craft " + + "can also be made harder.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.GAMEPLAY, + icon = Material.COMPASS, + settings = Config.class +) +public class CompassModule extends QSGModule { + private CompassRecipes recipes = null; + + private final Set<UUID> compassLocked = new HashSet<>(); + + + @Override + public void onEnable() { + recipes = QuartzLib.loadComponent(CompassRecipes.class); + } + + @Override + protected void onDisable() { + if (recipes != null) { + QuartzLib.unregisterEvents(recipes); + recipes = null; + } + } + + /** + * Used to update the compass. + */ + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerInteract(final PlayerInteractEvent ev) { + if (ev.getAction() != Action.PHYSICAL) { + ev.setCancelled(activateCompass(ev.getPlayer())); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerInteractAtEntity(final PlayerInteractAtEntityEvent ev) { + ev.setCancelled(activateCompass(ev.getPlayer())); + } + + /** + * Activates the compass for the player. + * + * @param compassUser The player. + * @return {@code true} if the compass was activated. + */ + private boolean activateCompass(final Player compassUser) { + if (!QSG.game().isAlive(compassUser) || compassUser.getItemInHand().getType() != Material.COMPASS) { + return false; + } + if (compassLocked.contains(compassUser.getUniqueId())) { + return false; + } + + compassLocked.add(compassUser.getUniqueId()); + RunTask.later(() -> compassLocked.remove(compassUser.getUniqueId()), 10L); + + final Locale locale = I18n.getPlayerLocale(compassUser); + + // We check if the player have what needed + + int feeAvailable = Arrays.stream(compassUser.getInventory().getContents()) + .filter(item -> item != null && item.getType() == Config.COMPASS_FEE_ITEM.get()) + .mapToInt(ItemStack::getAmount) + .sum(); + + if (feeAvailable < Config.COMPASS_FEE_AMOUNT.get()) { + MessageSender.sendActionBarMessage(compassUser, new RawText() + /// The singular is in the sentence « To use the compass, you must have one rotten flesh ». The plural: « […] you must have Rotten Flesh × 2 »? + .then(I.tln(locale, "To use the compass, you must have one ", "To use the compass, you must have ", + Config.COMPASS_FEE_AMOUNT.get())).color(ChatColor.RED) + .then().translate(new ItemStack(Config.COMPASS_FEE_ITEM.get(), Config.COMPASS_FEE_AMOUNT.get())) + .color(ChatColor.RED) + .then(Config.COMPASS_FEE_AMOUNT.get() > 1 ? " × " + Config.COMPASS_FEE_AMOUNT.get() : "") + .color(ChatColor.RED) + .then(".").color(ChatColor.RED) + .build() + ); + new QSGSound(1F, 1F, "BLOCK_WOOD_STEP", "STEP_WOOD").play(compassUser); + return false; + } + + // We consume the fee + + int feeLeft = Config.COMPASS_FEE_AMOUNT.get(); + + for (final ItemStack item : compassUser.getInventory().getContents()) { + if (item != null && item.getType() == Config.COMPASS_FEE_ITEM.get()) { + final int consumed = item.getAmount() - feeLeft; + + if (consumed <= 0) { + feeLeft -= item.getAmount(); + item.setAmount(0); + item.setType(Material.AIR); + } else { + feeLeft = 0; + item.setAmount(consumed); + } + + if (feeLeft == 0) { + break; + } + } + } + + // We lookup for the nearest player + + Player nearest = null; + Double distance = Double.MAX_VALUE; + + for (final Player otherPlayer : QSG.module(GameModule.class).getAliveConnectedPlayers()) { + try { + Double calc = compassUser.getLocation().distanceSquared(otherPlayer.getLocation()); + + if (calc > 1 && calc < distance) { + distance = calc; + + if (!otherPlayer.getUniqueId().equals(compassUser.getUniqueId()) && + (!Config.NEVER_TARGET_TEAMMATES.get() || + !Objects.equals(QuartzTeams.get().getTeamForPlayer(compassUser), + QuartzTeams.get().getTeamForPlayer(otherPlayer)))) { + nearest = otherPlayer.getPlayer(); + } + } + } + catch (Exception ignored) { + } // Different worlds + } + + if (nearest == null) { + /// Error message if a player tries to use his pointing compass without a player nearby. + MessageSender.sendActionBarMessage(compassUser, QSGUtils + .prefixedMessage(ChatColor.BOLD + I.tl(locale, "Compass"), ChatColor.YELLOW + "" + ChatColor.BOLD + + I.tl(locale, "Only silence answers your request."))); + + new QSGSound(1F, 1F, "BLOCK_WOOD_STEP", "STEP_WOOD").play(compassUser); + return false; + } + + CompassBehavior behavior = Config.COMPASS_BEHAVIOR.get(); + + if (behavior == CompassBehavior.GIVE_EITHER_RANDOMLY) { + final double r = RandomUtils.nextDouble(); + + if (r < .45) { + behavior = CompassBehavior.GIVE_DIRECTION; + } else if (r < .9) { + behavior = CompassBehavior.GIVE_DISTANCE; + } else { + behavior = CompassBehavior.GIVE_BOTH; + } + } + + if (behavior == CompassBehavior.GIVE_BOTH) { + compassUser.setCompassTarget(nearest.getLocation()); + compassUser.sendMessage(QSGUtils.prefixedMessage( + I.tl(locale, "Compass"), + ChatColor.YELLOW + I.tln( + locale, + "The compass now points to the closest player, {gold}{0} block {yellow}from you.", + "The compass now points to the closest player, {gold}{0} blocks {yellow}from you.", + (int) nearest.getLocation().distanceSquared(compassUser.getLocation()) + ) + )); + } else if (behavior == CompassBehavior.GIVE_DIRECTION) { + compassUser.setCompassTarget(nearest.getLocation()); + + /// Success message when a player uses his pointing compass. + MessageSender.sendActionBarMessage(compassUser, ChatColor.YELLOW + "" + ChatColor.BOLD + + I.tl(locale, "The compass now points to the closest player.")); + } else { + compassUser.sendMessage(QSGUtils.prefixedMessage(I.tl(locale, "Compass"), + I.tln(locale, "{yellow}There is {gold}{0} block {yellow}between the nearest player and yourself.", + "{yellow}There are {gold}{0} blocks {yellow}between the nearest player and yourself.", + (int) nearest.getLocation().distance(compassUser.getLocation())))); + } + + new QSGSound(1F, 1F, "ENTITY_ENDERMEN_TELEPORT", "ENDERMAN_TELEPORT").play(compassUser); + + return true; + } + + public enum CompassBehavior { + GIVE_DIRECTION, + GIVE_DISTANCE, + GIVE_BOTH, + GIVE_EITHER_RANDOMLY + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/compass/CompassRecipes.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/compass/CompassRecipes.java new file mode 100644 index 0000000..a1132d3 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/compass/CompassRecipes.java @@ -0,0 +1,266 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.compass; + +import eu.carrade.amaury.quartzsurvivalgames.utils.RecipesUtils; +import fr.zcraft.quartzlib.core.QuartzComponent; +import fr.zcraft.quartzlib.tools.items.CraftingRecipes; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import java.util.ArrayList; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.inventory.PrepareItemCraftEvent; +import org.bukkit.inventory.CraftingInventory; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; + +public class CompassRecipes extends QuartzComponent implements Listener { + private final Recipe VANILLA_RECIPE = CraftingRecipes.shaped( + "compass_vanilla", + new ItemStack(Material.COMPASS), + " A ", + "ABA", + " A ", + Material.IRON_INGOT, Material.REDSTONE + ); + + /** + * Checks if the recipe is a valid compass recipe. + * <p> + * A valid compass recipe is a recipe with: + * <ul> + * <li> + * in the center, the valid ingredient for the current compass craft + * (redstone, ender pearl or eye of ender); + * </li> + * <li> + * four iron ingots placed like the vanilla compass recipe; + * </li> + * <li> + * in the four corners, a bone, a rotten flesh, a spider eye and a gunpowder, + * placed in any shape. + * </li> + * </ul> + * <p> + * Executed in the {@code onInventoryClick} and {@code onInventoryDrag} events, to allow this to be recognized even if + * the recipe is not registered. + * + * @param matrix The content of the crafting inventory. + * @return true if the recipe is an alternate recipe for the compass. + */ + public boolean isValidCompassRecipe(final ItemStack[] matrix) { + if (matrix.length <= 5) { + return false; // Small crafting grid + } + + + // 0: is it fully filled? + + for (int i = 0; i < 9; i++) { + if (matrix[i] == null) { + return false; + } + } + + + // 1: check of the static part (central ingredient + iron) + + final Material iron1 = matrix[1].getType(); + final Material iron2 = matrix[3].getType(); + final Material iron3 = matrix[5].getType(); + final Material iron4 = matrix[7].getType(); + final Material centralIngredient = matrix[4].getType(); + + if (!(iron1.equals(Material.IRON_INGOT) + && iron2.equals(Material.IRON_INGOT) + && iron3.equals(Material.IRON_INGOT) + && iron4.equals(Material.IRON_INGOT) + && centralIngredient.equals(getCentralIngredient()))) { + return false; + } + + + // 2: check of the dynamic part (loots) + + final ArrayList<Material> corners = new ArrayList<>(); + corners.add(matrix[0].getType()); + corners.add(matrix[2].getType()); + corners.add(matrix[6].getType()); + corners.add(matrix[8].getType()); + + return corners.contains(Material.BONE) + && corners.contains(Material.ROTTEN_FLESH) + && corners.contains(Material.SPIDER_EYE) + && corners.contains(Material.GUNPOWDER); + } + + private Material getCentralIngredient() { + switch (Config.RECIPE.get()) { + case MEDIUM: + return Material.ENDER_PEARL; + + case HARD: + return Material.ENDER_EYE; + + default: + return Material.REDSTONE; + } + } + + @EventHandler(ignoreCancelled = true) + public void onInventoryClick(final InventoryClickEvent ev) { + if (Config.RECIPE.get() == CompassRecipe.DEFAULT) { + return; + } + + if (ev.getWhoClicked() instanceof Player) { + final Inventory inventory = ev.getInventory(); + + // Workaround to fix the crafting grid being not updated when the item is taken + // from the grid. + if (inventory instanceof CraftingInventory && ev.getSlotType() == InventoryType.SlotType.RESULT) { + RunTask.later( + () -> ev.getViewers().stream() + .filter(viewer -> viewer instanceof Player) + .forEach(viewer -> ((Player) viewer).updateInventory()), + 1L + ); + } + + + /* *** Allows any shape for the loots in the compass recipe. *** */ + + if (inventory instanceof CraftingInventory) { + // This is ran one tick after the click because when the event is fired, the inventory + // object is not updated, and so the result of the isValidCompassResult is invalid. + + RunTask.later(() -> + { + if (isValidCompassRecipe(((CraftingInventory) inventory).getMatrix())) { + // Puts the compass in the result slot + if (ev.getSlotType() == InventoryType.SlotType.CRAFTING) { + ((CraftingInventory) inventory).setResult(new ItemStack(Material.COMPASS)); + ev.setResult(Event.Result.ALLOW); + + ((Player) ev.getWhoClicked()).updateInventory(); // deprecated but needed + } + + // Consumes the materials in the crafting grid. + // Because this is not an "official" recipe, we need to do that manually. + else if (ev.getSlotType() == InventoryType.SlotType.RESULT) { + int index = 1; + for (ItemStack stack : ((CraftingInventory) inventory).getMatrix()) { + if (stack == null) { + continue; + } + + if (stack.getAmount() != 1) { + stack.setAmount(stack.getAmount() - 1); + inventory.setItem(index, stack); + } else { + inventory.setItem(index, new ItemStack(Material.AIR)); + } + + index++; + } + + ev.setCurrentItem(new ItemStack(Material.COMPASS)); + ev.setResult(Event.Result.ALLOW); + + ((Player) ev.getWhoClicked()).updateInventory(); // deprecated but needed + } + } + }, 1L); + } + } + } + + @EventHandler(ignoreCancelled = true) + public void onInventoryDrag(final InventoryDragEvent ev) { + if (Config.RECIPE.get() == CompassRecipe.DEFAULT) { + return; + } + + if (ev.getInventory() instanceof CraftingInventory) { + RunTask.later(() -> + { + if (isValidCompassRecipe(((CraftingInventory) ev.getInventory()).getMatrix())) { + ((CraftingInventory) ev.getInventory()).setResult(new ItemStack(Material.COMPASS)); + ((Player) ev.getWhoClicked()).updateInventory(); // deprecated but needed + } + }, 1L); + } + } + + @EventHandler + private void onPreCraft(final PrepareItemCraftEvent ev) { + if (Config.RECIPE.get() != CompassRecipe.DEFAULT && RecipesUtils.areSimilar(ev.getRecipe(), VANILLA_RECIPE)) { + ev.getInventory().setResult(new ItemStack(Material.AIR)); + } + } + + public enum CompassRecipe { + /** + * The default recipe with redstone and iron. + */ + DEFAULT, + + /** + * The same recipe as the default, but with the four main mobs loots + * in the corners: one string, one spider eye, one gun powder and + * one zombie flesh. + */ + EASY, + + /** + * The same recipe as the easy one, but with an ender pearl instead + * of the redstone at the center. + */ + MEDIUM, + + /** + * The same recipe as the medium one, but wyth an eye of ender instead + * of the ender pearl. + */ + HARD + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/compass/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/compass/Config.java new file mode 100644 index 0000000..eb6bf84 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/compass/Config.java @@ -0,0 +1,56 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.compass; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; +import org.bukkit.Material; + +public class Config extends ConfigurationInstance { + public final static ConfigurationItem<CompassRecipes.CompassRecipe> RECIPE = + item("recipe", CompassRecipes.CompassRecipe.EASY); + public final static ConfigurationItem<Material> COMPASS_FEE_ITEM = item("compass-fee-item", Material.ROTTEN_FLESH); + public final static ConfigurationItem<Integer> COMPASS_FEE_AMOUNT = item("compass-fee-amount", 1); + public final static ConfigurationItem<Boolean> NEVER_TARGET_TEAMMATES = item("never-target-teammates", true); + public final static ConfigurationItem<CompassModule.CompassBehavior> COMPASS_BEHAVIOR = + item("compass-behavior", CompassModule.CompassBehavior.GIVE_DIRECTION); + + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/daylightCycle/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/daylightCycle/Config.java new file mode 100644 index 0000000..06df84f --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/daylightCycle/Config.java @@ -0,0 +1,53 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.daylightCycle; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + +public class Config extends ConfigurationInstance { + static public final ConfigurationItem<Boolean> ENABLE_DAYLIGHT_CYCLE = item("enable-daylight-cycle", true); + static public final ConfigurationItem<TimeDelta> DAYLIGHT_CYCLE_DURATION = + item("daylight-cycle-duration", new TimeDelta(0, 20, 0)); + static public final ConfigurationItem<Long> WAITING_PHASE_HOUR = item("waiting-phase-hour", 6000L); + static public final ConfigurationItem<Long> INITIAL_GAME_HOUR = item("initial-game-hour", 0L); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/daylightCycle/DaylightCycleModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/daylightCycle/DaylightCycleModule.java new file mode 100644 index 0000000..6ab0aa6 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/daylightCycle/DaylightCycleModule.java @@ -0,0 +1,135 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.daylightCycle; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import java.util.concurrent.atomic.AtomicLong; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.event.EventHandler; +import org.bukkit.scheduler.BukkitTask; + + +@ModuleInfo( + name = "Daylight Cycle", + description = "Configures the daylight cycle (disabled, slowed down, normal, accelerated) and the initial time.", + category = ModuleCategory.GAMEPLAY, + icon = Material.CLOCK, + settings = Config.class +) +public class DaylightCycleModule extends QSGModule { + // Here are the Magic Values™. + private final static long TICKS_IN_ONE_DAYLIGHT_CYCLE = 24000L; + private final static TimeDelta NORMAL_DAYLIGHT_CYCLE_DURATION = new TimeDelta(0, 20, 0); + + private BukkitTask daylightCycleTask = null; + + + @Override + protected void onEnable() { + QSG.get().getWorlds().forEach(world -> { + world.setFullTime(Config.WAITING_PHASE_HOUR.get()); + world.setGameRuleValue("doDaylightCycle", Boolean.FALSE.toString()); + }); + } + + @Override + public void onLateEnable() { + if (QSG.module(GameModule.class).currentPhaseAfter(GamePhase.STARTING)) { + initDayLightCycle(QSG.get().getWorld(World.Environment.NORMAL).getFullTime()); + } + } + + @Override + protected void onDisable() { + if (daylightCycleTask != null) { + daylightCycleTask.cancel(); + daylightCycleTask = null; + } + } + + @EventHandler + public void onGameStart(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() == GamePhase.IN_GAME && ev.isRunningForward()) { + initDayLightCycle(Config.INITIAL_GAME_HOUR.get()); + } + } + + private void initDayLightCycle(final long initialTime) { + final World world = QSG.get().getWorld(World.Environment.NORMAL); + + world.setFullTime(Config.INITIAL_GAME_HOUR.get()); + world.setGameRuleValue("doDaylightCycle", Config.ENABLE_DAYLIGHT_CYCLE.get().toString()); + + // If the day cycle duration needs to be altered + if (!Config.DAYLIGHT_CYCLE_DURATION.get().equals(NORMAL_DAYLIGHT_CYCLE_DURATION)) { + // We disable the automatic cycle to avoid the sun and the moon to boggle on the clients + world.setGameRuleValue("doDaylightCycle", Boolean.FALSE.toString()); + + final long ticksPerDay = Config.DAYLIGHT_CYCLE_DURATION.get().getSeconds() * 20L; + + // For days slower than Minecraft days, it is not required to update every tick, as the daytime + // will be the same for multiple updates. + final long updateInterval = (long) Math.max(1L, (ticksPerDay * 1.0f) / TICKS_IN_ONE_DAYLIGHT_CYCLE); + + final AtomicLong tick = new AtomicLong(initialTime % TICKS_IN_ONE_DAYLIGHT_CYCLE); + if (tick.get() < 0L) { + tick.addAndGet(TICKS_IN_ONE_DAYLIGHT_CYCLE); + } + + daylightCycleTask = RunTask.timer(() -> { + // We keep the current tick in one daylight cycle. + if (tick.addAndGet(updateInterval) >= ticksPerDay) { + tick.set(0L); + } + + // On each tick, we calculate the time of day we should be at this point. + final long convertedTick = + (long) Math.floor((tick.floatValue() / ticksPerDay) * TICKS_IN_ONE_DAYLIGHT_CYCLE); + + // We update the main world. + world.setTime(convertedTick); + }, updateInterval, updateInterval); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/goldenHeads/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/goldenHeads/Config.java new file mode 100644 index 0000000..4e42358 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/goldenHeads/Config.java @@ -0,0 +1,83 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.goldenHeads; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.section; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.configuration.ConfigurationSection; +import java.io.File; + +public class Config extends ConfigurationInstance { + public static final ConfigurationItem<Boolean> DROP_HEAD_ON_DEATH = item("drop-head-on-death", true); + public static final ConfigurationItem<Boolean> DROP_HEAD_ON_DEATH_PVP_ONLY = + item("drop-head-on-death-pvp-only", false); + public static final ConfigurationItem<Boolean> DISPLAY_REGEN_AMOUNT_ON_APPLES = + item("display-regen-amount-on-apples", true); + public static final GoldenAppleSection GOLDEN_APPLE = section("golden-apple", GoldenAppleSection.class); + public static final EnchantedGoldenAppleSection ENCHANTED_GOLDEN_APPLE = + section("enchanted-golden-apple", EnchantedGoldenAppleSection.class); + public static final GoldenHeadSection PLAYER_GOLDEN_HEAD = section("player-golden-head", GoldenHeadSection.class); + public static final GoldenHeadSection WITHER_GOLDEN_HEAD = section("wither-golden-head", GoldenHeadSection.class); + public static final EnchantedGoldenHeadSection PLAYER_ENCHANTED_GOLDEN_HEAD = + section("player-enchanted-golden-head", EnchantedGoldenHeadSection.class); + public static final EnchantedGoldenHeadSection WITHER_ENCHANTED_GOLDEN_HEAD = + section("wither-enchanted-golden-head", EnchantedGoldenHeadSection.class); + public Config(File file) { + super(file); + } + + public static class GoldenAppleSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ENABLE = item("enable", true); + public final ConfigurationItem<Integer> REGENERATION = item("regeneration", 4); + } + + public static class EnchantedGoldenAppleSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ENABLE = item("enable", false); + public final ConfigurationItem<Integer> REGENERATION = item("regeneration", 180); + } + + public static class GoldenHeadSection extends GoldenAppleSection { + public final ConfigurationItem<Integer> AMOUNT_CRAFTED = item("amount-crafted", 1); + public final ConfigurationItem<Boolean> ADD_LORE = item("add-lore", true); + } + + public static class EnchantedGoldenHeadSection extends EnchantedGoldenAppleSection { + public final ConfigurationItem<Integer> AMOUNT_CRAFTED = item("amount-crafted", 1); + public final ConfigurationItem<Boolean> ADD_LORE = item("add-lore", true); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/goldenHeads/GoldenHeadsModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/goldenHeads/GoldenHeadsModule.java new file mode 100644 index 0000000..2ba1a95 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/goldenHeads/GoldenHeadsModule.java @@ -0,0 +1,380 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.goldenHeads; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import fr.zcraft.quartzlib.components.attributes.Attribute; +import fr.zcraft.quartzlib.components.attributes.Attributes; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.items.CraftingRecipes; +import fr.zcraft.quartzlib.tools.items.ItemStackBuilder; +import fr.zcraft.quartzlib.tools.items.ItemUtils; +import fr.zcraft.quartzlib.tools.reflection.NMSException; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import java.util.UUID; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.SkullType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.inventory.PrepareItemCraftEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + + +@ModuleInfo( + name = "Golden Apple & Heads", + description = "Changes golden apple behavior. This can change the regeneration from these apple, " + + "and allow players to craft “golden heads” from fallen heads when they kill a player. You can " + + "also enable or disable enchanted golden apples (aka “Notch Apples”).", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.GAMEPLAY, + icon = Material.GOLDEN_APPLE, // TODO 1.13: enchanted golden apple or player head + settings = Config.class +) +public class GoldenHeadsModule extends QSGModule { + private final static UUID HEADS_UUID = UUID.fromString("1a050e3b-6274-434e-b8c0-a720048142e7"); + private final static int TICKS_BETWEEN_EACH_REGENERATION = 50; + private final static int DEFAULT_NUMBER_OF_HEARTS_REGEN = 4; + private final static int DEFAULT_NUMBER_OF_HEARTS_REGEN_NOTCH = 180; + private final static int REGENERATION_LEVEL_GOLDEN_APPLE = 2; + private final static int REGENERATION_LEVEL_NOTCH_GOLDEN_APPLE = 5; + private final String HEART = "\u2764"; + private final String HALF = "\u00bd"; + + @Override + protected void onEnable() { + if (Config.ENCHANTED_GOLDEN_APPLE.ENABLE.get()) { + Bukkit.addRecipe(getOldEnchantedGoldenAppleRecipe()); + } + + if (Config.PLAYER_GOLDEN_HEAD.ENABLE.get()) { + Bukkit.addRecipe(getGoldenHeadRecipe("golden_player_head", true, false, Config.PLAYER_GOLDEN_HEAD.AMOUNT_CRAFTED.get(), + ChatColor.AQUA + I.t("Golden head"))); + } + + if (Config.PLAYER_ENCHANTED_GOLDEN_HEAD.ENABLE.get()) { + Bukkit.addRecipe(getGoldenHeadRecipe("enchanted_golden_player_head", true, true, Config.PLAYER_ENCHANTED_GOLDEN_HEAD.AMOUNT_CRAFTED.get(), + ChatColor.LIGHT_PURPLE + I.t("Golden head"))); + } + + if (Config.WITHER_GOLDEN_HEAD.ENABLE.get()) { + Bukkit.addRecipe(getGoldenHeadRecipe("golden_wither_head", false, false, Config.WITHER_GOLDEN_HEAD.AMOUNT_CRAFTED.get(), + ChatColor.AQUA + I.t("Golden head"))); + } + + if (Config.WITHER_ENCHANTED_GOLDEN_HEAD.ENABLE.get()) { + Bukkit.addRecipe(getGoldenHeadRecipe("enchanted_golden_wither_head", false, true, Config.WITHER_ENCHANTED_GOLDEN_HEAD.AMOUNT_CRAFTED.get(), + ChatColor.LIGHT_PURPLE + I.t("Golden head"))); + } + } + + private Recipe getGoldenHeadRecipe(String recipeName, final boolean player, final boolean enchanted, + final int amount, + final String resultDisplayName) { + final ItemStack goldenApple = new ItemStackBuilder(enchanted ? Material.ENCHANTED_GOLDEN_APPLE : Material.GOLDEN_APPLE) + .title(ChatColor.RESET + resultDisplayName) + .amount(amount) + .craftItem(); // Required to write attributes by reference + + writeHeadType(goldenApple, player ? SkullType.PLAYER : SkullType.WITHER); + + return CraftingRecipes.shaped( + recipeName, goldenApple, + "AAA", "ABA", "AAA", + enchanted ? Material.GOLD_BLOCK : Material.GOLD_INGOT, + player ? Material.PLAYER_HEAD : Material.WITHER_SKELETON_SKULL + ); + } + + private Recipe getOldEnchantedGoldenAppleRecipe() { + return CraftingRecipes.shaped( + "enchanted_golden_apple_old_vanilla", + new ItemStack(Material.ENCHANTED_GOLDEN_APPLE), + "AAA", "ABA", "AAA", + Material.GOLD_BLOCK, Material.APPLE + ); + } + + private void writeHeadType(final ItemStack stack, final SkullType type) { + final Attribute attribute = new Attribute(); + attribute.setUUID(HEADS_UUID); + attribute.setCustomData(type.name()); + + try { + Attributes.set(stack, attribute); + } + catch (NMSException e) { + PluginLogger.error("Unable to write head type into item stack.", e); + } + } + + /** + * From a golden apple, reads the head type written in it, so you can know + * if it's a regular golden apple, a Wither golden head or a Player golden + * head. + * <p> + * TODO replace SkullType with Material + * + * @param stack The ItemStack to analyze. + * @return Either {@link SkullType#PLAYER} (Player golden head), + * {@link SkullType#WITHER} (Wither golden head) or {@code null} (regular + * golden apple). + */ + public SkullType readHeadType(final ItemStack stack) { + try { + final Attribute attribute = Attributes.get(stack, HEADS_UUID); + + if (attribute != null) { + return SkullType.valueOf(attribute.getCustomData()); + } else { + return null; + } + } + catch (NMSException | IllegalArgumentException e) { + return null; + } + } + + @EventHandler + public void onPreCraft(final PrepareItemCraftEvent ev) { + /* *** We remove these recipes if disabled *** */ + + final ItemStack result = ev.getInventory().getResult(); + if (result == null || + (result.getType() != Material.GOLDEN_APPLE && result.getType() != Material.ENCHANTED_GOLDEN_APPLE)) { + return; + } + + final boolean isEnchanted = result.getType() == Material.ENCHANTED_GOLDEN_APPLE; + + if ((!Config.GOLDEN_APPLE.ENABLE.get() && result.getType() == Material.GOLDEN_APPLE && !isEnchanted) + || (!Config.ENCHANTED_GOLDEN_APPLE.ENABLE.get() && result.getType() == Material.GOLDEN_APPLE && + isEnchanted)) { + result.setType(Material.AIR); + } + + + /* *** We add a lore to the golden apples *** */ + + final SkullType headType = readHeadType(result); + if (headType != null) { + final ItemStackBuilder revampedResult = new ItemStackBuilder(result); + + if (headType == SkullType.WITHER && + ((!isEnchanted && Config.WITHER_GOLDEN_HEAD.ADD_LORE.get()) || + (isEnchanted && Config.WITHER_ENCHANTED_GOLDEN_HEAD.ADD_LORE.get()))) { + revampedResult.longLore(ChatColor.GRAY, + ChatColor.ITALIC + I.t("Made from the fallen head of a malignant monster")); + } else if (headType == SkullType.PLAYER && + ((!isEnchanted && Config.PLAYER_GOLDEN_HEAD.ADD_LORE.get()) || + (isEnchanted && Config.PLAYER_ENCHANTED_GOLDEN_HEAD.ADD_LORE.get()))) { + // We retrieve the player name to write it into the lore + String name = null; + + for (final ItemStack item : ev.getInventory().getContents()) { + // An human head + if (item.getType() == Material.PLAYER_HEAD) { + SkullMeta sm = (SkullMeta) item.getItemMeta(); + if (sm.hasOwner()) // An human head + { + name = sm.getOwningPlayer() != null ? sm.getOwningPlayer().getName() : null; + } + break; + } + } + + if (name != null) { + revampedResult + .longLore(ChatColor.GRAY, ChatColor.ITALIC + I.t("Made from the fallen head of {0}", name)); + } else { + revampedResult.longLore(ChatColor.GRAY, + ChatColor.ITALIC + I.t("Made from the fallen head of a powerful opponent")); + } + } + + revampedResult.hideAllAttributes().item(); + } + + + /* *** We add the regeneration amount on all apples, if non-vanilla *** */ + + if (Config.DISPLAY_REGEN_AMOUNT_ON_APPLES.get()) { + final int halfHearts = getRegenerationFor(headType, isEnchanted); + if (halfHearts != 0 && ((!isEnchanted && halfHearts != DEFAULT_NUMBER_OF_HEARTS_REGEN) || + (isEnchanted && halfHearts != DEFAULT_NUMBER_OF_HEARTS_REGEN_NOTCH))) { + final int hearts = halfHearts / 2; + final boolean plusHalf = halfHearts % 2 != 0; + + final String heartsSymbol; + + if (hearts <= 10) { + heartsSymbol = ChatColor.RED + StringUtils.repeat(HEART, hearts) + + (plusHalf ? ChatColor.GRAY + " + " + HALF : ""); + } else { + heartsSymbol = + ChatColor.RED + HEART + ChatColor.GRAY + " × " + hearts + (plusHalf ? " + " + HALF : ""); + } + + final ItemStackBuilder revampedResult = new ItemStackBuilder(result); + if (headType != null) { + revampedResult.loreSeparator(); + } + + revampedResult.loreLine(ChatColor.GRAY, I.t("Regenerates {0}", heartsSymbol)).item(); + } + } + } + + @EventHandler + public void onPlayerDeath(final AlivePlayerDeathEvent ev) { + if (Config.DROP_HEAD_ON_DEATH.get() && ev.getPlayer().isOnline() && + (!Config.DROP_HEAD_ON_DEATH_PVP_ONLY.get() || ev.getPlayer().getPlayer().getKiller() != null)) { + final ItemStackBuilder head = new ItemStackBuilder(Material.PLAYER_HEAD) + .title(ChatColor.AQUA, I.t("{0}'s head", ev.getPlayer().getName())) + .withMeta((SkullMeta meta) -> meta.setOwningPlayer(ev.getPlayer())); + + if (Config.PLAYER_GOLDEN_HEAD.ENABLE.get() || Config.PLAYER_ENCHANTED_GOLDEN_HEAD.ENABLE.get()) { + head.longLore(ChatColor.GRAY, ChatColor.ITALIC + + I.t("Old legends tell how the heads of the brave fallen warriors can become, through a rich and complex transformation, a precious healing balm..."), + 38); + } + + ItemUtils.dropNaturally(ev.getPlayer().getPlayer().getLocation(), head.item()); + } + } + + + /** + * Used to change the amount of regenerated hearts from a golden apple. + */ + @EventHandler + public void onPlayerItemConsume(final PlayerItemConsumeEvent ev) { + if (ev.getItem().getType() == Material.GOLDEN_APPLE || + ev.getItem().getType() == Material.ENCHANTED_GOLDEN_APPLE) { + final SkullType headType = readHeadType(ev.getItem()); + final boolean isEnchanted = ev.getItem().getType() == Material.ENCHANTED_GOLDEN_APPLE; + + final int halfHearts = getRegenerationFor(headType, isEnchanted); + final int level = isEnchanted ? REGENERATION_LEVEL_NOTCH_GOLDEN_APPLE : REGENERATION_LEVEL_GOLDEN_APPLE; + + + // Technically, a level-I effect is « level 0 ». + final int realLevel = level - 1; + + + // What is needed to do? + if ((!isEnchanted && halfHearts == DEFAULT_NUMBER_OF_HEARTS_REGEN) + || (isEnchanted && halfHearts == DEFAULT_NUMBER_OF_HEARTS_REGEN_NOTCH)) { + // Default behavior, nothing to do. + return; + } + + if ((!isEnchanted && halfHearts > DEFAULT_NUMBER_OF_HEARTS_REGEN) + || (isEnchanted && halfHearts > DEFAULT_NUMBER_OF_HEARTS_REGEN_NOTCH)) { + // If the heal needs to be increased, the effect can be applied immediately. + + int duration = + ((int) Math.floor(TICKS_BETWEEN_EACH_REGENERATION / (Math.pow(2, realLevel)))) * halfHearts; + + new PotionEffect(PotionEffectType.REGENERATION, duration, realLevel).apply(ev.getPlayer()); + } else { + // The heal needs to be decreased. + // We can't apply the effect immediately, because the server will just ignore it. + // So, we apply it two ticks later, with one half-heart less (because in two ticks, + // one half-heart is given to the player). + final int healthApplied = halfHearts - 1; + + RunTask.later(() -> + { + // The original, vanilla, effect is removed + ev.getPlayer().removePotionEffect(PotionEffectType.REGENERATION); + + int duration = ((int) Math.floor(TICKS_BETWEEN_EACH_REGENERATION / (Math.pow(2, realLevel)))) * + healthApplied; + new PotionEffect(PotionEffectType.REGENERATION, duration, realLevel).apply(ev.getPlayer()); + }, 2L); + } + } + } + + /** + * Returns the amount of regeneration we should apply for a given apple. + * + * @param headType The apple type ({@code null} meaning standard apple; else, {@link SkullType#WITHER} or {@link SkullType#PLAYER}). + * @param isEnchanted True if this is an enchanted golden apple (aka Notch Apple). + * @return The amount of regeneration, or 0 if invalid (i.e. bad skull type). + */ + private int getRegenerationFor(final SkullType headType, final boolean isEnchanted) { + // Standard golden apple + if (headType == null) { + if (!isEnchanted) // FIXME 1.13 + { + return Config.GOLDEN_APPLE.REGENERATION.get(); + } else { + return Config.ENCHANTED_GOLDEN_APPLE.REGENERATION.get(); + } + } else if (headType == SkullType.PLAYER) { + if (!isEnchanted) // FIXME 1.13 + { + return Config.PLAYER_GOLDEN_HEAD.REGENERATION.get(); + } else { + return Config.PLAYER_ENCHANTED_GOLDEN_HEAD.REGENERATION.get(); + } + } else if (headType == SkullType.WITHER) { + if (!isEnchanted) // FIXME 1.13 + { + return Config.WITHER_GOLDEN_HEAD.REGENERATION.get(); + } else { + return Config.WITHER_ENCHANTED_GOLDEN_HEAD.REGENERATION.get(); + } + } + + // Invalid attribute. Should never happen. + else { + return 0; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/hardcore/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/hardcore/Config.java new file mode 100644 index 0000000..c55660c --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/hardcore/Config.java @@ -0,0 +1,50 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.hardcore; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; +import org.bukkit.Difficulty; + +public class Config extends ConfigurationInstance { + static public final ConfigurationItem<Boolean> NATURAL_REGENERATION = item("natural-regeneration", false); + static public final ConfigurationItem<Difficulty> DIFFICULTY = item("difficulty", Difficulty.HARD); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/hardcore/HardcoreModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/hardcore/HardcoreModule.java new file mode 100644 index 0000000..b7e7a22 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/hardcore/HardcoreModule.java @@ -0,0 +1,80 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.hardcore; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import java.util.HashMap; +import java.util.Map; +import org.bukkit.Difficulty; +import org.bukkit.Material; + + +@ModuleInfo( + name = "Hardcore Mode", + description = "Disables health natural regeneration and sets correct difficulty in the game's worlds.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.GAMEPLAY, + icon = Material.GOLDEN_APPLE, + settings = Config.class +) +public class HardcoreModule extends QSGModule { + private final Map<String, Difficulty> oldDifficulties = new HashMap<>(); + private final Map<String, String> oldNaturalRegenerations = new HashMap<>(); + + @Override + protected void onEnable() { + QSG.get().getWorlds().forEach(world -> + { + oldDifficulties.put(world.getName(), world.getDifficulty()); + oldNaturalRegenerations.put(world.getName(), world.getGameRuleValue("naturalRegeneration")); + + world.setDifficulty(Config.DIFFICULTY.get()); + world.setGameRuleValue("naturalRegeneration", Config.NATURAL_REGENERATION.get().toString()); + }); + } + + @Override + protected void onDisable() { + QSG.get().getWorlds().forEach(world -> { + world.setDifficulty(oldDifficulties.getOrDefault(world.getName(), Difficulty.NORMAL)); + world.setGameRuleValue("naturalRegeneration", + oldNaturalRegenerations.getOrDefault(world.getName(), "true")); + }); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/killerRabbit/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/killerRabbit/Config.java new file mode 100644 index 0000000..c760eca --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/killerRabbit/Config.java @@ -0,0 +1,49 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.killerRabbit; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + +public class Config extends ConfigurationInstance { + public static final ConfigurationItem<Double> SPAWN_PROBABILITY = item("spawn-probability", 0.05); + public static final ConfigurationItem<String> NAME = item("name", "The Killer Rabbit of Cærbannog"); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/killerRabbit/KillerRabbitModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/killerRabbit/KillerRabbitModule.java new file mode 100644 index 0000000..8f4f2de --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/killerRabbit/KillerRabbitModule.java @@ -0,0 +1,79 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.killerRabbit; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import java.util.Random; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Rabbit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.CreatureSpawnEvent; + + +@ModuleInfo( + name = "Killer Rabbit", + description = "Brings back the Killer Rabbit of Cærbannog into the game. Beware, it bites.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.GAMEPLAY, + icon = Material.RABBIT_FOOT, + settings = Config.class +) +public class KillerRabbitModule extends QSGModule { + private final Random random = new Random(); + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onRabbitSpawn(final CreatureSpawnEvent ev) { + if (ev.getEntity().getType() != EntityType.RABBIT) { + return; + } + + if (random.nextDouble() >= Config.SPAWN_PROBABILITY.get()) { + return; + } + + final Rabbit rabbit = (Rabbit) ev.getEntity(); + rabbit.setRabbitType(Rabbit.Type.THE_KILLER_BUNNY); + + if (!Config.NAME.get().isEmpty()) { + rabbit.setCustomName(Config.NAME.get()); + rabbit.setCustomNameVisible(true); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/moarApples/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/moarApples/Config.java new file mode 100644 index 0000000..14a648a --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/moarApples/Config.java @@ -0,0 +1,48 @@ +/* + * Plugin UHCReloaded + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.moarApples; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + +public class Config extends ConfigurationInstance { + static public final ConfigurationItem<Double> REPLACEMENT_PERCENTAGE = item("replacement-percentage", 0.12); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/moarApples/MoarApplesModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/moarApples/MoarApplesModule.java new file mode 100644 index 0000000..3937e2e --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/moarApples/MoarApplesModule.java @@ -0,0 +1,78 @@ +/* + * Plugin UHCReloaded + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.moarApples; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import java.util.Random; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.ItemSpawnEvent; +import org.bukkit.inventory.ItemStack; + + +@ModuleInfo( + name = "Moar Apples", + description = "Increases apples rate spawn", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.GAMEPLAY, + icon = Material.APPLE, + settings = Config.class +) +public class MoarApplesModule extends QSGModule { + private final Random random = new Random(); + + /** + * We replace a configurable percentage of saplings with apples. + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onSaplingSpawn(final ItemSpawnEvent ev) { + if (ev.getEntityType() != EntityType.DROPPED_ITEM) + return; + + if (ev.getEntity().hasMetadata("playerDrop")) + return; + + if (ev.getEntity().getItemStack().getType() == Material.OAK_SAPLING || ev.getEntity().getItemStack().getType() == Material.DARK_OAK_SAPLING) { + if (random.nextDouble() < Config.REPLACEMENT_PERCENTAGE.get()) { + ev.getEntity().setItemStack(new ItemStack(Material.APPLE, ev.getEntity().getItemStack().getAmount())); + } + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/noWitches/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/noWitches/Config.java new file mode 100644 index 0000000..b0f3ac6 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/noWitches/Config.java @@ -0,0 +1,49 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.noWitches; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + +public class Config extends ConfigurationInstance { + public static final ConfigurationItem<Boolean> DISABLE_NATURAL_SPAWN = item("disable-natural-spawn", true); + public static final ConfigurationItem<Boolean> DISABLE_LIGHTNING_SPAWN = item("disable-lightning-spawn", true); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/noWitches/NoWitchesModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/noWitches/NoWitchesModule.java new file mode 100644 index 0000000..265bf24 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/noWitches/NoWitchesModule.java @@ -0,0 +1,68 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.noWitches; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; + +@ModuleInfo( + name = "No Witches", + description = "Prevents witches from spawning, either naturally, from lightning strike on a villager, or both.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.GAMEPLAY, + icon = Material.POTION, + settings = Config.class +) +public class NoWitchesModule extends QSGModule { + @EventHandler + public void onCreatureSpawn(CreatureSpawnEvent ev) { + if (ev.getEntityType().equals(EntityType.WITCH)) { + if (Config.DISABLE_NATURAL_SPAWN.get() && ev.getSpawnReason().equals(SpawnReason.NATURAL)) { + ev.setCancelled(true); + } + + if (Config.DISABLE_LIGHTNING_SPAWN.get() && ev.getSpawnReason().equals(SpawnReason.LIGHTNING)) { + ev.setCancelled(true); + } + } + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/task/CancelBrewTask.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/potions/CancelBrewTask.java similarity index 52% rename from src/main/java/eu/carrade/amaury/UHCReloaded/task/CancelBrewTask.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/potions/CancelBrewTask.java index 0d174c5..2b77244 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/task/CancelBrewTask.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/potions/CancelBrewTask.java @@ -30,8 +30,11 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.task; +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.potions; +import fr.zcraft.quartzlib.tools.items.ItemUtils; +import java.util.HashSet; +import java.util.Set; import org.bukkit.Material; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; @@ -40,69 +43,55 @@ import org.bukkit.scheduler.BukkitRunnable; -public class CancelBrewTask extends BukkitRunnable -{ +public class CancelBrewTask extends BukkitRunnable { private final BrewerInventory inventory; private final HumanEntity whoClicked; - public CancelBrewTask(BrewerInventory inventory, HumanEntity whoClicked) - { + public CancelBrewTask(BrewerInventory inventory, HumanEntity whoClicked) { this.inventory = inventory; this.whoClicked = whoClicked; } @Override - public void run() - { - if (inventory.getIngredient() == null) - { + public void run() { + if (inventory.getIngredient() == null) { return; // Nothing to do! } - if (whoClicked instanceof Player) - { - ItemStack ingredient = inventory.getIngredient(); + if (whoClicked instanceof Player) { + final ItemStack ingredient = inventory.getIngredient(); - if (ingredient.getType() != null && ingredient.getType().equals(Material.GLOWSTONE_DUST)) - { - inventory.setIngredient(new ItemStack(Material.AIR)); // The glowstone is removed. + final Set<Material> forbiddenIngredients = new HashSet<>(); - // First try: try to add the glowstone to an existing stack - boolean added = false; - for (ItemStack item : whoClicked.getInventory().getContents()) - { - if (item != null && item.getType() != null && item.getType().equals(Material.GLOWSTONE_DUST)) - { - if (item.getAmount() + ingredient.getAmount() <= item.getMaxStackSize()) - { - // We can add the glowstone here. - item.setAmount(item.getAmount() + ingredient.getAmount()); - added = true; - break; - } - } + if (Config.DISABLE_EXTENDED.get()) { + forbiddenIngredients.add(Material.REDSTONE); + } + if (Config.DISABLE_LEVEL_II.get()) { + forbiddenIngredients.add(Material.GLOWSTONE_DUST); + } + if (Config.DISABLE_SPLASH.get()) { + forbiddenIngredients.add(Material.GUNPOWDER); + } + if (Config.DISABLE_LINGERING.get()) { + // 1.9 - 1.12 + try { + forbiddenIngredients.add(Material.valueOf("DRAGONS_BREATH")); + } + catch (IllegalArgumentException ignored) { } - // Failed... We adds the glowstone to the first empty slot found. - if (!added) - { - int slotEmpty = whoClicked.getInventory().firstEmpty(); - - // -1 is returned if there isn't any empty slot - if (slotEmpty != -1) - { - whoClicked.getInventory().setItem(slotEmpty, ingredient); - } - - // Failed again (!). Maybe an item captured between the click and this execution. - // The stack is dropped at the player's location. - else - { - whoClicked.getWorld().dropItem(whoClicked.getLocation(), ingredient); - } + // 1.13+ + try { + forbiddenIngredients.add(Material.valueOf("DRAGON_BREATH")); } + catch (IllegalArgumentException ignored) { + } + } - ((Player) whoClicked).updateInventory(); + if (ingredient.getType() != null && forbiddenIngredients.contains(ingredient.getType())) { + // The element is removed and added back to the player's inventory. + inventory.setIngredient(new ItemStack(Material.AIR)); + ItemUtils.give((Player) whoClicked, ingredient); } } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/potions/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/potions/Config.java new file mode 100644 index 0000000..9cb35d6 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/potions/Config.java @@ -0,0 +1,51 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.potions; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + +public class Config extends ConfigurationInstance { + final static public ConfigurationItem<Boolean> DISABLE_LEVEL_II = item("disable-level-II", true); + final static public ConfigurationItem<Boolean> DISABLE_EXTENDED = item("disable-extended", false); + final static public ConfigurationItem<Boolean> DISABLE_SPLASH = item("disable-splash", false); + final static public ConfigurationItem<Boolean> DISABLE_LINGERING = item("disable-lingering", false); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/potions/PotionsModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/potions/PotionsModule.java new file mode 100644 index 0000000..ad82ea9 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/potions/PotionsModule.java @@ -0,0 +1,72 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.potions; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.inventory.BrewerInventory; + + +@ModuleInfo( + name = "Potions", + description = "Allows to tweak potions, by disabling level-II, enhanced, " + + "splash or lingering potions.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.GAMEPLAY, + icon = Material.BREWING_STAND, + settings = Config.class +) +public class PotionsModule extends QSGModule { + @EventHandler + public void onInventoryDrag(InventoryDragEvent ev) { + if (ev.getInventory() instanceof BrewerInventory) { + RunTask.later(new CancelBrewTask((BrewerInventory) ev.getInventory(), ev.getWhoClicked()), 1L); + } + } + + @EventHandler + public void onInventoryClick(InventoryClickEvent ev) { + if (ev.getInventory() instanceof BrewerInventory) { + RunTask.later(new CancelBrewTask((BrewerInventory) ev.getInventory(), ev.getWhoClicked()), 1L); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/weather/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/weather/Config.java new file mode 100644 index 0000000..73171ec --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/weather/Config.java @@ -0,0 +1,52 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.weather; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; +import org.bukkit.WeatherType; + +public class Config extends ConfigurationInstance { + static public final ConfigurationItem<Boolean> WEATHER_CYCLE = item("enable-weather-cycle", true); + static public final ConfigurationItem<WeatherType> INITIAL_WEATHER = item("initial-weather", WeatherType.CLEAR); + static public final ConfigurationItem<WeatherType> WAITING_PHASE_WEATHER = + item("waiting-phase-weather", WeatherType.CLEAR); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/weather/WeatherModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/weather/WeatherModule.java new file mode 100644 index 0000000..b5e160f --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/gameplay/weather/WeatherModule.java @@ -0,0 +1,103 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.gameplay.weather; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import java.util.HashSet; +import java.util.Set; +import org.bukkit.Material; +import org.bukkit.WeatherType; +import org.bukkit.World; +import org.bukkit.event.EventHandler; +import org.bukkit.event.weather.WeatherChangeEvent; + + +@ModuleInfo( + name = "Weather", + description = "Manages the in-game weather.", + settings = Config.class, + category = ModuleCategory.GAMEPLAY, + icon = Material.SUNFLOWER +) +public class WeatherModule extends QSGModule { + private final Set<World> firstWeatherUpdateOccurred = new HashSet<>(); + + @Override + protected void onEnable() { + QSG.get().getWorlds() + .forEach(world -> world.setStorm(Config.WAITING_PHASE_WEATHER.get() == WeatherType.DOWNFALL)); + } + + @Override + public void onLateEnable() { + QSG.get().getWorlds().forEach(world -> world.setStorm(Config.INITIAL_WEATHER.get() == WeatherType.DOWNFALL)); + } + + @EventHandler + public void onGameStarts(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() == GamePhase.IN_GAME && ev.isRunningForward()) { + onLateEnable(); + } + } + + @EventHandler + public void onWeatherChange(final WeatherChangeEvent ev) { + switch (QSG.module(GameModule.class).getPhase()) { + case WAIT: + case STARTING: + ev.setCancelled(true); + break; + + case IN_GAME: + case END: + if (!Config.WEATHER_CYCLE.get()) { + // We allow a single weather update, as it will be + // the one from the onGameStart event. + if (firstWeatherUpdateOccurred.contains(ev.getWorld())) { + ev.setCancelled(true); + } else { + firstWeatherUpdateOccurred.add(ev.getWorld()); + } + } + break; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/AdvancementsModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/AdvancementsModule.java new file mode 100644 index 0000000..69085dc --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/AdvancementsModule.java @@ -0,0 +1,124 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.other; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.events.FutureEventHandler; +import fr.zcraft.quartzlib.components.events.WrappedEvent; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.reflection.Reflection; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.command.CommandException; +import org.bukkit.event.EventHandler; + + +@ModuleInfo( + name = "Advancements", + description = "Resets the advancements when the game starts. Disable if " + + "you want to keep old advancements.\n\n" + + "Even if the name corresponds to Minecraft 1.12+, this module " + + "also handles achievements for older Minecraft versions.", + when = ModuleLoadTime.POST_WORLD, + category = ModuleCategory.OTHER, + icon = Material.HAY_BLOCK +) +public class AdvancementsModule extends QSGModule { + @FutureEventHandler(event = "player.PlayerAchievementAwardedEvent", ignoreCancelled = true) + public void onAchievementAwarded(final WrappedEvent ev) { + if (QSG.game().getPhase() == GamePhase.WAIT) { + ev.setCancelled(true); + } + } + + @EventHandler + public void onGameStarts(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() != GamePhase.IN_GAME || !ev.isRunningForward()) { + return; + } + + + // Achievements + + try { + final Object[] achievements = Class.forName("org.bukkit.Achievement").getEnumConstants(); + + QSG.game().getAliveConnectedPlayers().forEach(player -> { + try { + for (final Object achievement : achievements) { + PluginLogger.info("Removing achievement {0}", achievement); + Reflection.call(player, "removeAchievement", achievement); + } + } + catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { + } + }); + } + catch (final Exception ignored) { + } // Unsupported + + + // Advancements + + final Map<String, String> oldGameRule = new HashMap<>(); + QSG.get().getWorlds().forEach(world -> { + oldGameRule.put(world.getName(), world.getGameRuleValue("sendCommandFeedback")); + world.setGameRuleValue("sendCommandFeedback", "false"); + }); + + QSG.game().getAliveConnectedPlayers().forEach(player -> { + try { + // ¯\_(ツ)_/¯ + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), + "advancement revoke " + player.getName() + " everything"); + } + catch (final CommandException ignored) { + } + }); + + QSG.get().getWorlds() + .forEach(world -> world.setGameRuleValue("sendCommandFeedback", oldGameRule.get(world.getName()))); + oldGameRule.clear(); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/PomfModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/PomfModule.java new file mode 100644 index 0000000..ddbd8af --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/PomfModule.java @@ -0,0 +1,62 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.other; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.episodes.Config; +import eu.carrade.amaury.quartzsurvivalgames.modules.cosmetics.episodes.events.EpisodeChangedEvent; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; + +@ModuleInfo( + name = "Pomf", + description = "Pomf au milieu d'un épisode. #parceque", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.OTHER, + icon = Material.SLIME_BLOCK +) +public class PomfModule extends QSGModule { + @EventHandler + public void onEpisodeEnds(final EpisodeChangedEvent ev) { + if (ev.getNewEpisode() == 5) { + RunTask.later(() -> Bukkit.broadcastMessage("- Pomf -"), Config.LENGTH.get().divide(2).getSeconds() * 20L); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/StatisticsModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/StatisticsModule.java new file mode 100644 index 0000000..da65b1d --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/StatisticsModule.java @@ -0,0 +1,103 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.other; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import org.bukkit.Material; +import org.bukkit.Statistic; +import org.bukkit.entity.EntityType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerStatisticIncrementEvent; + + +@ModuleInfo( + name = "Statistics", + description = "If enabled, statistics will not be collected before the game" + + "and will be reset at the beginning of the game. Disable if you want " + + "to keep old statistics!", + when = ModuleLoadTime.POST_WORLD, + category = ModuleCategory.OTHER, + icon = Material.CRAFTING_TABLE +) +public class StatisticsModule extends QSGModule { + @EventHandler + public void onPlayerStatisticIncrement(final PlayerStatisticIncrementEvent ev) { + if (QSG.game().getPhase() == GamePhase.WAIT) { + ev.setCancelled(true); + } + } + + @EventHandler + public void onGameStart(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() == GamePhase.IN_GAME && ev.isRunningForward()) { + QSG.game().getAliveConnectedPlayers().forEach(player -> { + for (final Statistic statistic : Statistic.values()) { + switch (statistic.getType()) { + case UNTYPED: + player.setStatistic(statistic, 0); + break; + + case ITEM: + case BLOCK: + for (final Material material : Material.values()) { + try { + player.setStatistic(statistic, material, 0); + } + catch (final IllegalArgumentException ignored) { + } + } + break; + + case ENTITY: + for (final EntityType entityType : EntityType.values()) { + try { + player.setStatistic(statistic, entityType, 0); + } + catch (final Exception ignored) { + } + } + break; + } + } + }); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/about/AboutCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/about/AboutCommand.java new file mode 100644 index 0000000..070a6b1 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/about/AboutCommand.java @@ -0,0 +1,78 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.other.about; + +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.CommandUtils; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.components.i18n.I18n; + + +@CommandInfo(name = "about") +public class AboutCommand extends Command { + @Override + protected void run() { + final AboutModule about = QSG.module(AboutModule.class); + + CommandUtils.displaySeparator(sender); + + info(I.t("{yellow}{0} - version {1}", about.getPluginName(), about.getVersion()) + " - " + + about.getStability().toString().toLowerCase()); + info(I.t("Plugin made with love by {0}.", about.getFormattedAuthors())); + + if (about.getGitVersion() != null) { + info(I.t("Build number: {0}.", about.getGitVersion())); + } else { + info(I.t("Build number not available.")); + } + + // Translation + + info(""); + info(I.t("{aqua}------ Translations ------")); + info(I.t("Current language: {0} (translated by {1}).", I18n.getPrimaryLocale(), + I18n.getTranslationTeam(I18n.getPrimaryLocale()))); + info(I.t("Fallback language: {0} (translated by {1}).", I18n.getFallbackLocale(), + I18n.getTranslationTeam(I18n.getFallbackLocale()))); + + info(""); + info(I.t("{aqua}------ License ------")); + info(I.t("Published under the CeCILL-B License.")); + + CommandUtils.displaySeparator(sender); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/about/AboutModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/about/AboutModule.java new file mode 100644 index 0000000..4a51b58 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/other/about/AboutModule.java @@ -0,0 +1,222 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.other.about; + +import eu.carrade.amaury.quartzsurvivalgames.QuartzSurvivalGames; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.i18n.I; +import java.io.IOException; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; + + +@ModuleInfo( + name = "About", + description = "Provides information about this plugin.", + category = ModuleCategory.OTHER, + icon = Material.BOOK +) +public class AboutModule extends QSGModule { + private final String shortName = "Quartz Survival Games"; + private String version = null; + private Stability stability = null; + private String gitVersion = null; + private String authors = null; + + @Override + protected void onEnable() { + computeVersion(); + computeGitVersion(); + computeFormattedAuthors(); + } + + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(AboutCommand.class); + } + + @Override + public void injectIntoSidebar(Player player, SidebarInjector injector) { + if (QSG.module(GameModule.class).getPhase() == GamePhase.WAIT) { + injector.injectLines( + SidebarInjector.SidebarPriority.VERY_BOTTOM, + true, false, + ChatColor.GRAY + shortName + " " + version + ); + + if (getVersion() != null) { + injector.injectLines( + SidebarInjector.SidebarPriority.VERY_BOTTOM, + false, + ChatColor.GRAY + gitVersion.substring(0, 8) + ); + } + + if (stability != Stability.STABLE) { + switch (stability) { + case BETA: + injector.injectLines( + SidebarInjector.SidebarPriority.VERY_BOTTOM, + true, + I.t("{yellow}Beta version") + ); + break; + + case ALPHA: + injector.injectLines( + SidebarInjector.SidebarPriority.VERY_BOTTOM, + true, + I.t("{red}Development version") + ); + break; + } + } + } + } + + public String getPluginName() { + return QSG.get().getDescription().getDescription(); + } + + public String getShortPluginName() { + return shortName; + } + + public String getVersion() { + return version; + } + + public Stability getStability() { + return stability; + } + + public String getGitVersion() { + return gitVersion; + } + + public List<String> getAuthors() { + return QSG.get().getDescription().getAuthors(); + } + + public String getFormattedAuthors() { + return authors; + } + + private void computeGitVersion() { + try { + final Class<? extends QuartzSurvivalGames> clazz = QSG.get().getClass(); + final String className = clazz.getSimpleName() + ".class"; + final String classPath = clazz.getResource(className).toString(); + + if (classPath.startsWith("jar")) // Class from JAR + { + final String manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) + + "/META-INF/MANIFEST.MF"; + final Manifest manifest = new Manifest(new URL(manifestPath).openStream()); + final Attributes attr = manifest.getMainAttributes(); + + gitVersion = attr.getValue("Git-Commit"); + } + } + catch (IOException e) { + // Build not available. + } + } + + private void computeFormattedAuthors() { + final StringBuilder authors = new StringBuilder(); + final List<String> listAuthors = getAuthors(); + + for (final String author : listAuthors) { + if (!author.equals(listAuthors.get(0))) { + if (author.equals(listAuthors.get(listAuthors.size() - 1))) { + /// The "and" in the authors list (like "Amaury Carrade, azenet and João Roda") + authors.append(" ").append(I.tc("authors_list", "and")).append(" "); + } else { + authors.append(", "); + } + } + + authors.append(author); + } + + this.authors = authors.toString(); + } + + private void computeVersion() { + final String[] versionParts = QSG.get().getDescription().getVersion().split("-", 2); + + version = versionParts[0]; + + if (versionParts.length >= 2) { + switch (versionParts[1].trim().toLowerCase()) { + case "dev": + case "alpha": + stability = Stability.ALPHA; + break; + + case "beta": + case "bêta": + case "pre": + case "prerelease": + case "pre-release": + stability = Stability.BETA; + break; + + default: + stability = Stability.STABLE; + } + } else { + stability = Stability.STABLE; + } + } + + public enum Stability { + STABLE, BETA, ALPHA + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/AllianceRequest.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/AllianceRequest.java new file mode 100644 index 0000000..0136982 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/AllianceRequest.java @@ -0,0 +1,575 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.external.hawk.HawkModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances.commands.RequestAnswerCommand; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGSound; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.components.rawtext.RawText; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import fr.zcraft.quartzlib.tools.text.RawMessage; +import fr.zcraft.quartzteams.QuartzTeam; +import fr.zcraft.quartzteams.QuartzTeams; +import fr.zcraft.quartzteams.colors.TeamColor; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import me.cassayre.florian.hawk.report.ReportEvent; +import org.apache.commons.lang3.Validate; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +public class AllianceRequest { + private final GameModule game; + private final AlliancesModule alliances; + + private final UUID allianceRequestUUID = UUID.randomUUID(); + + private final UUID requesterID; + private final UUID requestedID; + private final Map<UUID, Boolean> approvalsIDs = new HashMap<>(); + + private final QuartzTeam requesterTeam; + private final QuartzTeam requestedTeam; + + private final RequestError requestError; + + public AllianceRequest(final UUID requesterID, final UUID requestedTo) { + Validate.notNull(requesterID, "The requester must not be null"); + Validate.notNull(requestedTo, "The requested must not be null"); + + game = QSG.module(GameModule.class); + alliances = QSG.module(AlliancesModule.class); + + this.requesterID = requesterID; + this.requestedID = requestedTo; + + this.requesterTeam = QuartzTeams.get().getTeamForPlayer(requesterID); + this.requestedTeam = QuartzTeams.get().getTeamForPlayer(requestedTo); + + final Player requesterPlayer = Bukkit.getPlayer(requesterID); + final Player requestedPlayer = Bukkit.getPlayer(requestedID); + + + // Cases of request incompatibility: + // - not both the requester and the requested are online; + // - the requester is too far from the requested; + // - the requester is out of alliances for the amount requested (the amount being + // the future amount of players in the new alliance); + // - the requested is out of alliances for the amount requested; + // - both the requester and the requested are in an alliance (at least one of them + // must be solo, or have their teammate dead); + // - both the requester and the requested are in the same alliance (obviously); + // - such an alliance would end the game (e.g. if there is two players left, they + // cannot ally). + + // We first check for errors + + if (requestedTeam.equals(requesterTeam)) { + requestError = RequestError.BOTH_IN_THE_SAME_ALLIANCE; + } else if (requesterPlayer == null || !requesterPlayer.isOnline() || requestedPlayer == null || + !requestedPlayer.isOnline()) { + requestError = RequestError.TOO_FAR; + } else if (!requesterPlayer.getWorld().equals(requestedPlayer.getWorld())) { + requestError = RequestError.TOO_FAR; + } else if (requesterPlayer.getLocation().distanceSquared(requestedPlayer.getLocation()) > + Math.pow(Config.MAX_DISTANCE_TO_CREATE_AN_ALLIANCE.get(), 2)) { + requestError = RequestError.TOO_FAR; + } else if (!checkAlliancesLeft(requesterID)) { + requestError = RequestError.REQUESTER_OUT_OF_ALLIANCES; + } else if (!checkAlliancesLeft(requestedTo)) { + requestError = RequestError.REQUESTED_OUT_OF_ALLIANCES; + } else if (alliances.allianceSize(requestedTeam) > 1 && alliances.allianceSize(requesterTeam) > 1) { + requestError = RequestError.BOTH_IN_A_DIFFERENT_ALLIANCE; + } else if (!checkFutureAllianceSize()) { + requestError = RequestError.FUTURE_ALLIANCE_TOO_BIG; + } else if (!checkGameEnd()) { + requestError = RequestError.WOULD_END_THE_GAME; + } else { + requestError = RequestError.OK; + } + + if (requestError != RequestError.OK) { + return; + } + + + // Okay so here we have a valid request. Yay! + + // Possible cases + // - If both are in a solo team, it's a request for a two-players alliance + // - If the requester is in a two-players alliance, an invite is sent to the + // third-party player to join the alliance. + // - If the requester is solo but the requested in a two-players alliance, an + // invite is sent to the requested and the other member of the alliance, to + // be sure everyone is OK. + // - And so on until the maximal amount of players per alliance is reached. + // + // To summarize, the request is sent to: + // - the requested player, of course; + // - if the requester is in an alliance, other players in the alliance; + // - if the requested is in an alliance, other players in that alliance. + + approvalsIDs.put(requestedTo, false); + + if (requesterTeam.size() > 1 || requestedTeam.size() > 1) { + (requestedTeam.size() > 1 ? requestedTeam : requesterTeam) + .getPlayers().stream() + .map(OfflinePlayer::getUniqueId) + .filter(uuid -> !uuid.equals(requesterID)) + .forEach(player -> approvalsIDs.put(player, false)); + } + + // We don't forget to self-register as an ongoing request. + + alliances.registerRequest(this); + } + + /** + * Sends an approval request to the players. + */ + public void sendApprovalRequests() { + checkError(); + + final QSGSound[] jingle = new QSGSound[] { + new QSGSound(1f, 0.8f, "ARROW_HIT_PLAYER", "SUCCESSFUL_HIT"), + new QSGSound(1f, 1.4f, "ARROW_HIT_PLAYER", "SUCCESSFUL_HIT"), + new QSGSound(1f, 1.1f, "ARROW_HIT_PLAYER", "SUCCESSFUL_HIT") + }; + + approvalsIDs.keySet().stream() + .map(Bukkit::getPlayer) + .filter(Objects::nonNull) + .forEach(player -> { + player.sendMessage(""); + + player.sendMessage( + I.t("{green}{bold}{0} would like to join you in an alliance.", getName(requesterID))); + + if (!player.getUniqueId().equals(requestedID)) { + player.sendMessage( + I.t("{gray}This request was sent to {0}, but everyone in the alliance also need to accept.", + getName(requestedID))); + } + + player.sendMessage(""); + + RawMessage.send(player, new RawText(" ") + .then(I.t("{darkgreen}{bold}» {green}{bold}Accept {darkgreen}{bold}«")) + .command(RequestAnswerCommand.class, allianceRequestUUID.toString(), "yes") + .hover(I.t("{green}{bold}Accept {green}this alliance")) + .then(" ") + .then(I.t("{darkred}{bold}» {red}{bold}Decline {darkred}{bold}«")) + .command(RequestAnswerCommand.class, allianceRequestUUID.toString(), "no") + .hover(I.t("{red}{bold}Decline {red}this alliance")) + .build() + ); + + player.sendMessage(""); + + for (int i = 0; i < jingle.length; i++) { + final int index = i; + RunTask.later(() -> jingle[index].play(player), i * 5L); + } + }); + } + + public void registerApproval(final UUID approver, final boolean approval) { + checkError(); + + if (!approvalsIDs.containsKey(approver)) { + throw new IllegalArgumentException("This player was not asked for approval"); + } + + if (!approval) { + denyAndClose(approver); + } else { + approvalsIDs.put(approver, true); + + // Missing approvers for notifications + final int missingApproversCount = (int) approvalsIDs.values().stream().filter(answer -> !answer).count(); + final String missingApprovers = missingApproversCount > 0 + ? " " + I.tn("{gray}Still waiting for {0}'s answer.", "{gray}Still waiting for answers from: {0}.", + missingApproversCount, String.join(", ", + approvalsIDs.keySet().stream().filter(id -> !approvalsIDs.get(id)) + .map(Bukkit::getOfflinePlayer).map(OfflinePlayer::getName) + .collect(Collectors.toSet()))) + : ""; + + // We notify the player who just approved the request. + if (missingApproversCount > 0) { + final Player player = Bukkit.getPlayer(approver); + if (player != null && player.isOnline()) { + final UUID allianceWith; + + if (requesterTeam.containsPlayer(player)) { + allianceWith = requestedID; + } else { + allianceWith = requesterID; + } + + player.sendMessage( + I.t("You accepted the request for an alliance with {0}.", getName(allianceWith))); + } + } + + // If one of the sides is an existing alliance, we notify the players in that + // alliance. + final QuartzTeam notifiedTeam; + final UUID allianceWith; + + if (alliances.allianceSize(requesterTeam) > 1) { + notifiedTeam = requesterTeam; + allianceWith = requestedID; + } else if (alliances.allianceSize(requestedTeam) > 1) { + notifiedTeam = requestedTeam; + allianceWith = requesterID; + } else { + notifiedTeam = null; + allianceWith = null; + } + + if (notifiedTeam != null) { + for (Player player : requesterTeam.getOnlinePlayers()) { + if (game.isAlive(player) && !player.getUniqueId().equals(approver)) { + player.sendMessage(I.t("{green}The request for an alliance with {0} was accepted by {1}.", + getName(allianceWith), getName(approver)) + missingApprovers); + } + } + } + + // If everyone agree + if (approvalsIDs.values().stream().allMatch(answer -> answer)) { + applyApprovedRequest(); + } + } + } + + private void denyAndClose(final UUID closedBy) { + // If one of the players deny the request, it is closed. All players must agree. + // If the request was closed by one of the members of an existing alliance, players + // *of this alliance only* are notified. + + alliances.unregisterRequest(this); + + final QuartzTeam notifiedTeam; + final OfflinePlayer allianceWith; + final OfflinePlayer closer = Bukkit.getOfflinePlayer(closedBy); + + if (alliances.allianceSize(requesterTeam) > 1 && requesterTeam.containsPlayer(closedBy)) { + notifiedTeam = requesterTeam; + allianceWith = Bukkit.getOfflinePlayer(requestedID); + } else if (alliances.allianceSize(requestedTeam) > 1 && requestedTeam.containsPlayer(closedBy)) { + notifiedTeam = requestedTeam; + allianceWith = Bukkit.getOfflinePlayer(requesterID); + } else { + notifiedTeam = null; + allianceWith = null; + } + + if (notifiedTeam != null) { + notifiedTeam.getOnlinePlayers().stream().filter(player -> !player.getUniqueId().equals(closedBy)).forEach( + player -> { + player.sendMessage(""); + player.sendMessage( + I.t("{red}The alliance with {0} was {bold}denied{red} by {1}.", allianceWith.getName(), + closer.getName())); + player.sendMessage(""); + } + ); + } + + if (closer.isOnline()) // Should always be true in normal context + { + closer.getPlayer().sendMessage(I.t("{red}You declined {0}'s alliance request.", getName(requesterID))); + } + } + + private void applyApprovedRequest() { + // In all cases we unregisters this request. + + alliances.unregisterRequest(this); + + + // We first check if we still can approve this request. + + if (!checkAlliancesLeft(requestedID) + || !checkAlliancesLeft(requesterID) + || !checkGameEnd() + || (alliances.allianceSize(requestedTeam) > 1 && alliances.allianceSize(requesterTeam) > 1)) { + QSG.log(AlliancesModule.class) + .warning("The alliance request from {0} to {1} was about to be approved but is now invalid.", + getName(requesterID), getName(requestedID)); + + Stream.of(requesterID, requestedID) + .map(Bukkit::getPlayer).filter(Objects::nonNull) + .forEach(player -> player + .sendMessage(I.t("{ce}This alliance request is no longer valid. Please re-send it."))); + return; + } + + + // We create a new team for this new alliance. Old teams are dropped. + + final QuartzTeam allianceTeam = QuartzTeams.get().createTeam(I.t("Your alliance"), TeamColor.WHITE); + + final Set<UUID> alliancePlayers = Stream.of(requesterTeam, requestedTeam) + .flatMap(team -> team.getPlayersUUID().stream()) + .filter(game::isAlive) + .collect(Collectors.toSet()); + + allianceTeam.addAll(alliancePlayers); + + requestedTeam.deleteTeam(); + requesterTeam.deleteTeam(); + + + // We consume the alliances + + alliances.consumeAlliance(requesterID, allianceTeam.size() - 1); + alliances.consumeAlliance(requestedID, allianceTeam.size() - 1); + + + // We notify the players + + final QSGSound[] jingle = new QSGSound[] { + new QSGSound(1f, 1.10f, "ARROW_HIT_PLAYER", "SUCCESSFUL_HIT"), + new QSGSound(1f, 1.22f, "ARROW_HIT_PLAYER", "SUCCESSFUL_HIT"), + new QSGSound(1f, 1.33f, "ARROW_HIT_PLAYER", "SUCCESSFUL_HIT"), + new QSGSound(1f, 1.44f, "ARROW_HIT_PLAYER", "SUCCESSFUL_HIT"), + new QSGSound(1f, 1.80f, "ENTITY_PLAYER_LEVELUP", "LEVEL_UP", "LEVELUP") + }; + + allianceTeam.getOnlinePlayers().forEach(player -> { + player.sendMessage(""); + + if (allianceTeam.size() == 2) { + player.sendMessage(I.t("{green}{bold}You are now allied with {0}!", + allianceTeam.getPlayers().stream().filter(p -> !p.getUniqueId().equals(player.getUniqueId())) + .findAny().map(OfflinePlayer::getName).orElse("<Unknown>"))); + player.sendMessage( + I.t("{green}Your objective is to win together. But chhhh! Other players are not aware of your alliance...")); + } else { + player.sendMessage(I.t("{green}{bold}The alliance expands!")); + player.sendMessage(I.t("{gray}Players in the alliance: {0}", String.join(", ", + allianceTeam.getPlayers().stream().map(OfflinePlayer::getName).collect(Collectors.toSet())))); + } + + player.sendMessage(""); + + for (int i = 0; i < jingle.length; i++) { + final int index = i; + RunTask.later(() -> jingle[index].play(player), i * 3L); + } + }); + + + // A small log message + + QSG.log(AlliancesModule.class).info( + "{0} succeeded! A new alliance was created between these players: {1}.", + this, + String.join(", ", allianceTeam.getPlayers().stream() + .map(player -> player.getName() + " (a=" + alliances.getAlliancesLeft(player.getUniqueId()) + + ")") + .collect(Collectors.toSet()) + ) + ); + + + // Also in the timeline + + QSG.ifLoaded(HawkModule.class, hawk -> { + if (allianceTeam.size() == 2) { + final Iterator<OfflinePlayer> players = allianceTeam.getPlayers().iterator(); + + hawk.getReport().record(ReportEvent.withIcon( + I.t("A new alliance is founded!"), + I.t("Between {0} and {1}", players.next().getName(), players.next().getName()), + "block-structure-block-data" + )); + } else { + @SuppressWarnings("OptionalGetWithoutIsPresent") final OfflinePlayer joiningPlayer = + requestedTeam.size() == 1 ? requestedTeam.getPlayers().stream().findFirst().get() : + requesterTeam.getPlayers().stream().findFirst().get(); + + final List<String> playersNames = + allianceTeam.getPlayers().stream().filter(player -> !player.equals(joiningPlayer)) + .map(OfflinePlayer::getName).collect(Collectors.toList()); + final int size = playersNames.size(); + + final StringBuilder sentence = new StringBuilder(size * 16); + + for (int i = 0; i < size; i++) { + sentence.append(playersNames.get(i)); + + if (i == size - 2) { + sentence.append(" ").append(I.t("and")).append(" "); + } else if (i != size - 1) { + sentence.append(", "); + } + } + + hawk.getReport().record(ReportEvent.withIcon( + I.t("The alliance is growing!"), + I.t("{0} joins {1}", joiningPlayer.getName(), sentence), + "block-structure-block" + )); + } + + allianceTeam.getPlayers().forEach(player -> hawk.getReport().getPlayer(player).setTagLine( + I.t("Allied"), + null, + I.t("Players in the (latest) alliance: {0}", String.join(", ", + allianceTeam.getPlayers().stream().map(OfflinePlayer::getName).collect(Collectors.toSet()))) + )); + }); + } + + /** + * @return The request's UUID, used for request identification in commands. + */ + public UUID getUniqueId() { + return allianceRequestUUID; + } + + /** + * @return The request sender's UUID. + */ + public UUID getRequesterID() { + return requesterID; + } + + /** + * @return The request's target UUID. + */ + public UUID getRequestedID() { + return requestedID; + } + + /** + * @return The error for this request (including « OK »). + */ + public RequestError getError() { + return requestError; + } + + /** + * A shortcut to get a player's name. + * + * @param playerID A player's UUID. + * @return The player name as a string. + */ + private String getName(final UUID playerID) { + return Optional.of(Bukkit.getOfflinePlayer(playerID)).map(OfflinePlayer::getName).orElse("<Unknown>"); + } + + /** + * Checks if the future alliance formed if the request is accepted is not too big according + * to the configuration. + * + * @return {@code true} if the future size is OK. + */ + private boolean checkFutureAllianceSize() { + return alliances.allianceSize(requestedTeam) + alliances.allianceSize(requesterTeam) <= + Config.MAX_PLAYERS_PER_ALLIANCE.get(); + } + + /** + * Checks if the given player have sufficient alliances left for this request. + * + * @param checkedPlayerID The player to check. + * @return {@code true} if there are enough alliances left. + */ + private boolean checkAlliancesLeft(final UUID checkedPlayerID) { + return alliances.getAlliancesLeft(checkedPlayerID) >= 1; + } + + /** + * Checks if this alliance would end the game. + * + * @return {@code true} if this alliance would <strong>not</strong> end the game. + */ + private boolean checkGameEnd() { + final Set<UUID> playersInFutureAlliance = Stream.of(requestedTeam.getPlayers(), requesterTeam.getPlayers()) + .flatMap(Collection::stream) + .map(OfflinePlayer::getUniqueId) + .collect(Collectors.toSet()); + return game.getAlivePlayersUUIDs().stream().anyMatch(player -> !playersInFutureAlliance.contains(player)); + } + + /** + * Throws an {@link IllegalStateException} if the request has errored. + */ + private void checkError() { + if (requestError != RequestError.OK) { + throw new IllegalStateException("This alliance request errored."); + } + } + + @Override + public String toString() { + return "AllianceRequest [from " + getName(requesterID) + " (n=" + requesterTeam.size() + ", a=" + + alliances.getAlliancesLeft(requesterID) + ") to " + getName(requestedID) + " (n=" + + requesterTeam.size() + ", a=" + alliances.getAlliancesLeft(requesterID) + ")]"; + } + + /** + * The request error state. If not OK, all methods except {@link #getError()} will throw + * an {@link IllegalStateException}. + */ + public enum RequestError { + OK, + TOO_FAR, + REQUESTER_OUT_OF_ALLIANCES, + REQUESTED_OUT_OF_ALLIANCES, + FUTURE_ALLIANCE_TOO_BIG, + BOTH_IN_A_DIFFERENT_ALLIANCE, + BOTH_IN_THE_SAME_ALLIANCE, + WOULD_END_THE_GAME + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/AlliancesModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/AlliancesModule.java new file mode 100644 index 0000000..8bac36f --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/AlliancesModule.java @@ -0,0 +1,242 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances; + +import com.google.common.collect.ImmutableMap; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start.BeforeTeleportationPhaseEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.SpectatorsModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.external.hawk.HawkModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances.commands.AllianceRequestCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances.commands.RequestAnswerCommand; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzteams.QuartzTeam; +import fr.zcraft.quartzteams.QuartzTeams; +import fr.zcraft.quartzteams.colors.TeamColor; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + + +@ModuleInfo( + name = "Alliances Scenario", + short_description = "Provides an alliances-based game, where players form alliances only " + + "by meeting in the game, everyone being alone at the beginning.", + description = "If enabled, the game will be alliances-based.\n\n" + + "To use this scenario, start without any team configured. All players " + + "will be alone at the beginning. If they meet someone, they can ask for " + + "an alliance with this player. If everyone is OK, they form a new team, " + + "but they are the only ones to know, as players names are not colored.\n\n" + + "An existing alliance can recruit a new ally using the same mechanism: " + + "if a player ask for an alliance to another player in an existing alliance, " + + "the two players in the alliance will be notified and will have to accept. " + + "If a player in an existing alliance want to invite someone, both the potential " + + "new ally and the other player in the existing alliance will have to agree.\n\n" + + "The number of alliances over time for a given player is limited. You start with " + + "an amount of alliances (default 2). If you create a two-players alliance, you lose " + + "one alliance. If you form a three-players alliance, you lose two alliances. If you " + + "run out of alliances, you can no longer form new alliances, and requests sent to you " + + "will be silently declined.", + when = ModuleLoadTime.ON_GAME_STARTING, + category = ModuleCategory.SCENARII, + icon = Material.PAPER, + settings = Config.class, + can_be_loaded_late = false +) +public class AlliancesModule extends QSGModule { + private final Map<UUID, Integer> alliancesLeft = new HashMap<>(); + private final Map<UUID, AllianceRequest> ongoingRequests = new HashMap<>(); + private GameModule game = null; + + @Override + protected void onEnable() { + game = QSG.module(GameModule.class); + + // We update some settings + + eu.carrade.amaury.quartzsurvivalgames.modules.core.game.Config.SIDEBAR.TEAMS.set(false); + eu.carrade.amaury.quartzsurvivalgames.modules.core.teams.Config.SIDEBAR.TITLE.USE_TEAM_NAME.set(true); + + QuartzTeams.settings() + .setTeamsOptions( + eu.carrade.amaury.quartzsurvivalgames.modules.core.teams.Config.CAN_SEE_FRIENDLY_INVISIBLES + .get(), + false, + false, + true // Important! As we use the same team names for lots of teams, as titles. + ) + .setMaxPlayersPerTeam(Config.MAX_PLAYERS_PER_ALLIANCE.get()); + + QSG.ifLoaded(HawkModule.class, hawk -> hawk.getReport().settings().enableSummary(true, true, false)); + + // ...And permissions + + QuartzTeams.setPermissionsChecker(new TeamsPermissionsChecker(QuartzTeams.get().permissionsChecker())); + } + + @Override + public List<Class<? extends Command>> getCommands() { + return Arrays.asList(AllianceRequestCommand.class, RequestAnswerCommand.class); + } + + @Override + public Map<String, Class<? extends Command>> getCommandsAliases() { + return ImmutableMap.of( + "alliance", AllianceRequestCommand.class, + "a", AllianceRequestCommand.class + ); + } + + + /** + * Inits the count of left alliances to the configured max if not already stored. + * + * @param playerID The player to initialize the count for. + */ + private void initAlliancesCountIfRequired(final UUID playerID) { + alliancesLeft.putIfAbsent(playerID, Config.ALLIANCES_PER_PLAYER.get()); + } + + /** + * Consumes an amount of alliances for the given player. + * + * @param playerID The player's ID. + * @param amount The amount to consume. + */ + public void consumeAlliance(final UUID playerID, final int amount) { + initAlliancesCountIfRequired(playerID); + alliancesLeft.put(playerID, Math.max(0, alliancesLeft.get(playerID) - amount)); + } + + /** + * Returns the amount of alliances left for the given player. + * + * @param playerID The player's ID. + * @return The amount of alliances left. + */ + public int getAlliancesLeft(final UUID playerID) { + initAlliancesCountIfRequired(playerID); + return alliancesLeft.get(playerID); + } + + /** + * Checks if we can borrow the given amount of alliances to a player. If so, + * borrows them and returns {@code true}. Else, returns {@code false}. + * + * @param playerID The player's ID. + * @param amount The amount of alliances to borrow. + * @return {@code true} if they could (and were) borrowed. + */ + public boolean consumeAlliancesIfPossible(final UUID playerID, final int amount) { + if (getAlliancesLeft(playerID) >= amount) { + consumeAlliance(playerID, amount); + return true; + } else { + return false; + } + } + + + public void registerRequest(final AllianceRequest request) { + ongoingRequests.put(request.getUniqueId(), request); + } + + public void unregisterRequest(final AllianceRequest request) { + ongoingRequests.remove(request.getUniqueId()); + } + + public AllianceRequest getRequestByID(final UUID requestID) { + return ongoingRequests.get(requestID); + } + + public Set<AllianceRequest> getRequestsBySender(final UUID requestSenderID) { + return ongoingRequests.values().stream() + .filter(request -> request.getRequesterID().equals(requestSenderID)) + .collect(Collectors.toSet()); + } + + public AllianceRequest getRequestByCouple(final UUID requestSenderID, final UUID requestedID) { + return ongoingRequests.values().stream() + .filter(request -> request.getRequesterID().equals(requestSenderID)) + .filter(request -> request.getRequestedID().equals(requestedID)) + .findAny().orElse(null); + } + + public int allianceSize(UUID playerID) { + final QuartzTeam team = QuartzTeams.get().getTeamForPlayer(playerID); + + if (team != null) { + return allianceSize(team); + } else { + return 1; + } + } + + public int allianceSize(final QuartzTeam team) { + return (int) team.getPlayers().stream().filter(game::isAlive).count(); + } + + + /** + * Creates teams for each player before the beginning of the game: the teams will be + * indistinguishable, and the game will be considered as a teams game, even with + * everyone in solo. + */ + @EventHandler(priority = EventPriority.LOWEST) + private void onPreSpawnSelection(final BeforeTeleportationPhaseEvent ev) { + final SpectatorsModule spectators = QSG.module(SpectatorsModule.class); + + new HashSet<>(QuartzTeams.get().getTeams()).forEach(QuartzTeam::deleteTeam); + + Bukkit.getOnlinePlayers().stream() + .filter(player -> !spectators.isSpectator(player)) + .forEach(player -> QuartzTeams.get().createTeam(I.t("Alone"), TeamColor.WHITE, player)); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/Config.java new file mode 100644 index 0000000..3a18c6b --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/Config.java @@ -0,0 +1,52 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + +public class Config extends ConfigurationInstance { + static public ConfigurationItem<Integer> ALLIANCES_PER_PLAYER = item("alliances-per-player", 2); + static public ConfigurationItem<Integer> MAX_PLAYERS_PER_ALLIANCE = item("max-players-per-alliance", 3); + static public ConfigurationItem<Integer> MAX_DISTANCE_TO_CREATE_AN_ALLIANCE = + item("max-distance-to-create-an-alliance", 60); + + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/TeamsPermissionsChecker.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/TeamsPermissionsChecker.java new file mode 100644 index 0000000..6dc4d23 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/TeamsPermissionsChecker.java @@ -0,0 +1,69 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances; + +import fr.zcraft.quartzteams.QuartzTeamsPermission; +import fr.zcraft.quartzteams.permissions.PermissionsChecker; +import org.bukkit.permissions.Permissible; + +public class TeamsPermissionsChecker implements PermissionsChecker { + private final PermissionsChecker delegate; + + public TeamsPermissionsChecker(PermissionsChecker delegate) { + this.delegate = delegate; + } + + @Override + public boolean hasPermission(Permissible permissible, QuartzTeamsPermission permission) { + switch (permission) { + + case CREATE_TEAM: + case DELETE_TEAM: + case RESET_TEAMS: + case LIST_TEAMS: // Very important! Would allow to see all alliances. + case JOIN_TEAM: + case LEAVE_TEAM: + case UPDATE_TEAMS_PLAYERS_LIST: + case UPDATE_TEAM_COLOR: + case UPDATE_OTHER_TEAM_NAME: + case UPDATE_OTHER_TEAM_COLOR: + case UPDATE_OTHER_TEAM_BANNER: + return false; + + default: + return delegate.hasPermission(permissible, permission); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/commands/AllianceRequestCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/commands/AllianceRequestCommand.java new file mode 100644 index 0000000..c5ee697 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/commands/AllianceRequestCommand.java @@ -0,0 +1,168 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances.AllianceRequest; +import eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances.AlliancesModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances.Config; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzteams.QuartzTeams; +import java.util.List; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +@CommandInfo(name = "alliance-request", usageParameters = "<player>", aliases = {"alliancerequest", "alliance", "ally"}) +public class AllianceRequestCommand extends Command { + @Override + protected void run() throws CommandException { + if (QSG.module(GameModule.class).currentPhaseBefore(GamePhase.IN_GAME)) { + error(I.t("The game is not started.")); + } else if (args.length == 0) { + throwInvalidArgument(I.t("You must provide a player name.")); + } + + final AlliancesModule alliances = QSG.module(AlliancesModule.class); + + final Player requested = getPlayerParameter(0); + + if (requested.getUniqueId().equals(playerSender().getUniqueId())) { + error(I.t("You cannot create an alliance with yourself.")); + } else if (alliances.getRequestByCouple(playerSender().getUniqueId(), requested.getUniqueId()) != null) { + error(I.t("You already have an ongoing alliance request sent to {0}. Please be patient!", + requested.getName())); + } + + final AllianceRequest request = new AllianceRequest(playerSender().getUniqueId(), requested.getUniqueId()); + + QSG.log().info("New request: {0} - {1}", request, request.getError()); + + // The rule to send error messages is: no answer should not be distinguishable from + // errors linked to existing alliances, because the alliances are secret. + + switch (request.getError()) { + case TOO_FAR: + error(I.t("{0} is too far. You must be within {1} blocks of each other.", requested.getName(), + Config.MAX_DISTANCE_TO_CREATE_AN_ALLIANCE.get())); + return; + + case REQUESTER_OUT_OF_ALLIANCES: + error(I.t("You can no longer join an alliance.")); + return; + + case REQUESTED_OUT_OF_ALLIANCES: + yourRequestHasBeenSent(requested); + + requested.sendMessage(""); + requested.sendMessage( + I.t("{gray}{bold}{0} just sent you an alliance request, but you cannot accept it because you have no alliance left.", + sender.getName())); + requested.sendMessage( + I.t("{gray}{0} is not aware of this, but I preferred to warn you so that you would not be caught off guard if he or she mentions it.", + sender.getName())); + requested.sendMessage(""); + + return; + + case FUTURE_ALLIANCE_TOO_BIG: + // Here, if the player is solo, we say that the request was sent and we warn the + // other alliance members. If the player is in an alliance he know its size and + // the other one is solo. + if (alliances.allianceSize(playerSender().getUniqueId()) == 1) { + yourRequestHasBeenSent(requested); + + QuartzTeams.get().getTeamForPlayer(requested).getOnlinePlayers().forEach(teammate -> { + teammate.sendMessage(""); + teammate.sendMessage( + I.t("{gray}{bold}{0} just sent you an alliance request, but you cannot accept it because your alliance is already at full capacity.", + sender.getName())); + teammate.sendMessage( + I.t("{gray}{0} is not aware of this, but I preferred to warn you so that you would not be caught off guard if he or she mentions it.", + sender.getName())); + teammate.sendMessage(""); + }); + } else { + error(I.t( + "You cannot send a request alliance as your alliance is already at full capacity. Don't be too greedy!")); + } + + return; + + case BOTH_IN_A_DIFFERENT_ALLIANCE: + // Here we cannot inform the other alliance because they would know the sender is in an alliance. + yourRequestHasBeenSent(requested); + return; + + case BOTH_IN_THE_SAME_ALLIANCE: + error(I.t("You're already allied with {0}!", requested.getName())); + return; + + case WOULD_END_THE_GAME: + error(I.t("You cannot create this alliance as it would end the game.")); + return; + + case OK: + yourRequestHasBeenSent(requested); + request.sendApprovalRequests(); + + break; + } + } + + @Override + protected List<String> complete() { + if (args.length == 1) { + return getMatchingPlayerNames( + Bukkit.getOnlinePlayers().stream().filter(player -> !player.equals(sender)) + .collect(Collectors.toSet()), + args[0]); + } else { + return null; + } + } + + private void yourRequestHasBeenSent(final Player to) { + info(""); + success(I.t("{bold}Your request has been sent to {0}.", to.getName())); + success(I.t("Wait until it is accepted. Let's hope you don't hear only silence...")); + info(""); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/commands/RequestAnswerCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/commands/RequestAnswerCommand.java new file mode 100644 index 0000000..16d32db --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/scenarii/alliances/commands/RequestAnswerCommand.java @@ -0,0 +1,86 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances.AllianceRequest; +import eu.carrade.amaury.quartzsurvivalgames.modules.scenarii.alliances.AlliancesModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.UUID; +import org.bukkit.entity.Player; + +@CommandInfo(name = "alliance-request-answer", usageParameters = "<requestUUID> <yes|no> §8(internal)") +public class RequestAnswerCommand extends Command { + @Override + protected void run() throws CommandException { + if (args.length < 2) { + QSG.log(AlliancesModule.class) + .info("{0} (badly) used the alliance-request-answer directly.", sender.getName()); + throwInvalidArgument( + I.t("Invalid command usage. But, you shouldn't use this command directly. What are you doing?")); + } + + try { + final Player player = playerSender(); + final UUID requestID = UUID.fromString(args[0]); + final boolean answer = getBooleanParameter(1); + + final AllianceRequest request = QSG.module(AlliancesModule.class).getRequestByID(requestID); + + if (request != null) { + try { + QSG.log(AlliancesModule.class).info("{0}: reply from {1}: {2}", request, player.getName(), answer); + request.registerApproval(player.getUniqueId(), answer); + } + catch (IllegalArgumentException e) { + QSG.log(AlliancesModule.class) + .warning("{0}: {1} tried to reply {2} but was not in the approvers list.", request, + player.getName(), answer); + error(I.t("You weren't asked for your opinion regarding this request.")); + } + } else { + error(I.t("This request has expired.")); + } + } + catch (IllegalArgumentException e) { + QSG.log(AlliancesModule.class) + .info("{0} (badly) used the alliance-request-answer directly.", sender.getName()); + throwInvalidArgument("Malformed UUID."); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/game/Cage.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/starting/cages/Cage.java similarity index 54% rename from src/main/java/eu/carrade/amaury/UHCReloaded/game/Cage.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/starting/cages/Cage.java index 679b19d..09ab4bd 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/game/Cage.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/starting/cages/Cage.java @@ -1,20 +1,20 @@ /* * Copyright or © or Copr. AmauryCarrade (2015) - * + * * 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, + * 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". - * + * "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. - * + * 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, @@ -22,43 +22,38 @@ * 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. - * + * 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.game; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.teams.UHTeam; -import eu.carrade.amaury.UHCReloaded.utils.ColorsUtils; +package eu.carrade.amaury.quartzsurvivalgames.modules.starting.cages; + +import fr.zcraft.quartzlib.tools.items.ColorableMaterial; +import fr.zcraft.quartzlib.tools.items.ItemUtils; +import fr.zcraft.quartzteams.QuartzTeam; +import java.util.HashMap; +import java.util.Map; +import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.material.MaterialData; - -import java.util.HashMap; -import java.util.Map; +import org.bukkit.block.data.BlockData; -public class Cage -{ +public class Cage { private final Location baseLocation; - - private Material material = Material.BARRIER; - private MaterialData materialData = null; - private final boolean buildCeiling; private final boolean visibleWalls; - + private final Map<Location, SimpleBlock> blocksBuilt = new HashMap<>(); + private Material material = Material.BARRIER; private int radius = 1; private int internalHeight = 3; - private boolean built = false; - private Map<Location, SimpleBlock> blocksBuilt = new HashMap<>(); /** @@ -66,34 +61,55 @@ public class Cage * teleported to be on the ground). * @param buildCeiling {@code true} to build the ceiling of the cage. */ - public Cage(Location baseLocation, boolean buildCeiling, boolean visibleWalls) - { + public Cage(Location baseLocation, boolean buildCeiling, boolean visibleWalls) { this.baseLocation = baseLocation; this.buildCeiling = buildCeiling; this.visibleWalls = visibleWalls; } /** - * Sets the custom material to use. + * Creates a Cage instance for the given team. * - * @param customMaterial A material. - * @param data The data value (or {@code null}). + * @param team The team. Can be null (fallbacks to white if a color is needed). + * @param location Where the cage should be built. + * @return A Cage */ - public void setCustomMaterial(Material customMaterial, MaterialData data) - { - this.material = customMaterial == null ? Material.BARRIER : customMaterial; - this.materialData = data; - } + static public Cage createInstanceForTeam(final QuartzTeam team, final Location location) { + final Material cageMaterial; - /** - * Sets the custom material to use. - * - * @param customMaterial A material. - * @param data The data value. - */ - public void setCustomMaterial(Material customMaterial, byte data) - { - setCustomMaterial(customMaterial, new MaterialData(this.material, data)); + switch (Config.TYPE.get()) { + case TEAM_COLOR_TRANSPARENT: + cageMaterial = ItemUtils.colorize( + ColorableMaterial.STAINED_GLASS, team != null ? team.getColorOrWhite().toChatColor() : ChatColor.WHITE); + break; + + case TEAM_COLOR_SOLID: + cageMaterial = ItemUtils.colorize(ColorableMaterial.TERRACOTTA, team != null ? team.getColorOrWhite().toChatColor() : ChatColor.WHITE); + break; + + case TEAM_COLOR_FANCY: + cageMaterial = ItemUtils.colorize(ColorableMaterial.GLAZED_TERRACOTTA, team != null ? team.getColorOrWhite().toChatColor() : ChatColor.WHITE); + break; + + case CUSTOM: + cageMaterial = Config.CUSTOM_BLOCK.get(); + break; + + // Should never happen + default: + cageMaterial = null; + } + + final Cage cage = new Cage(location, Config.BUILD_CEILING.get(), Config.VISIBLE_WALLS.get()); + + if (cageMaterial != null) // Should always be true + { + cage.setCustomMaterial(cageMaterial); + cage.setInternalHeight(Config.HEIGHT.get()); + cage.setRadius(Config.RADIUS.get()); + } + + return cage; } /** @@ -101,33 +117,29 @@ public void setCustomMaterial(Material customMaterial, byte data) * * @param customMaterial A material. */ - public void setCustomMaterial(Material customMaterial) - { - setCustomMaterial(customMaterial, null); + public void setCustomMaterial(Material customMaterial) { + this.material = customMaterial == null ? Material.BARRIER : customMaterial; } - /** * Sets the internal height, i.e. the height of the open space for players * (the ceiling will be above this height, and the ground under). * * @param internalHeight The height. */ - public void setInternalHeight(int internalHeight) - { + public void setInternalHeight(int internalHeight) { this.internalHeight = internalHeight; } /** * Sets the square radius of the cage. - * + * <p> * With 0, you'll have a cage with one block to walk. With 1, you'll have a * 3×3 cage. With 2, a 5×5 cage. Etc. * * @param radius The radius. */ - public void setRadius(int radius) - { + public void setRadius(int radius) { this.radius = radius; } @@ -137,48 +149,23 @@ public void setRadius(int radius) * @param location The location * @param material The block material */ - private void setBlock(final Location location, final Material material) - { - setBlock(location, material, null); - } - - /** - * Sets a block (and remembers the old one to clean up things after). - * - * @param location The location - * @param material The block material - * @param data The block data value (as byte) - */ - private void setBlock(final Location location, final Material material, final byte data) - { - setBlock(location, material, new MaterialData(material, data)); - } - - /** - * Sets a block (and remembers the old one to clean up things after). - * - * @param location The location - * @param material The block material - * @param data The block data value (as {@link MaterialData}) - */ - private void setBlock(final Location location, final Material material, final MaterialData data) - { + private void setBlock(final Location location, final Material material) { final Block block = location.getBlock(); - if (!blocksBuilt.containsKey(location)) - blocksBuilt.put(location, new SimpleBlock(block.getType(), block.getState().getData().clone())); + if (!blocksBuilt.containsKey(location)) { + blocksBuilt.put(location, new SimpleBlock(block.getType(), block.getState().getBlockData().clone())); + } block.setType(material); - if (data != null) block.setData(data.getData()); } - /** * Builds the cage. */ - public void build() - { - if (built) return; + public boolean build() { + if (built) { + return false; + } final int externalRadius = radius + 1; final int xMin = baseLocation.getBlockX() - externalRadius; @@ -192,38 +179,37 @@ public void build() // Builds the base barrier square under any cage, to support falling blocks and to avoid players falling // through the blocks when teleported - for (int x = xMin; x <= xMax; x++) - for (int z = zMin; z <= zMax; z++) + for (int x = xMin; x <= xMax; x++) { + for (int z = zMin; z <= zMax; z++) { setBlock(new Location(world, x, baseLocation.getBlockY() - 2, z), Material.BARRIER); + } + } // Builds the ground - for (int x = xMin + 1; x <= xMax - 1; x++) - for (int z = zMin + 1; z <= zMax - 1; z++) - setBlock(new Location(world, x, baseLocation.getBlockY() - 1, z), material, materialData); + for (int x = xMin + 1; x <= xMax - 1; x++) { + for (int z = zMin + 1; z <= zMax - 1; z++) { + setBlock(new Location(world, x, baseLocation.getBlockY() - 1, z), material); + } + } // Builds the walls final Material wallsMaterial = visibleWalls ? material : Material.BARRIER; - final MaterialData wallsMaterialData = visibleWalls ? materialData : null; - for (int x = xMin; x <= xMax; x++) - { - for (int y = baseLocation.getBlockY() - 1; y < baseLocation.getBlockY() + internalHeight; y++) - { - setBlock(new Location(world, x, y, zMin), wallsMaterial, wallsMaterialData); - setBlock(new Location(world, x, y, zMax), wallsMaterial, wallsMaterialData); + for (int x = xMin; x <= xMax; x++) { + for (int y = baseLocation.getBlockY() - 1; y < baseLocation.getBlockY() + internalHeight; y++) { + setBlock(new Location(world, x, y, zMin), wallsMaterial); + setBlock(new Location(world, x, y, zMax), wallsMaterial); } } - for (int z = zMin; z <= zMax; z++) - { - for (int y = baseLocation.getBlockY() - 1; y < baseLocation.getBlockY() + internalHeight; y++) - { - setBlock(new Location(world, xMin, y, z), wallsMaterial, wallsMaterialData); - setBlock(new Location(world, xMax, y, z), wallsMaterial, wallsMaterialData); + for (int z = zMin; z <= zMax; z++) { + for (int y = baseLocation.getBlockY() - 1; y < baseLocation.getBlockY() + internalHeight; y++) { + setBlock(new Location(world, xMin, y, z), wallsMaterial); + setBlock(new Location(world, xMax, y, z), wallsMaterial); } } @@ -231,120 +217,54 @@ public void build() // Builds the ceiling final Material ceilingMaterial = buildCeiling ? material : Material.BARRIER; - final MaterialData ceilingMaterialData = buildCeiling ? materialData : null; int xMinCeiling = xMin, xMaxCeiling = xMax, zMinCeiling = zMin, zMaxCeiling = zMax; - if (buildCeiling && !visibleWalls) - { + if (buildCeiling && !visibleWalls) { xMinCeiling++; xMaxCeiling--; zMinCeiling++; zMaxCeiling--; } - for (int x = xMinCeiling; x <= xMaxCeiling; x++) - for (int z = zMinCeiling; z <= zMaxCeiling; z++) - setBlock(new Location(world, x, baseLocation.getBlockY() + internalHeight, z), ceilingMaterial, ceilingMaterialData); + for (int x = xMinCeiling; x <= xMaxCeiling; x++) { + for (int z = zMinCeiling; z <= zMaxCeiling; z++) { + setBlock(new Location(world, x, baseLocation.getBlockY() + internalHeight, z), ceilingMaterial); + } + } built = true; + + return true; } /** * Destroys the cage. */ - public void destroy() - { - for (Map.Entry<Location, SimpleBlock> entry : blocksBuilt.entrySet()) - { + public void destroy() { + if (!built) { + return; + } + + for (final Map.Entry<Location, SimpleBlock> entry : blocksBuilt.entrySet()) { final Block block = entry.getKey().getBlock(); final SimpleBlock originalBlock = entry.getValue(); block.setType(originalBlock.material); - if (originalBlock.data != null) - block.getState().setData(originalBlock.data); + if (originalBlock.data != null) { + block.getState().setBlockData(originalBlock.data); + } } built = false; } - /** - * Creates a Cage instance for the given team. - * - * @param team The team - * @param location The spawn location - * - * @return A Cage - */ - static public Cage createInstanceForTeam(final UHTeam team, final Location location) - { - final Material cageMaterial; - final Byte cageData; - - switch (UHConfig.START.SLOW.CAGES.TYPE.get()) - { - case TEAM_COLOR_TRANSPARENT: - cageMaterial = Material.STAINED_GLASS; - cageData = ColorsUtils.chat2Dye(team.getColorOrWhite().toChatColor()).getWoolData(); - break; - - case TEAM_COLOR_SOLID: - cageMaterial = Material.STAINED_CLAY; - cageData = ColorsUtils.chat2Dye(team.getColorOrWhite().toChatColor()).getWoolData(); - break; - - case CUSTOM: - cageMaterial = UHConfig.START.SLOW.CAGES.CUSTOM_BLOCK.get(); - cageData = null; - break; - - // Should never happen - default: - cageMaterial = null; - cageData = null; - } - - final Cage cage = new Cage( - location, - UHConfig.START.SLOW.CAGES.BUILD_CEILING.get(), - UHConfig.START.SLOW.CAGES.VISIBLE_WALLS.get() - ); - - if (cageMaterial != null) // Should always be true - { - cage.setCustomMaterial(cageMaterial, cageData != null ? cageData : 0); - cage.setInternalHeight(UHConfig.START.SLOW.CAGES.HEIGHT.get()); - cage.setRadius(UHConfig.START.SLOW.CAGES.RADIUS.get()); - } - - return cage; - } - - /** - * Creates a Cage instance for the given team if cages are enabled. - * - * @param team The team. - * @param location The spawn location. - * - * @return A Cage, or null if cages are disabled. - */ - static public Cage createInstanceForTeamIfEnabled(final UHTeam team, final Location location) - { - if (UHConfig.START.SLOW.CAGES.ENABLED.get()) - { - return createInstanceForTeam(team, location); - } - else return null; - } - - /** * Cage type, enum used for the configuration */ - public enum CageType - { + public enum CageType { /** * Cages in stained glass, using the team color (or the closest color * available). @@ -352,11 +272,17 @@ public enum CageType TEAM_COLOR_TRANSPARENT, /** - * Cages in stained hardened clay, using the team color (or the closest + * Cages in stained terracotta clay, using the team color (or the closest * color available). */ TEAM_COLOR_SOLID, + /** + * Cages in stained glazed terracotta, using the team color (or the closest + * color available). + */ + TEAM_COLOR_FANCY, + /** * Cages in a custom provided block. */ @@ -367,13 +293,11 @@ public enum CageType * A block + data value (storage class used to restore old blocks when the * cage is destroyed). */ - private class SimpleBlock - { + private class SimpleBlock { public Material material; - public MaterialData data; + public BlockData data; - public SimpleBlock(Material material, MaterialData data) - { + public SimpleBlock(Material material, BlockData data) { this.material = material; this.data = data; } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/starting/cages/CagesModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/starting/cages/CagesModule.java new file mode 100644 index 0000000..554c096 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/starting/cages/CagesModule.java @@ -0,0 +1,109 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.starting.cages; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start.PlayerAboutToBeTeleportedToSpawnPointEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start.PlayerSpawnPointSelectedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.start.PlayerTeleportedToSpawnPointEvent; +import fr.zcraft.quartzteams.QuartzTeams; +import java.util.HashMap; +import java.util.Map; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + + +@ModuleInfo( + name = "Cages", + description = "Puts players in cages (or platforms) instead of letting them float in the air, during the startup process.", + when = ModuleLoadTime.ON_GAME_STARTING, + category = ModuleCategory.STARTING, + icon = Material.GLASS, + settings = Config.class, + can_be_loaded_late = false +) +public class CagesModule extends QSGModule { + private final Map<Location, Cage> cages = new HashMap<>(); + + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerSpawnSelected(PlayerSpawnPointSelectedEvent ev) { + final Location spawn = cloneAndNormalize(ev.getSpawnPoint()); + cages.putIfAbsent(spawn, Cage.createInstanceForTeam(QuartzTeams.get().getTeamForPlayer(ev.getPlayer()), spawn)); + } + + @EventHandler + public void onPlayerAboutToBeTeleportedToSpawn(PlayerAboutToBeTeleportedToSpawnPointEvent ev) { + final Cage cage = cages.get(cloneAndNormalize(ev.getSpawnPoint())); + + if (cage != null) { + cage.build(); + } + } + + @EventHandler + public void onPlayerTeleportedToSpawn(PlayerTeleportedToSpawnPointEvent ev) { + final Location normalizedLocation = cloneAndNormalize(ev.getSpawnPoint()); + + // We only remove the fly if there is a cage for that player. + if (cages.containsKey(normalizedLocation)) { + ev.getPlayer().setFlying(false); + ev.getPlayer().setAllowFlight(false); + + // We slightly fix the player location so he is at the center of the platform. + ev.getPlayer().teleport(normalizedLocation.add(.5, .5, .5)); + } + } + + @EventHandler + public void onGameStarts(GamePhaseChangedEvent ev) { + if (ev.getNewPhase() != GamePhase.IN_GAME) { + return; + } + cages.forEach((location, nicolas) -> nicolas.destroy()); // Not even sorry. + } + + private Location cloneAndNormalize(final Location location) { + return new Location(location.getWorld(), location.getBlockX(), location.getBlockY(), location.getBlockZ(), 0, + 0); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/starting/cages/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/starting/cages/Config.java new file mode 100644 index 0000000..17c4cee --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/starting/cages/Config.java @@ -0,0 +1,55 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.starting.cages; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; +import org.bukkit.Material; + + +public class Config extends ConfigurationInstance { + public static final ConfigurationItem<Cage.CageType> TYPE = item("type", Cage.CageType.TEAM_COLOR_TRANSPARENT); + public static final ConfigurationItem<Material> CUSTOM_BLOCK = item("custom-block", Material.BARRIER); + public static final ConfigurationItem<Boolean> BUILD_CEILING = item("build-ceiling", false); + public static final ConfigurationItem<Boolean> VISIBLE_WALLS = item("visible-walls", true); + public static final ConfigurationItem<Integer> RADIUS = item("radius", 2); + public static final ConfigurationItem<Integer> HEIGHT = item("height", 3); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/TagPlayerDrops.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/TagPlayerDrops.java new file mode 100644 index 0000000..0dd2f43 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/TagPlayerDrops.java @@ -0,0 +1,68 @@ +/* + * Plugin UHCReloaded + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.metadata.FixedMetadataValue; + + +@ModuleInfo( + name = "Tag Player Drops", + description = "Adds a metadata to player drops so we can detect them if needed", + when = ModuleLoadTime.POST_WORLD, + category = ModuleCategory.UTILITIES, + internal = true, + hidden = true, + can_be_unloaded = false +) +public class TagPlayerDrops extends QSGModule { + + /** + * Adds a metadata to items thrown by a player. + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerItemDrop(PlayerDropItemEvent event) + { + if (!event.getItemDrop().hasMetadata("playerDrop")) + event.getItemDrop().setMetadata("playerDrop", new FixedMetadataValue(QSG.get(), true)); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/check/CheckCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/check/CheckCommand.java new file mode 100644 index 0000000..52815c3 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/check/CheckCommand.java @@ -0,0 +1,59 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.check; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.BorderModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; + +@CommandInfo(name = "border-check", usageParameters = "<radius>", aliases = {"bordercheck", "bcheck", "bc"}) +public class CheckCommand extends Command { + @Override + protected void run() throws CommandException { + if (args.length == 0) { + throwInvalidArgument(I.t("You must provide a check radius.")); + } + + try { + QSG.module(BorderModule.class).sendCheckMessage(sender, Integer.valueOf(args[0])); + } + catch (NumberFormatException e) { + sender.sendMessage(I.t("{ce}“{0}” is not a number...", args[0])); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/check/CheckModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/check/CheckModule.java new file mode 100644 index 0000000..c085aa0 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/check/CheckModule.java @@ -0,0 +1,58 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.check; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import fr.zcraft.quartzlib.components.commands.Command; +import java.util.Collections; +import java.util.List; +import org.bukkit.Material; + +@ModuleInfo( + name = "Border Check", + description = "Offers a command to check how far players are from a given border size.", + category = ModuleCategory.UTILITIES, + icon = Material.JUNGLE_FENCE, + when = ModuleLoadTime.ON_GAME_START +) +public class CheckModule extends QSGModule { + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(CheckCommand.class); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/food/FoodModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/food/FoodModule.java new file mode 100644 index 0000000..ed3efb3 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/food/FoodModule.java @@ -0,0 +1,61 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.food; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.food.commands.FeedAllCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.food.commands.FeedCommand; +import fr.zcraft.quartzlib.components.commands.Command; +import java.util.Arrays; +import java.util.List; +import org.bukkit.Material; + + +@ModuleInfo( + name = "Food Commands", + description = "Provides commands to update food level & saturation of some or all players.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.UTILITIES, + icon = Material.MUSHROOM_STEW +) +public class FoodModule extends QSGModule { + @Override + public List<Class<? extends Command>> getCommands() { + return Arrays.asList(FeedCommand.class, FeedAllCommand.class); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/food/commands/FeedAllCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/food/commands/FeedAllCommand.java new file mode 100644 index 0000000..f927885 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/food/commands/FeedAllCommand.java @@ -0,0 +1,82 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.food.commands; + +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + + +@CommandInfo(name = "feed-all", usageParameters = "[foodPoints=20] [saturation=max]") +public class FeedAllCommand extends Command { + @Override + protected void run() throws CommandException { + int foodLevel = 20; + float saturation = 20f; + + // /uh feed-all <foodLevel> + if (args.length > 0) { + try { + foodLevel = Integer.valueOf(args[0]); + } + catch (NumberFormatException e) { + throwInvalidArgument( + I.t("{ce}Food points and saturation must be numbers (floats for the saturation)!")); + } + + // /uh feed-all <foodLevel> <saturation> + if (args.length > 1) { + try { + // The saturation value cannot be more than the food level. + saturation = Math.max(foodLevel, Float.valueOf(args[1])); + } + catch (NumberFormatException e) { + throwInvalidArgument( + I.t("{ce}Food points and saturation must be numbers (floats for the saturation)!")); + } + } + } + + for (final Player player : Bukkit.getOnlinePlayers()) { + player.setFoodLevel(foodLevel); + player.setSaturation(saturation); + } + + success(I.t("Set food level to {0} and saturation to {1} for every player.", foodLevel, saturation)); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/food/commands/FeedCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/food/commands/FeedCommand.java new file mode 100644 index 0000000..67b6d71 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/food/commands/FeedCommand.java @@ -0,0 +1,91 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.food.commands; + +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.List; +import org.bukkit.entity.Player; + + +@CommandInfo(name = "feed", usageParameters = "<player> [foodPoints=20] [saturation=max]", aliases = {"food"}) +public class FeedCommand extends Command { + @Override + protected void run() throws CommandException { + final Player target = getPlayerParameter(0); + + int foodLevel = 20; + float saturation = 20f; + + // /uh feed <player> <foodLevel> + if (args.length > 1) { + try { + foodLevel = Integer.valueOf(args[1]); + } + catch (final NumberFormatException e) { + throwInvalidArgument( + I.t("{ce}Food points and saturation must be numbers (floats for the saturation)!")); + } + + // /uh feed <player> <foodLevel> <saturation> + if (args.length > 2) { + try { + // The saturation value cannot be more than the food level. + saturation = Math.max(foodLevel, Float.valueOf(args[2])); + } + catch (final NumberFormatException e) { + throwInvalidArgument( + I.t("{ce}Food points and saturation must be numbers (floats for the saturation)!")); + } + } + } + + target.setFoodLevel(foodLevel); + target.setSaturation(saturation); + + success(I.t("Set food level to {0} and saturation to {1} for {2}.", foodLevel, saturation, target.getName())); + } + + @Override + protected List<String> complete() { + if (args.length == 1) { + return getMatchingPlayerNames(args[0]); + } else { + return null; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/freezer/FreezeCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/freezer/FreezeCommand.java new file mode 100644 index 0000000..e30a9d2 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/freezer/FreezeCommand.java @@ -0,0 +1,153 @@ +/* + * 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.quartzsurvivalgames.modules.utilities.freezer; + +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.List; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +/** + * This command freezes the players. + * <p> + * Usage: /uh freeze <on [player]|off [player]|all|none> + * - on [player]: freezes the given player, or the sender if no player was provided. + * - off [player]: unfreezes the given player (or the sender, same condition). + * - all: freezes all the alive players, the mobs and the timer. + * - none: unfreezes all the alive players (even if there where frozen before using + * /uh freeze all), the mobs and the timer. + */ +@CommandInfo(name = "freeze", usageParameters = "<on|off|all|none> [target]") +public class FreezeCommand extends Command { + @Override + public void run() throws CommandException { + if (args.length == 0) { + info(I.t("{aqua}------ Freeze commands ------")); + info(I.t("{cc}/uh freeze on [player]{ci}: freezes a player, or the sender without a specified player.")); + info(I.t( + "{cc}/uh freeze off [player]{ci}: unfreezes a player (or the sender), even if the entire game is frozen.")); + info(I.t("{cc}/uh freeze all{ci}: freezes the entire game (players, mobs, timer).")); + info(I.t( + "{cc}/uh freeze none{ci}: unfreezes the entire game. You NEED to execute this in order to relaunch the timer.")); + return; + } + + final String subCommand = args[0]; + + if (subCommand.equalsIgnoreCase("on") || subCommand.equalsIgnoreCase("off")) { + final boolean on = subCommand.equalsIgnoreCase("on"); + + // /uh freeze on: freezes the sender + if (args.length == 1) { + QSG.module(FreezerModule.class).setPlayerFreezeState(playerSender(), on); + + if (on) { + info(I.t("{cst}You where frozen by {0}.", sender.getName())); + } else { + info(I.t("{cst}You where unfrozen by {0}.", sender.getName())); + } + } + + // /uh freeze on <player>: freezes <player>. + else if (args.length == 2) { + final Player player = getPlayerParameter(1); + + if (player == null) { + error(I.t("{ce}{0} is offline!", args[1])); + } else { + QSG.module(FreezerModule.class).setPlayerFreezeState(player, on); + + if (on) { + player.sendMessage( + QSGUtils.prefixedMessage(I.t("Freezer"), + I.t("{cst}You where frozen by {0}.", sender.getName()))); + success(I.t("{cs}{0} is now frozen.", player.getName())); + } else { + player.sendMessage( + QSGUtils.prefixedMessage(I.t("Freezer"), + I.t("{cst}You where unfrozen by {0}.", sender.getName()))); + success(I.t("{cs}{0} is now unfrozen.", player.getName())); + } + } + } + } else if (subCommand.equalsIgnoreCase("all") || subCommand.equalsIgnoreCase("none")) { + final boolean on = subCommand.equalsIgnoreCase("all"); + + QSG.module(FreezerModule.class).setGlobalFreezeState(on); + + Bukkit.broadcastMessage(""); + if (on) { + Bukkit.broadcastMessage( + QSGUtils.prefixedMessage(I.t("Freezer"), I.t("{darkaqua}The entire game is now frozen."))); + } else { + Bukkit.broadcastMessage( + QSGUtils.prefixedMessage(I.t("Freezer"), I.t("{darkaqua}The game is now unfrozen."))); + } + Bukkit.broadcastMessage(""); + } + } + + @Override + public List<String> complete() { + if (args.length == 1) { + return getMatchingSubset(args[0], "on", "off", "all", "none"); + } else if (args.length == 2) { + if (args[0].equalsIgnoreCase("off")) { + return getMatchingSubset( + QSG.module(FreezerModule.class).getFrozenPlayers().stream() + .map(OfflinePlayer::getName) + .collect(Collectors.toSet()), + args[1]); + } else if (args[0].equalsIgnoreCase("on")) { + return getMatchingSubset( + QSG.game().getAlivePlayers().stream() + .filter(player -> !QSG.module(FreezerModule.class).isPlayerFrozen(player)) + .map(OfflinePlayer::getName) + .collect(Collectors.toSet()), + args[1] + ); + } else { + return null; + } + } else { + return null; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/FreezerListener.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/freezer/FreezerListener.java similarity index 64% rename from src/main/java/eu/carrade/amaury/UHCReloaded/listeners/FreezerListener.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/freezer/FreezerListener.java index 7687790..9f077a0 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/listeners/FreezerListener.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/freezer/FreezerListener.java @@ -30,9 +30,9 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.listeners; +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.freezer; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; import org.bukkit.entity.Creature; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -47,125 +47,81 @@ import org.bukkit.event.player.PlayerMoveEvent; -public class FreezerListener implements Listener -{ - - private UHCReloaded p = null; - - public FreezerListener() - { - this.p = UHCReloaded.get(); - } - - +public class FreezerListener implements Listener { /** * Used to prevent frozen players to break blocks. - * - * @param ev */ @EventHandler - public void onBlockBreakEvent(final BlockBreakEvent ev) - { - if (p.getFreezer().isPlayerFrozen(ev.getPlayer())) - { + public void onBlockBreakEvent(final BlockBreakEvent ev) { + if (QSG.module(FreezerModule.class).isPlayerFrozen(ev.getPlayer())) { ev.setCancelled(true); } } - /** * Used to prevent frozen players to place blocks. - * - * @param ev */ @EventHandler - public void onBlockPlaceEvent(final BlockPlaceEvent ev) - { - if (p.getFreezer().isPlayerFrozen(ev.getPlayer())) - { + public void onBlockPlaceEvent(final BlockPlaceEvent ev) { + if (QSG.module(FreezerModule.class).isPlayerFrozen(ev.getPlayer())) { ev.setCancelled(true); } } - /** * Used to freeze the players. - * - * @param ev */ @EventHandler - public void onPlayerMove(PlayerMoveEvent ev) - { - p.getFreezer().freezePlayerIfNeeded(ev.getPlayer(), ev.getFrom(), ev.getTo()); + public void onPlayerMove(PlayerMoveEvent ev) { + QSG.module(FreezerModule.class).freezePlayerIfNeeded(ev.getPlayer(), ev.getFrom(), ev.getTo()); } - /** * Used to prevent the bows to be used while in global freeze mode. - * - * @param ev */ @EventHandler - public void onEntityShoot(EntityShootBowEvent ev) - { - if ((ev.getEntity() instanceof Player && p.getFreezer().isPlayerFrozen((Player) ev.getEntity())) - || p.getFreezer().getGlobalFreezeState()) - { - + public void onEntityShoot(EntityShootBowEvent ev) { + if ((ev.getEntity() instanceof Player && + QSG.module(FreezerModule.class).isPlayerFrozen((Player) ev.getEntity())) + || QSG.module(FreezerModule.class).getGlobalFreezeState()) { ev.setCancelled(true); // If a shoot from a player is cancelled, the arrow seems to be // consumed in the player' screen. // The inventory needs to be updated for the arrow to "come back". - if (ev.getEntity() instanceof Player) - { + if (ev.getEntity() instanceof Player) { ((Player) ev.getEntity()).updateInventory(); } } } - /** - * Used to prevent items from despawning if the game is frozen. - * - * @param ev + * Used to prevent items from de-spawning if the game is frozen. */ @EventHandler - public void onItemDespawn(ItemDespawnEvent ev) - { - if (p.getFreezer().getGlobalFreezeState()) - { + public void onItemDespawn(ItemDespawnEvent ev) { + if (QSG.module(FreezerModule.class).getGlobalFreezeState()) { ev.setCancelled(true); } } - /** * Used to freeze the mobs spawning while the game is frozen. - * @param ev */ @EventHandler - public void onEntitySpawn(CreatureSpawnEvent ev) - { - if (p.getFreezer().getGlobalFreezeState() && ev.getEntity() instanceof Creature) - { - p.getFreezer().freezeCreature((Creature) ev.getEntity(), true); + public void onEntitySpawn(CreatureSpawnEvent ev) { + if (QSG.module(FreezerModule.class).getGlobalFreezeState() && ev.getEntity() instanceof Creature) { + QSG.module(FreezerModule.class).freezeCreature((Creature) ev.getEntity(), true); } } - /** * Used to disable any damages if the player is frozen. - * - * @param ev */ @EventHandler - public void onEntityDamage(final EntityDamageEvent ev) - { - if (ev.getEntity() instanceof Player) - { - if (p.getFreezer().isPlayerFrozen((Player) ev.getEntity())) - { + public void onEntityDamage(final EntityDamageEvent ev) { + if (ev.getEntity() instanceof Player) { + if (QSG.module(FreezerModule.class).isPlayerFrozen((Player) ev.getEntity())) { ev.setCancelled(true); } } @@ -173,16 +129,11 @@ public void onEntityDamage(final EntityDamageEvent ev) /** * Used to cancel any food loss (but the players can still eat). - * - * @param ev */ @EventHandler - public void onFoodUpdate(FoodLevelChangeEvent ev) - { - if (p.getFreezer().isPlayerFrozen((Player) ev.getEntity())) - { - if (ev.getFoodLevel() < ((Player) ev.getEntity()).getFoodLevel()) - { + public void onFoodUpdate(FoodLevelChangeEvent ev) { + if (QSG.module(FreezerModule.class).isPlayerFrozen((Player) ev.getEntity())) { + if (ev.getFoodLevel() < ((Player) ev.getEntity()).getFoodLevel()) { ev.setCancelled(true); } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/misc/Freezer.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/freezer/FreezerModule.java similarity index 57% rename from src/main/java/eu/carrade/amaury/UHCReloaded/misc/Freezer.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/freezer/FreezerModule.java index 43ec706..5df4ca6 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/misc/Freezer.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/freezer/FreezerModule.java @@ -29,66 +29,103 @@ * 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.misc; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.listeners.FreezerListener; +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.freezer; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimersModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.core.QuartzLib; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; import org.bukkit.entity.Creature; import org.bukkit.entity.Player; -import org.bukkit.event.HandlerList; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.UUID; -import java.util.stream.Collectors; - - -public class Freezer -{ - private UHCReloaded p = null; +@ModuleInfo( + name = "Freezer", + description = "Provides a command to freeze some or all players, " + + "allowing to “pause” the game.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.UTILITIES, + icon = Material.PACKED_ICE +) +public class FreezerModule extends QSGModule { + private final Set<UUID> frozenPlayers = new HashSet<>(); + private final Map<UUID, Boolean> oldAllowFly = new HashMap<>(); + private final Map<UUID, Boolean> oldFlyMode = new HashMap<>(); private boolean isListenerRegistered = false; - private FreezerListener freezerListener = null; - - private Boolean globalFreeze = false; - private ArrayList<UUID> frozenPlayers = new ArrayList<>(); - private HashMap<UUID, Boolean> oldAllowFly = new HashMap<>(); - private HashMap<UUID, Boolean> oldFlyMode = new HashMap<>(); - + private FreezerListener freezerListener; + private boolean globalFreeze = false; private boolean hiddenFreeze = false; - public Freezer(UHCReloaded plugin) - { - this.p = plugin; - + @Override + public void onEnable() { this.freezerListener = new FreezerListener(); } + @Override + protected void onDisable() { + QuartzLib.unregisterEvents(freezerListener); + freezerListener = null; + } + + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(FreezeCommand.class); + } + + @Override + public void injectIntoSidebar(Player player, SidebarInjector injector) { + if (!hiddenFreeze) { + if (globalFreeze) { + /// Notice displayed at the bottom of the sidebar if the game is paused (/uh freeze all). + injector.injectLines(SidebarInjector.SidebarPriority.BOTTOM, true, I.t("{darkaqua}Game frozen")); + } else if (isPlayerFrozen(player)) { + injector.injectLines(SidebarInjector.SidebarPriority.BOTTOM, true, I.t("{darkaqua}You are frozen")); + } + } + } /** * Freezes a player, if needed. * The player is blocked inside the block he is currently. - * + * <p> * This method is intended to be executed when a player moves. * * @param player The player to freeze - * @param from The old position from the PlayerMoveEvent - * @param to The new position from the PlayerMoveEvent + * @param from The old position from the PlayerMoveEvent + * @param to The new position from the PlayerMoveEvent */ - public void freezePlayerIfNeeded(Player player, Location from, Location to) - { - if (frozenPlayers.contains(player.getUniqueId())) - { + public void freezePlayerIfNeeded(Player player, Location from, Location to) { + if (frozenPlayers.contains(player.getUniqueId())) { // If the X, Y or Z coordinate of the player change, he needs to be teleported inside the old block. // The yaw and pitch are conserved, to teleport more smoothly. - if (from.getBlockX() != to.getBlockX() || from.getBlockY() != to.getBlockY() || from.getBlockZ() != to.getBlockZ()) - { - player.teleport(new Location(from.getWorld(), from.getBlockX() + 0.5, from.getBlockY(), from.getBlockZ() + 0.5, to.getYaw(), to.getPitch()), TeleportCause.PLUGIN); + if (from.getBlockX() != to.getBlockX() || from.getBlockY() != to.getBlockY() || + from.getBlockZ() != to.getBlockZ()) { + player.teleport( + new Location(from.getWorld(), from.getBlockX() + 0.5, from.getBlockY(), from.getBlockZ() + 0.5, + to.getYaw(), to.getPitch()), TeleportCause.PLUGIN); } } } @@ -97,70 +134,60 @@ public void freezePlayerIfNeeded(Player player, Location from, Location to) /** * Enables or disables the global freeze of players, mobs, timer. * - * @param frozen If true the global freeze will be enabled. + * @param frozen If true the global freeze will be enabled. * @param showStateInScoreboard If false, the freeze state will not be displayed in the scoreboard. */ - public void setGlobalFreezeState(Boolean frozen, Boolean showStateInScoreboard) - { + public void setGlobalFreezeState(Boolean frozen, Boolean showStateInScoreboard) { this.globalFreeze = frozen; this.hiddenFreeze = !showStateInScoreboard; - if (frozen) - { - p.getGameManager() - .getOnlineAlivePlayers() - .forEach(player -> this.setPlayerFreezeState(player, true)); + if (frozen) { + QSG.game().getAlivePlayers().forEach(player -> setPlayerFreezeState(player, true)); // Freezes the mobs by applying a Slowness effect. There isn't any EntityMoveEvent, so... - p.getServer().getWorlds().stream() + QSG.get().getWorlds().stream() .flatMap(world -> world.getLivingEntities().stream()) .filter(entity -> entity instanceof Creature) .forEach(entity -> freezeCreature((Creature) entity, true)); // Freezes the timers. - p.getTimerManager().pauseAllRunning(true); - } - - else - { + QSG.module(TimersModule.class).pauseAllRunning(true); + } else { // All the online players are listed, not the internal list of frozen players, // to avoid a ConcurrentModificationException if the iterated list is being emptied. - p.getServer().getOnlinePlayers().stream() + QSG.game().getAlivePlayers().stream() .filter(this::isPlayerFrozen) .forEach(player -> this.setPlayerFreezeState(player, false)); // Removes the slowness effect - p.getServer().getWorlds().stream() + QSG.get().getWorlds().stream() .flatMap(world -> world.getLivingEntities().stream()) .filter(entity -> entity instanceof Creature) .forEach(entity -> freezeCreature((Creature) entity, false)); // Unfreezes the timers. - p.getTimerManager().pauseAllRunning(false); + QSG.module(TimersModule.class).pauseAllRunning(false); } updateListenerRegistration(); } /** - * Enables or disables the global freeze of players, mobs, timer. + * Returns the current state of the global freeze. * - * @param frozen If true the global freeze will be enabled. + * @return True if the global freeze is enabled. */ - public void setGlobalFreezeState(Boolean frozen) - { - setGlobalFreezeState(frozen, true); + public boolean getGlobalFreezeState() { + return this.globalFreeze; } - /** - * Returns the current state of the global freeze. + * Enables or disables the global freeze of players, mobs, timer. * - * @return True if the global freeze is enabled. + * @param frozen If true the global freeze will be enabled. */ - public boolean getGlobalFreezeState() - { - return this.globalFreeze; + public void setGlobalFreezeState(Boolean frozen) { + setGlobalFreezeState(frozen, true); } /** @@ -169,25 +196,26 @@ public boolean getGlobalFreezeState() * @param player The player to freeze. * @param frozen If true the player will be frozen. If false, unfrozen. */ - public void setPlayerFreezeState(Player player, Boolean frozen) - { - if (frozen && !this.frozenPlayers.contains(player.getUniqueId())) - { + public void setPlayerFreezeState(OfflinePlayer player, Boolean frozen) { + if (frozen && !frozenPlayers.contains(player.getUniqueId())) { this.frozenPlayers.add(player.getUniqueId()); - this.oldAllowFly.put(player.getUniqueId(), player.getAllowFlight()); - this.oldFlyMode.put(player.getUniqueId(), player.isFlying()); + this.oldAllowFly.put(player.getUniqueId(), player.isOnline() && player.getPlayer().getAllowFlight()); + this.oldFlyMode.put(player.getUniqueId(), player.isOnline() && player.getPlayer().isFlying()); // Used to prevent the player to be kicked for fly if he was frozen during a fall. // He is blocked inside his current block anyway. - player.setAllowFlight(true); + if (player.isOnline()) { + player.getPlayer().setAllowFlight(true); + } } - if (!frozen && this.frozenPlayers.contains(player.getUniqueId())) - { + if (!frozen && frozenPlayers.contains(player.getUniqueId())) { this.frozenPlayers.remove(player.getUniqueId()); - player.setFlying(this.oldFlyMode.get(player.getUniqueId())); - player.setAllowFlight(this.oldAllowFly.get(player.getUniqueId())); + if (player.isOnline()) { + player.getPlayer().setFlying(oldFlyMode.get(player.getUniqueId())); + player.getPlayer().setAllowFlight(oldAllowFly.get(player.getUniqueId())); + } this.oldAllowFly.remove(player.getUniqueId()); this.oldFlyMode.remove(player.getUniqueId()); @@ -202,36 +230,21 @@ public void setPlayerFreezeState(Player player, Boolean frozen) * @param player The player to be checked. * @return true if the given player is frozen. */ - public boolean isPlayerFrozen(Player player) - { + public boolean isPlayerFrozen(final OfflinePlayer player) { return frozenPlayers.contains(player.getUniqueId()); } - /** - * Returns {@code true} if the current freeze must be hidden in the sidebar. - * - * @return {@code true} to hide it. - */ - public boolean isHiddenFreeze() - { - return hiddenFreeze; - } - /** * (Un)freezes a creature. * * @param creature The creature to freeze. - * @param frozen If true the creature will be frozen. Else... + * @param frozen If true the creature will be frozen. Else... */ - public void freezeCreature(Creature creature, Boolean frozen) - { - if (frozen) - { + public void freezeCreature(final Creature creature, final boolean frozen) { + if (frozen) { // Freezes the creature for about 68 years. creature.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, Integer.MAX_VALUE, 100, true)); - } - else - { + } else { creature.removePotionEffect(PotionEffectType.SLOW); } } @@ -239,29 +252,24 @@ public void freezeCreature(Creature creature, Boolean frozen) /** * Registers the listener if it wasn't registered, and unregisters this listener * if there isn't any frozen player. - * + * <p> * Call this AFTER registering the first frozen player, and AFTER unregistering * the last one. */ - private void updateListenerRegistration() - { + private void updateListenerRegistration() { // Registers the listener if needed // (i.e if there isn't any frozen player, or if the global freeze is enabled). - if (!this.isListenerRegistered) - { - if (!this.frozenPlayers.isEmpty() || this.getGlobalFreezeState()) - { - p.getServer().getPluginManager().registerEvents(freezerListener, p); + if (!this.isListenerRegistered) { + if (!this.frozenPlayers.isEmpty() || this.getGlobalFreezeState()) { + QuartzLib.registerEvents(freezerListener); this.isListenerRegistered = true; } } // Unregisters the listener if needed - else - { - if (this.frozenPlayers.isEmpty() && !this.getGlobalFreezeState()) - { - HandlerList.unregisterAll(freezerListener); + else { + if (this.frozenPlayers.isEmpty() && !this.getGlobalFreezeState()) { + QuartzLib.unregisterEvents(freezerListener); this.isListenerRegistered = false; } } @@ -273,11 +281,7 @@ private void updateListenerRegistration() * * @return The list. */ - public ArrayList<Player> getFrozenPlayers() - { - - return frozenPlayers.stream() - .map(id -> p.getServer().getPlayer(id)) - .collect(Collectors.toCollection(ArrayList::new)); + public Set<OfflinePlayer> getFrozenPlayers() { + return frozenPlayers.stream().map(Bukkit::getOfflinePlayer).collect(Collectors.toSet()); } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/health/HealthModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/health/HealthModule.java new file mode 100644 index 0000000..4099650 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/health/HealthModule.java @@ -0,0 +1,61 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.health; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.health.commands.HealAllCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.health.commands.HealCommand; +import fr.zcraft.quartzlib.components.commands.Command; +import java.util.Arrays; +import java.util.List; +import org.bukkit.Material; + + +@ModuleInfo( + name = "Health Commands", + description = "Provides commands to update health of some or all players.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.UTILITIES, + icon = Material.GOLDEN_APPLE +) +public class HealthModule extends QSGModule { + @Override + public List<Class<? extends Command>> getCommands() { + return Arrays.asList(HealCommand.class, HealAllCommand.class); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/health/commands/HealAllCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/health/commands/HealAllCommand.java new file mode 100644 index 0000000..75840ee --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/health/commands/HealAllCommand.java @@ -0,0 +1,104 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.health.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.teams.TeamsModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + + +@CommandInfo(name = "heal-all", usageParameters = "[half-hearts=20|±diff]", aliases = {"healall"}) +public class HealAllCommand extends Command { + @Override + protected void run() throws CommandException { + double diffHealth; + boolean add = false; // "add" (±, true) or "raw" (exact health, false) mode + + // /uh heal-all: full life for player. + if (args.length == 0) { + diffHealth = Integer.MAX_VALUE; + } + + // /uh heal-all <hearts> + else { + try { + if (args[0].startsWith("+") || args[0].startsWith("-")) { + add = true; + } + + diffHealth = Double.parseDouble(args[0]); + } + catch (final NumberFormatException e) { + throwInvalidArgument(I.t("{ce}Hey, this is not a number of half-hearts. It's a text. Pfff.")); + return; + } + } + + if (!add && diffHealth <= 0) { + error(I.t("{ce}Serial killer!")); + } + + for (final Player player : Bukkit.getServer().getOnlinePlayers()) { + double health = !add ? diffHealth : player.getHealth() + diffHealth; + + if (health <= 0D) { + warning(I.t("{ce}The health of {0} was not updated to avoid a kill.", player.getName())); + continue; + } else if (health > player.getMaxHealth()) { + health = player.getMaxHealth(); + } + + player.setHealth(health); + QSG.module(TeamsModule.class).getSidebarPlayerCache(player.getUniqueId()).updateHealth(health); + } + + if (!add) { + if (diffHealth == Integer.MAX_VALUE) { + success(I.t("The health of all players was completely filled.", diffHealth)); + } else { + success(I.t("The health of all players was set to {0}.", diffHealth)); + } + } else if (diffHealth > 0) { + success(I.t("The health of all players was increased by {0}.", diffHealth)); + } else { + success(I.t("The health of all players was decreased by {0}.", -diffHealth)); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/health/commands/HealCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/health/commands/HealCommand.java new file mode 100644 index 0000000..497c741 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/health/commands/HealCommand.java @@ -0,0 +1,107 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.health.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.teams.TeamsModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.List; +import org.bukkit.entity.Player; + + +@CommandInfo(name = "heal", usageParameters = "<player> [half-hearts=20|±diff]", aliases = {"life", "set-health", + "sethealth"}) +public class HealCommand extends Command { + @Override + protected void run() throws CommandException { + if (args.length == 0) { + throwInvalidArgument(I.t("A player is required")); + } + + final Player target = getPlayerParameter(0); + + double health; + boolean add = false; // "add" (±, true) or "raw" (exact health, false) mode + + // /uh heal <player> : full life for player. + if (args.length == 1) { + health = 20D; + } + + // /uh heal <player> <hearts> + else { + double diffHealth; + + try { + if (args[1].startsWith("+") || args[1].startsWith("-")) { + add = true; + } + + diffHealth = Double.parseDouble(args[1]); + } + catch (final NumberFormatException e) { + throwInvalidArgument(I.t("{ce}Hey, this is not a number of half-hearts. It's a text. Pfff.")); + return; + } + + health = !add ? diffHealth : target.getHealth() + diffHealth; + + if (health <= 0D) { + error(I.t("{ce}You can't kill a player with this command, to avoid typo fails.")); + } else if (health > 20D) { + health = 20D; + } + } + + target.setHealth(health); + + // TODO Could we get rid of this hard reference? + QSG.module(TeamsModule.class).getSidebarPlayerCache(target.getUniqueId()).updateHealth(health); + + success(I.t("The health of {0} was set to {1}.", target.getName(), health)); + } + + @Override + protected List<String> complete() { + if (args.length == 1) { + return getMatchingPlayerNames(args[0]); + } else { + return null; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/playersLoader/LoadPlayersCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/playersLoader/LoadPlayersCommand.java new file mode 100644 index 0000000..1d847d4 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/playersLoader/LoadPlayersCommand.java @@ -0,0 +1,82 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.playersLoader; + +import eu.carrade.amaury.quartzsurvivalgames.utils.OfflinePlayersLoader; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.Arrays; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; + +@CommandInfo( + name = "load-players", + usageParameters = "<player1> [player2] [player3] […]", + aliases = {"loadplayers", "load-player", "loadplayer"} +) +public class LoadPlayersCommand extends Command { + @Override + protected void run() { + if (!Bukkit.getOnlineMode()) { + sender.sendMessage(I.t("{ce}You cannot load unknown players in offline mode, sorry.")); + return; + } + + if (args.length == 0) { + /// Error returned if one calls /uh loadplayers without arguments. + sender.sendMessage(I.t("{ce}You need to provide at least one player name.")); + return; + } + + /// Message displayed when the /uh loadplayers command is used, as the execution may take some time. + info(I.t("{cst}Loading players...")); + + final CommandSender fSender = sender; + + OfflinePlayersLoader.loadPlayers( + Arrays.asList(args), + addedPlayers -> fSender.sendMessage( + I.tn("{cs}Loaded {0} player successfully.", "{cs}Loaded {0} players successfully.", + addedPlayers.size())), + notFound -> { + /// Message sent if some players cannot be loaded while /uh loadplayers is used. 0 = amount of players missing; 1 = list of nicknames (format "nick1, nick2, nick3"). + fSender.sendMessage(I.tn("{ce}{0} player is missing: {1}.", "{ce}{0} players are missing: {1}.", + notFound.size(), notFound.size(), StringUtils.join(notFound, ", "))); + } + ); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/playersLoader/PlayersLoaderModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/playersLoader/PlayersLoaderModule.java new file mode 100644 index 0000000..ed00109 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/playersLoader/PlayersLoaderModule.java @@ -0,0 +1,58 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.playersLoader; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import fr.zcraft.quartzlib.components.commands.Command; +import java.util.Collections; +import java.util.List; +import org.bukkit.Material; + +@ModuleInfo( + name = "Players Loader", + description = + "Loads player into the server even if they never came before, so you can add them to teams and such. " + + "An interface to the built-in players loader.", + category = ModuleCategory.UTILITIES, + icon = Material.PLAYER_HEAD +) +public class PlayersLoaderModule extends QSGModule { + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(LoadPlayersCommand.class); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/rules/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/rules/Config.java new file mode 100644 index 0000000..17e99a0 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/rules/Config.java @@ -0,0 +1,58 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.rules; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.list; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.section; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.configuration.ConfigurationList; +import fr.zcraft.quartzlib.components.configuration.ConfigurationSection; +import java.io.File; + +public class Config extends ConfigurationInstance { + public static final DisplaySection DISPLAY = section("display", DisplaySection.class); + public static final ConfigurationList<String> RULES = list("rules", String.class); + + public Config(File file) { + super(file); + } + + static public class DisplaySection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ON_JOIN = item("on-join", false); + public final ConfigurationItem<Boolean> ON_START = item("on-start", true); + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHRulesCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/rules/RulesCommand.java similarity index 50% rename from src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHRulesCommand.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/rules/RulesCommand.java index 83b8688..f48287c 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHRulesCommand.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/rules/RulesCommand.java @@ -29,83 +29,51 @@ * 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.commands.commands.uh; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.commands.commands.categories.Category; -import eu.carrade.amaury.UHCReloaded.commands.core.AbstractCommand; -import eu.carrade.amaury.UHCReloaded.commands.core.annotations.Command; -import eu.carrade.amaury.UHCReloaded.commands.core.exceptions.CannotExecuteCommandException; -import fr.zcraft.zlib.components.i18n.I; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.rules; -import java.util.Collections; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; import java.util.List; +import java.util.Optional; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; -@Command (name = "rules") -public class UHRulesCommand extends AbstractCommand -{ - private UHCReloaded p; - - public UHRulesCommand(UHCReloaded plugin) - { - p = plugin; - } - - - @Override - public void run(CommandSender sender, String[] args) throws CannotExecuteCommandException - { - if (!p.getRulesManager().isEnabled()) - { - sender.sendMessage(I.t("{ce}No rules are set in the config file.")); - return; +@CommandInfo(name = "rules", usageParameters = "[player]") +public class RulesCommand extends Command { + public void run() throws CommandException { + if (!QSG.module(RulesModule.class).hasRules()) { + error(I.t("{ce}No rules are set in the config file.")); } - if (args.length >= 1) - { - Player player = Bukkit.getPlayer(args[0]); - if (player != null) - { - p.getRulesManager().displayRulesTo(player); + if (args.length >= 1) { + final Optional<? extends Player> player = Bukkit.getOnlinePlayers().stream() + .filter(onlinePlayer -> onlinePlayer.getName().equalsIgnoreCase(args[0].trim())) + .findAny(); - if (!sender.equals(player)) - sender.sendMessage(I.t("{cs}Rules sent to {0}.", player.getName())); - } - else - { + if (player.isPresent()) { + QSG.module(RulesModule.class).displayRulesTo(player.get()); + + if (!sender.equals(player.get())) { + sender.sendMessage(I.t("{cs}Rules sent to {0}.", player.get().getName())); + } + } else { sender.sendMessage(I.t("{ce}Cannot display the rules to {0} because he (or she) is offline.", args[0])); } + } else { + QSG.module(RulesModule.class).broadcastRules(); } - else - { - p.getRulesManager().broadcastRules(); - } - } - - @Override - public List<String> tabComplete(CommandSender sender, String[] args) - { - return null; } @Override - public List<String> help(CommandSender sender) - { - return null; - } - - @Override - public List<String> onListHelp(CommandSender sender) - { - return Collections.singletonList(I.t("{cc}/uh rules [player] {ci}: sends the server rules to the server or the given player.")); - } - - @Override - public String getCategory() - { - return Category.MISC.getTitle(); + public List<String> complete() { + if (args.length == 1) { + return getMatchingPlayerNames(args[0]); + } else { + return null; + } } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/misc/RulesManager.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/rules/RulesModule.java similarity index 53% rename from src/main/java/eu/carrade/amaury/UHCReloaded/misc/RulesManager.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/rules/RulesModule.java index a6797f4..a87ffc5 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/misc/RulesManager.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/rules/RulesModule.java @@ -29,81 +29,77 @@ * 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.misc; -import eu.carrade.amaury.UHCReloaded.UHConfig; -import eu.carrade.amaury.UHCReloaded.commands.core.utils.CommandUtils; -import fr.zcraft.zlib.components.i18n.I; +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.rules; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.CommandUtils; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.Material; import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.List; - - -public class RulesManager -{ - private final boolean DISPLAY_ON_JOIN; - private final boolean DISPLAY_ON_START; - +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; + +@ModuleInfo( + name = "Rules", + description = "Displays configured game rules when the game start or the " + + "players join", + when = ModuleLoadTime.POST_WORLD, + category = ModuleCategory.UTILITIES, + icon = Material.BOOKSHELF, + settings = Config.class +) +public class RulesModule extends QSGModule { private final List<String> rules = new ArrayList<>(); - - public RulesManager() - { - if (UHConfig.RULES.isDefined() && !UHConfig.RULES.RULES.isEmpty() ) - { - DISPLAY_ON_JOIN = UHConfig.RULES.DISPLAY.ON_JOIN.get(); - DISPLAY_ON_START = UHConfig.RULES.DISPLAY.ON_START.get(); - - + @Override + public void onEnable() { + if (Config.RULES.isDefined() && !Config.RULES.isEmpty()) { // We check if the list is non-empty, i.e. if there is at least a non-empty rule. boolean empty = true; - for (String rule : UHConfig.RULES.RULES) - { - if (rule == null) continue; + for (final String rule : Config.RULES) { + if (rule == null) { + continue; + } - rule = rule.trim(); - rules.add(ChatColor.translateAlternateColorCodes('&',rule)); + rules.add(ChatColor.translateAlternateColorCodes('&', rule.trim())); - if (!rule.isEmpty()) + if (!rule.isEmpty()) { empty = false; + } } // If the list is empty, no rules are displayed. We reset the list. - if (empty) rules.clear(); - } - else - { - DISPLAY_ON_JOIN = false; - DISPLAY_ON_START = true; + if (empty) { + rules.clear(); + } } } - /** - * @return {@code true} if the rules system is enabled - */ - public boolean isEnabled() - { - return rules.size() != 0; - } - - /** - * @return {@code true} if the rules have to be displayed to every joining player. - */ - public boolean displayOnJoin() - { - return isEnabled() && DISPLAY_ON_JOIN; + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(RulesCommand.class); } /** - * @return {@code true} if the rules have to be displayed when the game starts. + * @return {@code true} if the rules system is enabled */ - public boolean displayOnStart() - { - return isEnabled() && DISPLAY_ON_START; + public boolean hasRules() { + return rules.size() != 0; } @@ -112,21 +108,16 @@ public boolean displayOnStart() * * @param receiver The receiver. */ - public void displayRulesTo(CommandSender receiver) - { + public void displayRulesTo(CommandSender receiver) { CommandUtils.displaySeparator(receiver); /// Title of the rules box. receiver.sendMessage(I.t("{red}{bold}Rules and informations")); - for (String rule : rules) - { - if (rule.isEmpty()) - { + for (String rule : rules) { + if (rule.isEmpty()) { receiver.sendMessage(""); - } - else - { + } else { /// Rule item in the rule box. receiver.sendMessage(I.t("{darkgray}- {reset}{0}", rule)); } @@ -138,9 +129,27 @@ public void displayRulesTo(CommandSender receiver) /** * Broadcasts the rules to the whole server. */ - public void broadcastRules() - { + public void broadcastRules() { Bukkit.getOnlinePlayers().forEach(this::displayRulesTo); displayRulesTo(Bukkit.getConsoleSender()); } + + @EventHandler + public void onPlayerJoin(final PlayerJoinEvent ev) { + if (QSG.game().getPhase() == GamePhase.WAIT && hasRules() && Config.DISPLAY.ON_JOIN.get()) { + RunTask.later(() -> { + if (ev.getPlayer().isOnline()) { + displayRulesTo(ev.getPlayer()); + } + }, 100L); + } + } + + @EventHandler + public void onGameStart(final GamePhaseChangedEvent ev) { + if (ev.getNewPhase() == GamePhase.IN_GAME && ev.isRunningForward() && hasRules() && + Config.DISPLAY.ON_START.get()) { + RunTask.later(this::broadcastRules, 200L); + } + } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/runtimeCommandsExecutor/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/runtimeCommandsExecutor/Config.java new file mode 100644 index 0000000..c72a278 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/runtimeCommandsExecutor/Config.java @@ -0,0 +1,52 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.runtimeCommandsExecutor; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.list; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationList; +import java.io.File; +import java.util.Map; + +public class Config extends ConfigurationInstance { + public final static ConfigurationList<Map> WAIT = list("wait", Map.class); + public final static ConfigurationList<Map> STARTING = list("starting", Map.class); + public final static ConfigurationList<Map> IN_GAME = list("in-game", Map.class); + public final static ConfigurationList<Map> END = list("end", Map.class); + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/runtimeCommandsExecutor/RuntimeCommandsExecutor.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/runtimeCommandsExecutor/RuntimeCommandsExecutor.java new file mode 100644 index 0000000..b9269e8 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/runtimeCommandsExecutor/RuntimeCommandsExecutor.java @@ -0,0 +1,319 @@ +/* + * 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.quartzsurvivalgames.modules.utilities.runtimeCommandsExecutor; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import fr.zcraft.quartzlib.components.configuration.ConfigurationList; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.scheduler.BukkitTask; + + +/** + * This will execute the commands to be executed during runtime, as configured in the config file + * or added through the API. + */ +@ModuleInfo( + name = "Runtime Commands Executor", + description = "Executes commands during runtime, at specific times of the game, automatically. " + + "This is a powerful tool to schedule any command at any time relative to the game progression.", + when = ModuleLoadTime.STARTUP, + category = ModuleCategory.UTILITIES, + icon = Material.COMMAND_BLOCK, + settings = Config.class +) +public class RuntimeCommandsExecutor extends QSGModule { + /** + * Stores the commands to be executed later. + * <p> + * The first map (String->HashMap) associates a key to a group of commands launched at the same time.<br> + * The sub-map (Integer->HashSet) associates a delay, in seconds, with a set containing the commands to be + * executed this number of seconds after the call of the {@link #runCommands(String)} + * method. + */ + private final Map<String, HashMap<Integer, HashSet<String>>> scheduled = new HashMap<>(); + + /** + * Stores the running tasks, to be able to cancel them. + */ + private final Map<String, Set<BukkitTask>> runningTasks = new HashMap<>(); + + + /** + * Register the commands registered under the given key in the Bukkit' scheduler. + * <p> + * Delays are from the execution of this method. + * + * @param key The key to schedule. All commands previously registered under this key will be executed. + */ + public void runCommands(final String key) { + runCommands(key, scheduled.get(key)); + } + + /** + * Register the commands registered under the given phase in the Bukkit' scheduler. + * <p> + * Delays are from the execution of this method. + * + * @param phase The phase to schedule. All commands previously registered under this phase will be executed. + */ + public void runCommands(final GamePhase phase) { + runCommands(getPhaseKey(phase)); + } + + /** + * Register the given commands in the Bukkit' scheduler. + * <p> + * Delays are from the execution of this method. + * + * @param key The key to store the tasks under. + * @param scheduledCommands The commands to schedule + */ + private void runCommands(final String key, final Map<Integer, HashSet<String>> scheduledCommands) { + if (scheduledCommands != null) { + final Set<BukkitTask> tasks = runningTasks.computeIfAbsent(key, k -> new HashSet<>()); + for (Entry<Integer, HashSet<String>> scheduledCommandsStack : scheduledCommands.entrySet()) { + tasks.add(RunTask.later( + new ScheduledCommandsExecutorTask(scheduledCommandsStack.getValue()), + scheduledCommandsStack.getKey() * 20L + )); + } + } + } + + + /** + * Cancels all tasks currently running for the given key. + * + * @param key The key. + */ + public void cancelTasks(final String key) { + if (runningTasks.containsKey(key)) { + runningTasks.get(key).forEach(BukkitTask::cancel); + runningTasks.get(key).clear(); + } + } + + /** + * Cancels all tasks currently running for the given phase. + * + * @param phase The phase. + */ + public void cancelTasks(final GamePhase phase) { + cancelTasks(getPhaseKey(phase)); + } + + /** + * Schedules a command. + * <p> + * Commands scheduled with any non-standard key will not be executed automatically. You'll have + * to call {@link #runCommands(String)} to schedule them. + * + * @param key The command will be stored under this key. + * @param command The command to add. + * @param delay The delay. + * @see #scheduleCommand(GamePhase, String, TimeDelta) to schedule a command from one game phase change. + */ + public void scheduleCommand(final String key, final String command, final TimeDelta delay) { + final Map<Integer, HashSet<String>> commandsMap = scheduled.computeIfAbsent(key, k -> new HashMap<>()); + scheduleCommand(commandsMap, command, delay); + } + + /** + * Schedule a command to be run when the given phase starts. + * + * @param phase The phase + * @param command The command to execute + * @param delay The delay after the phase's beginning. + */ + public void scheduleCommand(final GamePhase phase, String command, final TimeDelta delay) { + scheduleCommand(getPhaseKey(phase), command, delay); + } + + /** + * Schedules a command. + * + * @param scheduledCommands A map containing the scheduled commands, sorted by delay. + * @param command The command to add. + * @param delay The delay (seconds). + */ + private void scheduleCommand(Map<Integer, HashSet<String>> scheduledCommands, String command, TimeDelta delay) { + final Set<String> list = scheduledCommands.computeIfAbsent((int) delay.getSeconds(), k -> new HashSet<>()); + list.add(clearCommandName(command)); + } + + + /** + * Removes the given command from everywhere. + * + * @param key The command will be stored under this key. + * @param command The command. Not case-sensitive. + */ + public void removeScheduledCommand(String key, String command) { + removeScheduledCommand(scheduled.get(key), command); + } + + /** + * Removes the given command from everywhere. + * + * @param scheduledCommands A map containing the scheduled commands, sorted by delay. + * @param command The command. Not case-sensitive. + */ + private void removeScheduledCommand(Map<Integer, HashSet<String>> scheduledCommands, String command) { + for (HashSet<String> commands : scheduledCommands.values()) { + for (String scheduledCommand : new HashSet<>(commands)) { + if (scheduledCommand.equalsIgnoreCase(clearCommandName(command))) { + commands.remove(scheduledCommand); + } + } + } + } + + + /** + * Removes the given command from everywhere. + * + * @param key The key the command was registered under. + * @param command The command. Not case-sensitive. + */ + public void removeScheduledCommand(String key, String command, TimeDelta delay) { + removeScheduledCommand(scheduled.get(key), command, delay); + } + + /** + * Removes the given command from everywhere. + * + * @param phase The phase the command was registered under. + * @param command The command. Not case-sensitive. + */ + public void removeScheduledCommand(GamePhase phase, String command, TimeDelta delay) { + removeScheduledCommand(getPhaseKey(phase), command, delay); + } + + /** + * Removes the given command from everywhere. + * + * @param scheduledCommands A map containing the scheduled commands, sorted by delay. + * @param command The command. Not case-sensitive. + */ + private void removeScheduledCommand(Map<Integer, HashSet<String>> scheduledCommands, String command, + TimeDelta delay) { + HashSet<String> commands = scheduledCommands.get(((int) delay.getSeconds())); + + if (commands != null) { + commands.stream() + .filter(scheduledCommand -> scheduledCommand.equalsIgnoreCase(clearCommandName(command))) + .forEach(commands::remove); + } + } + + + /* Utilities */ + + + private String clearCommandName(String command) { + if (command.startsWith("/")) { + command = command.substring(1); + } + + return command; + } + + private String getPhaseKey(final GamePhase phase) { + return "internal." + phase.name().toLowerCase().replace('_', '-'); + } + + + /* Events to launch tasks */ + + @EventHandler + protected void onGamePhaseChanged(final GamePhaseChangedEvent ev) { + if (!ev.isRunningForward()) { + cancelTasks(ev.getNewPhase()); + return; + } + + // We load the commands to run + final ConfigurationList<Map> commands; + + switch (ev.getNewPhase()) { + case WAIT: + commands = Config.WAIT; + break; + case STARTING: + commands = Config.STARTING; + break; + case IN_GAME: + commands = Config.IN_GAME; + break; + case END: + commands = Config.END; + break; + default: + return; + } + + commands.stream() + .filter(command -> command.containsKey("exec") && !command.get("exec").toString().isEmpty()) + .forEach(command -> { + try { + scheduleCommand(ev.getNewPhase(), command.get("exec").toString(), + new TimeDelta(command.get("delay").toString())); + } + catch (IllegalArgumentException e) { + PluginLogger.error( + "Invalid delay “{0}” in scheduled command “{1}” for phase {2}", + command.get("delay").toString(), + command.get("exec").toString(), + ev.getNewPhase() + ); + } + }); + + // And we schedule all of them. + runCommands(ev.getNewPhase()); + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/task/ScheduledCommandsExecutorTask.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/runtimeCommandsExecutor/ScheduledCommandsExecutorTask.java similarity index 81% rename from src/main/java/eu/carrade/amaury/UHCReloaded/task/ScheduledCommandsExecutorTask.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/runtimeCommandsExecutor/ScheduledCommandsExecutorTask.java index e6bf661..47a9ca4 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/task/ScheduledCommandsExecutorTask.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/runtimeCommandsExecutor/ScheduledCommandsExecutorTask.java @@ -30,40 +30,33 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.task; - -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import fr.zcraft.zlib.tools.PluginLogger; -import org.bukkit.command.CommandException; +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.runtimeCommandsExecutor; +import eu.carrade.amaury.quartzsurvivalgames.QuartzSurvivalGames; +import fr.zcraft.quartzlib.tools.PluginLogger; import java.util.HashSet; +import org.bukkit.command.CommandException; /** * Schedules a stack of commands executed at the same time. */ -public class ScheduledCommandsExecutorTask implements Runnable -{ - private final UHCReloaded p; +public class ScheduledCommandsExecutorTask implements Runnable { + private final QuartzSurvivalGames p; private final HashSet<String> commands; - public ScheduledCommandsExecutorTask(HashSet<String> commands) - { - this.p = UHCReloaded.get(); + public ScheduledCommandsExecutorTask(HashSet<String> commands) { + this.p = QuartzSurvivalGames.get(); this.commands = commands; } @Override - public void run() - { - for (final String command : commands) - { - try - { + public void run() { + for (final String command : commands) { + try { p.getServer().dispatchCommand(p.getServer().getConsoleSender(), command); } - catch (CommandException e) - { + catch (CommandException e) { PluginLogger.error("The scheduled command '{0}' failed.", e, command); } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/TeleportationModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/TeleportationModule.java new file mode 100644 index 0000000..c11f659 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/TeleportationModule.java @@ -0,0 +1,90 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.teleportation; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.players.AlivePlayerDeathEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.teleportation.commands.TPDeathCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.teleportation.commands.TPSpawnCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.teleportation.commands.TPSpectatorsCommand; +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.teleportation.commands.TPTeamCommand; +import fr.zcraft.quartzlib.components.commands.Command; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.event.EventHandler; + + +@ModuleInfo( + name = "Teleportation Commands", + description = "Provides commands to teleport to spawn, death location, or groups of players.", + category = ModuleCategory.UTILITIES, + icon = Material.COMMAND_BLOCK_MINECART +) +public class TeleportationModule extends QSGModule { + private final Map<UUID, Location> deathLocations = new HashMap<>(); + + @Override + public List<Class<? extends Command>> getCommands() { + return Arrays.asList( + TPDeathCommand.class, + TPSpawnCommand.class, + TPTeamCommand.class, + TPSpectatorsCommand.class + ); + } + + @EventHandler + public void onPlayerDeath(final AlivePlayerDeathEvent ev) { + if (ev.getPlayer().isOnline()) { + deathLocations.put(ev.getPlayer().getUniqueId(), ev.getPlayer().getPlayer().getLocation()); + } + } + + public boolean hasDeathLocation(final OfflinePlayer player) { + return deathLocations.containsKey(player.getUniqueId()); + } + + public Location getDeathLocation(final OfflinePlayer player) { + return deathLocations.get(player.getUniqueId()).clone(); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/TPDeathCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/TPDeathCommand.java new file mode 100644 index 0000000..44c75c0 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/TPDeathCommand.java @@ -0,0 +1,91 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.teleportation.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.teleportation.TeleportationModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.List; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +@CommandInfo(name = "tp-death", usageParameters = "[player] [force]", aliases = {"tpback", "tpdeath", "tpd"}) +public class TPDeathCommand extends Command { + @Override + protected void run() throws CommandException { + final Player player = args.length > 0 ? getPlayerParameter(0) : playerSender(); + final boolean force = args.length > 1 && args[1].equalsIgnoreCase("force"); + + if (!QSG.module(TeleportationModule.class).hasDeathLocation(player)) { + error(I.t("{ce}No death location available for the player {0}.", player.getName())); + } + + final Location deathLocation = QSG.module(TeleportationModule.class).getDeathLocation(player); + + if (force) { + QSGUtils.safeTP(player, deathLocation, true); + success(I.t("{cs}The player {0} was teleported back.", player.getName())); + } else if (QSGUtils.safeTP(player, deathLocation)) { + success(I.t("{cs}The player {0} was teleported back.", player.getName())); + } else { + warning(I + .t("{ce}The player {0} was NOT teleported back because no safe spot was found.", player.getName())); + warning(I.t("{ci}Use {cc}/uh tpback {0} force{ci} to teleport the player regardless this point.", + player.getName())); + } + } + + @Override + protected List<String> complete() { + if (args.length == 1) { + final TeleportationModule tm = QSG.module(TeleportationModule.class); + + return getMatchingPlayerNames( + Bukkit.getOnlinePlayers().stream().filter(tm::hasDeathLocation).collect(Collectors.toList()), + args[0] + ); + } else if (args.length == 2) { + return getMatchingSubset(args[1].toLowerCase(), "force"); + } else { + return null; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/TPSpawnCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/TPSpawnCommand.java new file mode 100644 index 0000000..b03d36d --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/TPSpawnCommand.java @@ -0,0 +1,103 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.teleportation.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.teleporter.Teleporter; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.List; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +@CommandInfo(name = "tp-spawn", usageParameters = "<player> [force]", aliases = {"tpspawn"}) +public class TPSpawnCommand extends Command { + @Override + protected void run() throws CommandException { + final Teleporter teleporter = QSG.module(GameModule.class).getTeleporter(); + + if (teleporter == null) { + error(I.t("{ce}The spawn points are not already assigned to the player, because the game is not started.")); + return; + } + + final Player player = args.length > 0 ? getPlayerParameter(0) : playerSender(); + final boolean force = args.length > 1 && args[1].equalsIgnoreCase("force"); + final Location spawnLocation = teleporter.getSpawnForPlayer(player.getUniqueId()); + + if (spawnLocation == null) { + error(I.t("{ce}No spawn location available for the player {0}.", player.getName())); + return; + } + + if (force) { + teleporter.teleportPlayer(player.getUniqueId(), true); + success(I.t("{cs}The player {0} was teleported to his spawn location.", player.getName())); + } else if (QSGUtils.safeTP(player, spawnLocation)) { + success(I.t("{cs}The player {0} was teleported to his spawn location.", player.getName())); + } else { + warning(I.t("{ce}The player {0} was NOT teleported to his spawn because no safe spot was found.", + player.getName())); + warning(I.t("{ci}Use {cc}/uh tpspawn {0} force{ci} to teleport the player regardless this point.", + player.getName())); + } + } + + @Override + protected List<String> complete() { + final Teleporter teleporter = QSG.module(GameModule.class).getTeleporter(); + + if (teleporter == null) { + return null; + } else if (args.length == 1) { + return getMatchingPlayerNames( + Bukkit.getOnlinePlayers().stream() + .filter(player -> teleporter.hasSpawnForPlayer(player.getUniqueId())) + .collect(Collectors.toList()), + args[0] + ); + } else if (args.length == 2) { + return getMatchingSubset(args[1].toLowerCase(), "force"); + } else { + return null; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/TPSpectatorsCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/TPSpectatorsCommand.java new file mode 100644 index 0000000..5a6a5cf --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/TPSpectatorsCommand.java @@ -0,0 +1,100 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.teleportation.commands; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.spectators.SpectatorsModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.List; +import java.util.Objects; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + +@CommandInfo(name = "tp-spectators", usageParameters = "<x> <y> <z> | <target>", aliases = {"tpspectators", "tp-specs", + "tpspecs"}) +public class TPSpectatorsCommand extends WorldBasedCommand { + @Override + protected void run() throws CommandException { + final SpectatorsModule spectators = QSG.module(SpectatorsModule.class); + + // /uh tp-spectators <x> <y> <z> + if (args.length == 3) { + try { + final World world = getTargetWorld(); + + final double x = Integer.parseInt(args[0]) + 0.5; + final double y = Integer.parseInt(args[1]) + 0.5; + final double z = Integer.parseInt(args[2]) + 0.5; + + spectators.getSpectators().stream() + .map(Bukkit::getPlayer).filter(Objects::nonNull) + .forEach(spectator -> spectator.teleport(new Location(world, x, y, z), TeleportCause.PLUGIN)); + + /// {0}: world name. {1-3}: x, y, z. + success(I.t("All spectators were teleported to ({0} ; {1} ; {2} ; {3}).", world.getName(), x, y, z)); + } + catch (final NumberFormatException e) { + throwInvalidArgument(I.t("{ce}The coordinates must be three valid numbers.")); + } + } + + // /uh tp-spectators <target> + else if (args.length == 1) { + final Player target = getPlayerParameter(0); + + spectators.getSpectators().stream() + .map(Bukkit::getPlayer).filter(Objects::nonNull) + .forEach(spectator -> spectator.teleport(target, TeleportCause.PLUGIN)); + + success(I.t("All spectators were teleported to the player {0}.", target.getName())); + } else { + throwInvalidArgument(I.t("You must specify either three coordinates or a player name.")); + } + } + + @Override + protected List<String> complete() { + if (args.length == 1) { + return getMatchingPlayerNames(args[0]); + } else { + return null; + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/TPTeamCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/TPTeamCommand.java new file mode 100644 index 0000000..caa40d3 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/TPTeamCommand.java @@ -0,0 +1,109 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.teleportation.commands; + +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzteams.QuartzTeam; +import fr.zcraft.quartzteams.QuartzTeams; +import fr.zcraft.quartzteams.texts.TextUtils; +import java.util.stream.Collectors; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.entity.Player; + +@CommandInfo(name = "tp-team", usageParameters = "<x> <y> <z> \"<team name>\" | <target> \"<team name>\"", aliases = { + "tpteam", "tpt"}) +public class TPTeamCommand extends WorldBasedCommand { + @Override + protected void run() throws CommandException { + final String[] qargs = TextUtils.extractArgsWithQuotes(args, 0); + + // possibly /uh tp-team <x> <y> <z> "<team ...>" + if (qargs.length == 4) { + final QuartzTeam team = QuartzTeams.get().getTeamByName(qargs[3]); + + // ok, the team exists. + if (team != null) { + try { + final World world = getTargetWorld(); + + final double x = Integer.parseInt(args[0]) + 0.5; + final double y = Integer.parseInt(args[1]) + 0.5; + final double z = Integer.parseInt(args[2]) + 0.5; + + team.teleportTo(new Location(world, x, y, z)); + + /// {1}: players names, comma-separated. {2}: world name. {3-5}: x, y, z. + success(I.t( + "The players in the team {0} ({1}) were teleported to ({2} ; {3} ; {4} ; {5}).", + team.getName(), + String.join(", ", + team.getPlayers().stream().map(OfflinePlayer::getName).collect(Collectors.toSet())), + world.getName(), x, y, z + )); + + return; + } + catch (NumberFormatException e) { + throwInvalidArgument(I.t("{ce}The coordinates must be three valid numbers.")); + } + } + } + + // /uh tp team <target> "<team ...>" + if (qargs.length == 2) { + final QuartzTeam team = QuartzTeams.get().getTeamByName(qargs[1]); + + if (team == null) { + throwInvalidArgument(I.t("{ce}This team is not registered.")); + } else { + final Player player = getPlayerParameter(0); + team.teleportTo(player.getLocation()); + + /// {1}: players names, comma-separated. + success(I.t( + "The players in the team {0} ({1}) were teleported to the player {2}.", + team.getName(), + String.join(", ", + team.getPlayers().stream().map(OfflinePlayer::getName).collect(Collectors.toSet())), + player.getName() + )); + } + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/WorldBasedCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/WorldBasedCommand.java new file mode 100644 index 0000000..0a53899 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/teleportation/commands/WorldBasedCommand.java @@ -0,0 +1,53 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.teleportation.commands; + +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import org.bukkit.World; +import org.bukkit.command.BlockCommandSender; +import org.bukkit.entity.Player; + +public abstract class WorldBasedCommand extends Command { + protected World getTargetWorld() { + if (sender instanceof Player) { + return ((Player) sender).getWorld(); + } else if (sender instanceof BlockCommandSender) { + return ((BlockCommandSender) sender).getBlock().getWorld(); + } else { + return QSG.get().getWorld(World.Environment.NORMAL); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/Config.java new file mode 100644 index 0000000..480dae8 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/Config.java @@ -0,0 +1,58 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.section; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.configuration.ConfigurationSection; +import java.io.File; +import org.bukkit.Material; + +public class Config extends ConfigurationInstance { + public static final ConfigurationItem<Integer> HEIGHT = item("height", 128); + public static final BlockSection BLOCK = section("block", BlockSection.class); + + public Config(File file) { + super(file); + } + + static public class BlockSection extends ConfigurationSection { + public final ConfigurationItem<Material> REPLACE_AIR = item("replace-air", Material.GLASS); + public final ConfigurationItem<Material> REPLACE_SOLID = item("replace-solid", Material.BEDROCK); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/WallsCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/WallsCommand.java new file mode 100644 index 0000000..c29984e --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/WallsCommand.java @@ -0,0 +1,82 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls; + +import eu.carrade.amaury.quartzsurvivalgames.QuartzSurvivalGames; +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls.exceptions.CannotGenerateWallsException; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import org.bukkit.World; +import org.bukkit.command.BlockCommandSender; +import org.bukkit.entity.Player; + +@CommandInfo(name = "build-walls", aliases = {"buildwalls", "generate-walls", "generatewalls"}) +public class WallsCommand extends Command { + @Override + protected void run() throws CommandException { + info(I.t("{cst}Generating the walls...")); + + final World world; + + if (sender instanceof Player) { + world = ((Player) sender).getWorld(); + } else if (sender instanceof BlockCommandSender) { + world = ((BlockCommandSender) sender).getBlock().getWorld(); + } else { + world = QuartzSurvivalGames.get().getWorld(World.Environment.NORMAL); + info(I.t("{ci}From the console, generating the walls of the default world, {0}", world.getName())); + } + + try { + QSG.module(WallsModule.class).generateWalls(world); + } + catch (CannotGenerateWallsException e) { + error(I.t( + "{ce}Unable to generate the wall: see logs for details. The blocks set in the config are probably invalid.")); + return; + + } + catch (Exception e) { + error(I.t("{ce}An error occurred, see console for details.")); + e.printStackTrace(); + return; + } + + success(I.t("{cst}Generation done.")); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/WallsModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/WallsModule.java new file mode 100644 index 0000000..ac06ec1 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/WallsModule.java @@ -0,0 +1,99 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.BorderModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls.exceptions.CannotGenerateWallsException; +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls.exceptions.UnknownWallGenerator; +import eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls.generators.WallGenerator; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import java.util.Collections; +import java.util.List; +import org.bukkit.Material; +import org.bukkit.World; + + +@ModuleInfo( + name = "Walls Generator", + description = "Provides a command to generate a solid wall around the arena.", + when = ModuleLoadTime.POST_WORLD, + category = ModuleCategory.UTILITIES, + icon = Material.BARRIER, + settings = Config.class +) +public class WallsModule extends QSGModule { + private BorderModule borderModule; + + @Override + protected void onEnable() { + borderModule = QSG.module(BorderModule.class); + } + + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(WallsCommand.class); + } + + /** + * Generates the walls in the given world, following the current border configuration. + * + * @param world The world were the walls will be built in. + * @throws CannotGenerateWallsException If an error occurred while generating the wall. + */ + public void generateWalls(final World world) throws CannotGenerateWallsException { + final Integer wallHeight = Config.HEIGHT.get(); + + final Material wallBlockAir = Config.BLOCK.REPLACE_AIR.get(); + final Material wallBlockSolid = Config.BLOCK.REPLACE_SOLID.get(); + + if (wallBlockAir == null || !wallBlockAir.isSolid() || wallBlockSolid == null || !wallBlockSolid.isSolid()) { + throw new CannotGenerateWallsException("Cannot generate the walls: invalid blocks set in the config"); + } + + final WallGenerator generator = + WallGenerator.fromShape(borderModule.getMapShape(), wallBlockAir, wallBlockSolid); + + if (generator != null) { + generator.build(world, borderModule.getCurrentBorderDiameter(), wallHeight); + } else { + throw new UnknownWallGenerator("Unable to load walls generator."); + } + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/exceptions/CannotGenerateWallsException.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/exceptions/CannotGenerateWallsException.java similarity index 88% rename from src/main/java/eu/carrade/amaury/UHCReloaded/borders/exceptions/CannotGenerateWallsException.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/exceptions/CannotGenerateWallsException.java index 3407022..1cc1216 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/exceptions/CannotGenerateWallsException.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/exceptions/CannotGenerateWallsException.java @@ -29,12 +29,11 @@ * 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.borders.exceptions; -public class CannotGenerateWallsException extends Exception -{ - public CannotGenerateWallsException(String message) - { +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls.exceptions; + +public class CannotGenerateWallsException extends Exception { + public CannotGenerateWallsException(String message) { super(message); } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/exceptions/UnknownWallGenerator.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/exceptions/UnknownWallGenerator.java similarity index 88% rename from src/main/java/eu/carrade/amaury/UHCReloaded/borders/exceptions/UnknownWallGenerator.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/exceptions/UnknownWallGenerator.java index 9dadeee..001284b 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/exceptions/UnknownWallGenerator.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/exceptions/UnknownWallGenerator.java @@ -29,12 +29,11 @@ * 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.borders.exceptions; -public class UnknownWallGenerator extends Exception -{ - public UnknownWallGenerator(String message) - { +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls.exceptions; + +public class UnknownWallGenerator extends CannotGenerateWallsException { + public UnknownWallGenerator(String message) { super(message); } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/generators/CircularWallGenerator.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/generators/CircularWallGenerator.java similarity index 86% rename from src/main/java/eu/carrade/amaury/UHCReloaded/borders/generators/CircularWallGenerator.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/generators/CircularWallGenerator.java index a652e1b..720457c 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/generators/CircularWallGenerator.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/generators/CircularWallGenerator.java @@ -29,17 +29,16 @@ * 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.borders.generators; + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls.generators; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; -public class CircularWallGenerator extends WallGenerator -{ - public CircularWallGenerator(Material wallBlockAir, Material wallBlockSolid) - { +public class CircularWallGenerator extends WallGenerator { + public CircularWallGenerator(Material wallBlockAir, Material wallBlockSolid) { super(wallBlockAir, wallBlockSolid); } @@ -51,8 +50,7 @@ public CircularWallGenerator(Material wallBlockAir, Material wallBlockSolid) * @param wallHeight The height of the wall. */ @Override - public void build(World world, int diameter, int wallHeight) - { + public void build(World world, int diameter, int wallHeight) { // Only one quarter of the circle is explicitly set, the other parts are generated // following the first quarter. // The quarter chosen to be explicitly generated if the one on the South-East, @@ -76,16 +74,14 @@ public void build(World world, int diameter, int wallHeight) Block candidate3; // Infinite loop broken when the generation is done. - while (true) - { + while (true) { // 1) the current point, the symmetries and the opposite point are built. this.buildWallPoint(world, currentBlock.getX(), currentBlock.getZ(), wallHeight, diameter); // 2) the two candidates are found, except if the build is finished. - if (currentBlock.getX() == xSpawn) - { + if (currentBlock.getX() == xSpawn) { // END break; } @@ -96,22 +92,23 @@ public void build(World world, int diameter, int wallHeight) // 3) The good block is selected - Double distanceCandidate1ToRef = Math.abs((candidate1.getLocation().distance(world.getSpawnLocation()) - radius)); - Double distanceCandidate2ToRef = Math.abs((candidate2.getLocation().distance(world.getSpawnLocation()) - radius)); - Double distanceCandidate3ToRef = Math.abs((candidate3.getLocation().distance(world.getSpawnLocation()) - radius)); + Double distanceCandidate1ToRef = + Math.abs((candidate1.getLocation().distance(world.getSpawnLocation()) - radius)); + Double distanceCandidate2ToRef = + Math.abs((candidate2.getLocation().distance(world.getSpawnLocation()) - radius)); + Double distanceCandidate3ToRef = + Math.abs((candidate3.getLocation().distance(world.getSpawnLocation()) - radius)); // The first is better - if (distanceCandidate1ToRef < distanceCandidate2ToRef && distanceCandidate1ToRef < distanceCandidate3ToRef) - { + if (distanceCandidate1ToRef < distanceCandidate2ToRef && + distanceCandidate1ToRef < distanceCandidate3ToRef) { currentBlock = candidate1; } // The second is better - else if (distanceCandidate2ToRef < distanceCandidate1ToRef && distanceCandidate2ToRef < distanceCandidate3ToRef) - { + else if (distanceCandidate2ToRef < distanceCandidate1ToRef && + distanceCandidate2ToRef < distanceCandidate3ToRef) { currentBlock = candidate2; - } - else - { + } else { currentBlock = candidate3; } } @@ -128,8 +125,7 @@ else if (distanceCandidate2ToRef < distanceCandidate1ToRef && distanceCandidate2 * @param wallHeight * @param diameter */ - private void buildWallPoint(World world, int x, int z, int wallHeight, int diameter) - { + private void buildWallPoint(World world, int x, int z, int wallHeight, int diameter) { WallPosition positionOriginal; WallPosition positionSymmetricX; WallPosition positionSymmetricZ; @@ -147,15 +143,12 @@ private void buildWallPoint(World world, int x, int z, int wallHeight, int diame // Following the way the wall is generated, the position of the original // "tower" can only be « SOUTH » or « EAST ». - if (z > Math.floor(diameter / 2)) - { + if (z > Math.floor(diameter / 2)) { positionOriginal = WallPosition.SOUTH; positionSymmetricX = WallPosition.SOUTH; positionSymmetricZ = WallPosition.NORTH; positionOpposite = WallPosition.NORTH; - } - else - { + } else { positionOriginal = WallPosition.EAST; positionSymmetricX = WallPosition.WEST; positionSymmetricZ = WallPosition.EAST; @@ -163,8 +156,7 @@ private void buildWallPoint(World world, int x, int z, int wallHeight, int diame } // The 4 towers are built. - for (int y = 1; y <= wallHeight; y++) - { + for (int y = 1; y <= wallHeight; y++) { setBlock(world.getBlockAt(x, y, z), positionOriginal); setBlock(world.getBlockAt(x - 2 * (x - xSpawn), y, z), positionSymmetricX); setBlock(world.getBlockAt(x, y, z + 2 * (zSpawn - z)), positionSymmetricZ); diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/generators/SquaredWallGenerator.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/generators/SquaredWallGenerator.java similarity index 88% rename from src/main/java/eu/carrade/amaury/UHCReloaded/borders/generators/SquaredWallGenerator.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/generators/SquaredWallGenerator.java index d3f1106..afba7e4 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/generators/SquaredWallGenerator.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/generators/SquaredWallGenerator.java @@ -29,16 +29,15 @@ * 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.borders.generators; + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls.generators; import org.bukkit.Material; import org.bukkit.World; -public class SquaredWallGenerator extends WallGenerator -{ - public SquaredWallGenerator(Material wallBlockAir, Material wallBlockSolid) - { +public class SquaredWallGenerator extends WallGenerator { + public SquaredWallGenerator(Material wallBlockAir, Material wallBlockSolid) { super(wallBlockAir, wallBlockSolid); } @@ -50,8 +49,7 @@ public SquaredWallGenerator(Material wallBlockAir, Material wallBlockSolid) * @param wallHeight The height of the wall. */ @Override - public void build(World world, int diameter, int wallHeight) - { + public void build(World world, int diameter, int wallHeight) { final int halfDiameter = (int) Math.floor(diameter / 2); final int limitXInf = world.getSpawnLocation().add(-halfDiameter, 0, 0).getBlockX(); @@ -59,25 +57,21 @@ public void build(World world, int diameter, int wallHeight) final int limitZInf = world.getSpawnLocation().add(0, 0, -halfDiameter).getBlockZ(); final int limitZSup = world.getSpawnLocation().add(0, 0, halfDiameter).getBlockZ(); - for (int x = limitXInf; x <= limitXSup; x++) - { + for (int x = limitXInf; x <= limitXSup; x++) { world.getBlockAt(x, 1, limitZInf).setType(Material.BEDROCK); world.getBlockAt(x, 1, limitZSup).setType(Material.BEDROCK); - for (int y = 2; y <= wallHeight; y++) - { + for (int y = 2; y <= wallHeight; y++) { setBlock(world.getBlockAt(x, y, limitZInf), WallPosition.NORTH); setBlock(world.getBlockAt(x, y, limitZSup), WallPosition.SOUTH); } } - for (int z = limitZInf + 1; z <= limitZSup - 1; z++) - { + for (int z = limitZInf + 1; z <= limitZSup - 1; z++) { world.getBlockAt(limitXInf, 1, z).setType(Material.BEDROCK); world.getBlockAt(limitXSup, 1, z).setType(Material.BEDROCK); - for (int y = 2; y <= wallHeight; y++) - { + for (int y = 2; y <= wallHeight; y++) { setBlock(world.getBlockAt(limitXInf, y, z), WallPosition.WEST); setBlock(world.getBlockAt(limitXSup, y, z), WallPosition.EAST); } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/generators/WallGenerator.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/generators/WallGenerator.java similarity index 67% rename from src/main/java/eu/carrade/amaury/UHCReloaded/borders/generators/WallGenerator.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/generators/WallGenerator.java index fbd9a30..fe1ab04 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/generators/WallGenerator.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/generators/WallGenerator.java @@ -30,26 +30,49 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.borders.generators; +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls.generators; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.MapShape; +import org.apache.commons.lang3.Validate; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; -public abstract class WallGenerator -{ +public abstract class WallGenerator { final private Material wallBlockAir; final private Material wallBlockSolid; private int blocksSet = 0; - public WallGenerator(Material wallBlockAir, Material wallBlockSolid) - { - this.wallBlockAir = wallBlockAir; - this.wallBlockSolid = wallBlockSolid; + public WallGenerator(Material wallBlockAir, Material wallBlockSolid) { + this.wallBlockAir = wallBlockAir != null ? wallBlockAir : Material.GLASS; + this.wallBlockSolid = wallBlockSolid != null ? wallBlockSolid : Material.BEDROCK; } + /** + * Returns a new instance of the wall generator for the given shape. + * + * @param shape The shape. + * @param wallBlockAir The block to use to replace air. + * @param wallBlockSolid The block to use to replace solid blocks. + * @return The instance. + * @see WallGenerator#WallGenerator(Material, Material) + */ + public static WallGenerator fromShape(final MapShape shape, final Material wallBlockAir, + final Material wallBlockSolid) { + Validate.notNull(shape, "Map shape must not be null."); + + switch (shape) { + case CIRCULAR: + return new CircularWallGenerator(wallBlockAir, wallBlockSolid); + + case SQUARED: + return new SquaredWallGenerator(wallBlockAir, wallBlockSolid); + } + + return null; + } /** * Builds a wall in the world. @@ -60,33 +83,26 @@ public WallGenerator(Material wallBlockAir, Material wallBlockSolid) */ public abstract void build(World world, int diameter, int wallHeight); - /** * Sets a block according to his environment. * If the block replaces a "air/tree" block, or if it is next to a transparent block, it needs to be a * "wall.block.replaceAir" block. * In all other cases, it needs to be a "wall.block.replaceSolid" one. * - * @param block The block to set. + * @param block The block to set. * @param position The position of the current wall in the world */ - protected void setBlock(Block block, WallPosition position) - { + protected void setBlock(Block block, WallPosition position) { // The block is a transparent block or a tree - if (isBlockTransparentOrNatural(block.getType())) - { + if (isBlockTransparentOrNatural(block.getType())) { block.setType(wallBlockAir); } // We set the block according to the block near it inside the border. - else - { + else { final Material innerMaterial = getInnerBlock(block, position).getType(); - if (isBlockTransparentOrNatural(innerMaterial)) - { + if (isBlockTransparentOrNatural(innerMaterial)) { block.setType(wallBlockAir); - } - else - { + } else { block.setType(wallBlockSolid); } } @@ -101,51 +117,37 @@ protected void setBlock(Block block, WallPosition position) * @return boolean True if the block is transparent, or part of a tree/a giant mushroom/a * generated structure/etc. */ - protected Boolean isBlockTransparentOrNatural(Material blockType) - { - if (blockType.isTransparent()) - { + protected Boolean isBlockTransparentOrNatural(Material blockType) { + if (blockType.isTransparent()) { return true; } - switch (blockType) - { + switch (blockType) { + // TODO re-add stained glass, stained glass pane, logs, leaves, beds, signs, fences + // Low priority as this is mostly unused anyway, with vanilla world border. case GLASS: // The glass isn't a transparent block for the `isTransparent` method. - case STAINED_GLASS: - case THIN_GLASS: - case STAINED_GLASS_PANE: - case LEAVES: - case LEAVES_2: - case LOG: - case LOG_2: case CHEST: // Avoid a cube of the solid block where there where a chest. case TRAPPED_CHEST: case ENDER_CHEST: case WATER: - case STATIONARY_WATER: - case BED_BLOCK: - case PISTON_STICKY_BASE: // Same idea (in jungle temples). - case PISTON_BASE: + case STICKY_PISTON: // Same idea (in jungle temples). + case PISTON: + case PISTON_HEAD: case BOOKSHELF: // Same idea (in villages & fortresses). - case MOB_SPAWNER: // Same idea (in dungeons). - case SIGN_POST: - case WALL_SIGN: + case SPAWNER: // Same idea (in dungeons). case ICE: // Same idea (in cold biomes). case PACKED_ICE: case CACTUS: // Same idea (in deserts) - case FENCE: - case FENCE_GATE: - case IRON_FENCE: - case NETHER_FENCE: case PUMPKIN: - case MELON_BLOCK: // Same idea (in jungles) + case MELON: // Same idea (in jungles) case GLOWSTONE: // Same idea (in the Nether - why not?) case JACK_O_LANTERN: - case HUGE_MUSHROOM_1: // Same idea (in dark forests). - case HUGE_MUSHROOM_2: - case CAKE_BLOCK: // It may be a lie, but hey, why not. + case BROWN_MUSHROOM_BLOCK: // Same idea (in dark forests). + case RED_MUSHROOM_BLOCK: + case MUSHROOM_STEM: + case CAKE: // It may be a lie, but hey, why not. case BEACON: - case COBBLE_WALL: + case COBBLESTONE_WALL: case ANVIL: return true; default: @@ -156,19 +158,17 @@ protected Boolean isBlockTransparentOrNatural(Material blockType) /** * Gets the block left to the given block inside the border. * - * @param block The reference block. + * @param block The reference block. * @param position The position of the wall currently build. */ - protected Block getInnerBlock(Block block, WallPosition position) - { + protected Block getInnerBlock(Block block, WallPosition position) { // Just for readability. final World world = block.getWorld(); final int x = block.getX(); final int y = block.getY(); final int z = block.getZ(); - switch (position) - { + switch (position) { case EAST: return world.getBlockAt(x - 1, y, z); case NORTH: @@ -182,8 +182,7 @@ protected Block getInnerBlock(Block block, WallPosition position) } } - public int getBlocksSet() - { + public int getBlocksSet() { return blocksSet; } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/generators/WallPosition.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/generators/WallPosition.java similarity index 93% rename from src/main/java/eu/carrade/amaury/UHCReloaded/borders/generators/WallPosition.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/generators/WallPosition.java index 1d6cab6..d0be294 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/borders/generators/WallPosition.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/walls/generators/WallPosition.java @@ -30,18 +30,17 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.borders.generators; +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.walls.generators; /** * Used to determine in witch wall we are, to get the "inner" block. - * + * <p> * North: small Z * South: big Z * East: big X * West: small X */ -public enum WallPosition -{ +public enum WallPosition { NORTH, SOUTH, EAST, diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/task/BorderWarningTask.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/warning/BorderWarningTask.java similarity index 56% rename from src/main/java/eu/carrade/amaury/UHCReloaded/task/BorderWarningTask.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/warning/BorderWarningTask.java index 0df8262..1a2c4e4 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/task/BorderWarningTask.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/warning/BorderWarningTask.java @@ -29,47 +29,44 @@ * 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.task; -import eu.carrade.amaury.UHCReloaded.UHCReloaded; -import eu.carrade.amaury.UHCReloaded.borders.MapShape; -import fr.zcraft.zlib.components.i18n.I; +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.warning; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.BorderModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.MapShape; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.i18n.I; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; -public class BorderWarningTask extends BukkitRunnable -{ - private final UHCReloaded p; - - public BorderWarningTask() - { - this.p = UHCReloaded.get(); - } +public class BorderWarningTask extends BukkitRunnable { + private final BorderModule borderModule = QSG.module(BorderModule.class); + private final WarningModule warningModule = QSG.module(WarningModule.class); @Override - public void run() - { - if (p.getFreezer().getGlobalFreezeState()) - { - return; // No messages are sent if the game is frozen. - } + public void run() { +// final FreezerModule freezer = UR.module(FreezerModule.class); +// if (freezer != null && freezer.getGlobalFreezeState()) +// { +// return; // No messages are sent if the game is frozen. +// } // Message sent to all players outside the border - for (Player player : p.getBorderManager().getPlayersOutside(p.getBorderManager().getWarningSize())) - { - double distance = p.getBorderManager().getDistanceToBorder(player.getLocation(), p.getBorderManager().getWarningSize()); + for (Player player : borderModule.getPlayersOutside(warningModule.getWarningSize())) { + double distance = borderModule.getDistanceToBorder(player.getLocation(), warningModule.getWarningSize()); - if (p.getBorderManager().getMapShape() == MapShape.CIRCULAR) - { - player.sendMessage(I.tn("{ce}You are currently out of the future border (diameter of {0} block).", "{ce}You are currently out of the future border (diameter of {0} blocks).", p.getBorderManager().getWarningSize())); - } - else - { - player.sendMessage(I.t("{ce}You are currently out of the future border of {0}×{0} blocks.", p.getBorderManager().getWarningSize())); + if (borderModule.getMapShape() == MapShape.CIRCULAR) { + player.sendMessage(I.tn("{ce}You are currently out of the future border (diameter of {0} block).", + "{ce}You are currently out of the future border (diameter of {0} blocks).", + warningModule.getWarningSize())); + } else { + player.sendMessage(I.t("{ce}You are currently out of the future border of {0}×{0} blocks.", + warningModule.getWarningSize())); } - player.sendMessage(I.tn("{ci}You have {0} block to go before being inside.", "{ci}You have {0} blocks to go before being inside.", (int) distance)); + player.sendMessage(I.tn("{ci}You have {0} block to go before being inside.", + "{ci}You have {0} blocks to go before being inside.", (int) distance)); } } } diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/warning/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/warning/Config.java new file mode 100644 index 0000000..e24b77c --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/warning/Config.java @@ -0,0 +1,51 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.warning; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import java.io.File; + +public class Config extends ConfigurationInstance { + public static final ConfigurationItem<TimeDelta> WARNING_INTERVAL = + item("warning-interval", new TimeDelta(0, 1, 30)); + + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/warning/WarningCommand.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/warning/WarningCommand.java new file mode 100644 index 0000000..0f1f76d --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/warning/WarningCommand.java @@ -0,0 +1,96 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.warning; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.commands.CommandException; +import fr.zcraft.quartzlib.components.commands.CommandInfo; +import fr.zcraft.quartzlib.components.i18n.I; +import java.util.List; + +@CommandInfo( + name = "border-warning", + usageParameters = "<future border size | cancel> [time delta (minutes or mm:ss or hh:mm:ss) until border reduction]", + aliases = {"borderwarning", "borderwarn", "bw"} +) +public class WarningCommand extends Command { + @Override + protected void run() throws CommandException { + final WarningModule warnings = QSG.module(WarningModule.class); + + // /uh border warning + if (args.length == 0) { + throwInvalidArgument(I.t("Missing future border size.")); + } + + // /uh border warning cancel + else if (args[0].equalsIgnoreCase("cancel")) { + warnings.cancelWarning(); + success(I.t("{cs}Warning canceled.")); + } + + // /uh border warning <?> + // or + // /uh border warning <?> <?> + else { + try { + final int warnDiameter = Integer.parseInt(args[0]); + TimeDelta warnTime = null; + + // /uh border warning <?> <?> + if (args.length >= 2) { + warnTime = new TimeDelta(args[1]); + } + + warnings.setWarningSize(warnDiameter, warnTime, sender); + success(I + .tn("{cs}Future size saved. All players outside this future border will be warned every {0} second.", + "{cs}Future size saved. All players outside this future border will be warned every {0} seconds.", + (int) Config.WARNING_INTERVAL.get().getSeconds())); + + } + catch (NumberFormatException e) { + error(I.t("{ce}“{0}” is not a number...", args[0])); + } + } + } + + @Override + protected List<String> complete() throws CommandException { + return args.length == 1 ? getMatchingSubset(args[0], "cancel") : null; + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/warning/WarningModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/warning/WarningModule.java new file mode 100644 index 0000000..24e6188 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/utilities/warning/WarningModule.java @@ -0,0 +1,190 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.utilities.warning; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.border.events.BorderChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.Timer; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimersModule; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import fr.zcraft.quartzlib.components.commands.Command; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import java.util.Collections; +import java.util.List; +import org.bukkit.Material; +import org.bukkit.command.CommandSender; +import org.bukkit.event.EventHandler; +import org.bukkit.scheduler.BukkitRunnable; + +@ModuleInfo( + name = "Border Warning", + description = "Warns players about the future border size.", + when = ModuleLoadTime.ON_GAME_START, + category = ModuleCategory.UTILITIES, + icon = Material.NETHER_BRICK_FENCE, + settings = Config.class +) +public class WarningModule extends QSGModule { + + private Integer warningSize = 0; + private BukkitRunnable warningTask = null; + + private final Boolean warningFinalTimeEnabled = false; + private Timer warningTimer = null; + private String warningTimerName = null; + private CommandSender warningSender = null; + + + @Override + protected void onEnable() { + /// The name of the warning timer displaying the time left before the next border + warningTimerName = I.t("Border shrinking"); + } + + @Override + protected void onDisable() { + cancelWarning(); + } + + @Override + public List<Class<? extends Command>> getCommands() { + return Collections.singletonList(WarningCommand.class); + } + + /** + * Returns the size of the future border, used in the warning messages sent to the + * players out of this future border. + * + * @return the future border diameter. + */ + public int getWarningSize() { + return this.warningSize; + } + + /** + * Sets the size of the future border, used in the warning messages sent to the + * players out of this future border. + * <p> + * This also starts the display of the warning messages, every 90 seconds by default + * (configurable, see config.yml, map.border.warningInterval). + * + * @param diameter The diameter of the future border. + */ + public void setWarningSize(final int diameter) { + setWarningSize(diameter, null, null); + } + + /** + * @return true if there is currently a warning with a time left displayed. + */ + public boolean getWarningFinalTimeEnabled() { + return this.warningFinalTimeEnabled; + } + + /** + * @return the sender of the last warning configured. + */ + public CommandSender getWarningSender() { + return this.warningSender; + } + + /** + * Sets the size of the future border, used in the warning messages sent to the + * players out of this future border. + * <p> + * This also starts the display of the warning messages, every 90 seconds by default + * (configurable, see config.yml, map.border.warningInterval). + * <p> + * If timeLeft is not null, the time available for the players to go inside the future + * border is displayed in the warning message. + * + * @param diameter The future diameter. + * @param timeLeft The time available for the players to go inside the future border. + * @param sender The user who requested this change. + */ + public void setWarningSize(final int diameter, final TimeDelta timeLeft, final CommandSender sender) { + cancelWarning(); + + this.warningSize = diameter; + + if (timeLeft != null) { + warningTimer = new Timer(this.warningTimerName); + warningTimer.setDuration((int) timeLeft.getSeconds()); + + QSG.module(TimersModule.class).registerTimer(warningTimer); + + warningTimer.start(); + } + + if (sender != null) { + this.warningSender = sender; + } + + RunTask.timer( + warningTask = new BorderWarningTask(), + 20L, + 20L * Config.WARNING_INTERVAL.get().getSeconds() + ); + } + + /** + * Stops the display of the warning messages. + */ + public void cancelWarning() { + if (warningTask != null) { + try { + warningTask.cancel(); + } + catch (IllegalStateException ignored) { + } + } + + if (warningTimer != null) { + warningTimer.stop(); + QSG.module(TimersModule.class).unregisterTimer(warningTimer); + } + } + + + @EventHandler + public void onBorderChanged(final BorderChangedEvent ev) { + cancelWarning(); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/waitingPhase/wait/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/waitingPhase/wait/Config.java new file mode 100644 index 0000000..f4cb530 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/waitingPhase/wait/Config.java @@ -0,0 +1,74 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.waitingPhase.wait; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.item; +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.section; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationItem; +import fr.zcraft.quartzlib.components.configuration.ConfigurationSection; +import java.io.File; +import org.bukkit.Material; + +public class Config extends ConfigurationInstance { + static public final ConfigurationItem<Boolean> TELEPORT_TO_SPAWN_IF_NOT_STARTED = + item("teleport-to-spawn-if-not-started", true); + public static final InventorySection INVENTORY = section("inventory", InventorySection.class); + public static final TeamSelectorSection TEAM_SELECTOR = section("teams-selector", TeamSelectorSection.class); + public static final ConfigAccessorSection CONFIG_ACCESSOR = section("config-accessor", ConfigAccessorSection.class); + public static final ConfigurationItem<Boolean> TEAM_IN_ACTION_BAR = item("team-in-action-bar", true); + public static final ConfigurationItem<Boolean> ENABLE_PVP = item("enable-pvp", false); + + public Config(File file) { + super(file); + } + + static public class InventorySection extends ConfigurationSection { + public final ConfigurationItem<Boolean> CLEAR = item("clear", true); + public final ConfigurationItem<Boolean> PREVENT_USAGE = item("prevent-usage", true); + public final ConfigurationItem<Boolean> ALLOW_FOR_BUILDERS = item("allow-for-builders", true); + } + + static public class TeamSelectorSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ENABLED = item("enabled", true); + public final ConfigurationItem<Material> ITEM = item("item", Material.NETHER_STAR); + } + + static public class ConfigAccessorSection extends ConfigurationSection { + public final ConfigurationItem<Boolean> ENABLED = item("enabled", true); + public final ConfigurationItem<Material> ITEM = item("item", Material.COMPARATOR); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/waitingPhase/wait/WaitModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/waitingPhase/wait/WaitModule.java new file mode 100644 index 0000000..bb26c07 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/waitingPhase/wait/WaitModule.java @@ -0,0 +1,534 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.waitingPhase.wait; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GamePhase; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.events.game.GamePhaseChangedEvent; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.modules.gui.MainConfigGUI; +import eu.carrade.amaury.quartzsurvivalgames.shortcuts.QSG; +import eu.carrade.amaury.quartzsurvivalgames.utils.EntitiesUtils; +import eu.carrade.amaury.quartzsurvivalgames.utils.QSGUtils; +import fr.zcraft.quartzlib.components.attributes.Attribute; +import fr.zcraft.quartzlib.components.attributes.Attributes; +import fr.zcraft.quartzlib.components.gui.Gui; +import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.core.QuartzLib; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.items.ItemStackBuilder; +import fr.zcraft.quartzlib.tools.reflection.NMSException; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import fr.zcraft.quartzlib.tools.text.ActionBar; +import fr.zcraft.quartzteams.QuartzTeam; +import fr.zcraft.quartzteams.QuartzTeams; +import fr.zcraft.quartzteams.events.PlayerJoinedTeamEvent; +import fr.zcraft.quartzteams.events.PlayerLeftTeamEvent; +import fr.zcraft.quartzteams.events.TeamUnregisteredEvent; +import fr.zcraft.quartzteams.events.TeamUpdatedEvent; +import fr.zcraft.quartzteams.guis.TeamsSelectorGUI; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.permissions.Permissible; +import org.bukkit.scheduler.BukkitTask; + + +@ModuleInfo( + name = "Waiting phase", + description = "Manages the waiting phase: inventory, effects, modes, teleportation, etc.", + category = ModuleCategory.WAITING_PHASE, + icon = Material.CLOCK, + settings = Config.class, + can_be_loaded_late = false +) +public class WaitModule extends QSGModule { + private final static UUID ACTIONABLE_ITEM_UUID = UUID.fromString("3f65c4a9-e1ae-437e-b8b4-57d80a831480"); + + private final Map<UUID, String> playerInventoriesStates = new HashMap<>(); + private BukkitTask inventoriesUpdateTask = null; + + @Override + protected void onEnable() { + Bukkit.getOnlinePlayers().forEach(this::handleNewPlayer); + + inventoriesUpdateTask = RunTask.timer(() -> Bukkit.getOnlinePlayers().forEach(this::updateInventory), 20L, 20L); + } + + @Override + protected void onDisable() { + if (inventoriesUpdateTask != null) { + inventoriesUpdateTask.cancel(); + inventoriesUpdateTask = null; + } + } + + /** + * Writes an action into an Item Stack. + * + * @param item The item. This must be a CraftItemStack. + * @param action The action to store. + * @see #readAction(ItemStack) to read a previously stored action. + */ + private void writeAction(final ItemStack item, final String action) { + final Attribute attribute = new Attribute(); + + attribute.setUUID(ACTIONABLE_ITEM_UUID); + attribute.setCustomData(action); + + try { + Attributes.set(item, attribute); + } + catch (final NMSException e) { + PluginLogger + .error("Unable to store item action into attribute. Inventory tools won't work before the game."); + } + } + + /** + * Reads an action previously written into this ItemStack. + * + * @param item The item. + * @return The action, or en empty string if nothing stored. + * @see #writeAction(ItemStack, String) to write an action. + */ + private String readAction(final ItemStack item) { + try { + final Attribute attribute = Attributes.get(item, ACTIONABLE_ITEM_UUID); + return attribute != null && attribute.getCustomData() != null ? attribute.getCustomData() : ""; + } + catch (NMSException ignored) { + return ""; + } + } + + /** + * Opens the teams selector GUI, if needed (enabled, game not started, needed item). + * + * @param player The player who right-clicked an item. + * @param item The right-clicked item. + */ + private boolean openGUI(Player player, ItemStack item) { + if (isGameStarted() || item == null) { + return false; + } + + switch (readAction(item)) { + case "teams": + Gui.open(player, new TeamsSelectorGUI()); + return true; + + case "config": + if (player.isOp()) // TODO add permissions + { + Gui.open(player, new MainConfigGUI()); + return true; + } else { + return false; + } + } + + return false; + } + + /** + * Sets the state of a player joining the game while the waiting phase is in progress. + * + * @param player The player to setup. + */ + private void handleNewPlayer(final Player player) { + if (Config.TELEPORT_TO_SPAWN_IF_NOT_STARTED.get() && QSG.game().getPhase() != GamePhase.STARTING) { + final Location worldSpawn = QSG + .get().getWorld(World.Environment.NORMAL).getSpawnLocation().add(0.5, 0.5, 0.5); + if (!QSGUtils.safeTP(player, worldSpawn)) { + player.teleport(worldSpawn.add(0, 1, 0)); + } + + if (Config.ENABLE_PVP.get()) { + player.setBedSpawnLocation(worldSpawn, true); + } + } + + player.setHealth(player.getMaxHealth()); + player.setFoodLevel(20); + player.setSaturation(20f); + + updateInventory(player); + + player.getInventory().setHeldItemSlot(4); + + displayTeamInActionBar(player); + } + + /** + * Update the player inventory and game mode, if its state changed since last update. + * + * @param player The player to update. + */ + private void updateInventory(final Player player) { + final boolean builder = isBuilder(player); + final boolean teamsDisplayed = Config.TEAM_SELECTOR.ENABLED.get(); + final boolean configDisplayed = Config.CONFIG_ACCESSOR.ENABLED.get() && player.isOp(); + + // Only updates the inventory when the access state change. + final String state = String.format("%b%b%b", builder, teamsDisplayed, configDisplayed); + if (playerInventoriesStates.containsKey(player.getUniqueId()) && + playerInventoriesStates.get(player.getUniqueId()).equals(state)) { + return; + } + + playerInventoriesStates.put(player.getUniqueId(), state); + + player.setGameMode(builder ? GameMode.CREATIVE : GameMode.ADVENTURE); + + if (!builder && Config.INVENTORY.CLEAR.get()) { + player.getInventory().clear(); + player.getInventory().setArmorContents(null); + } + + if (Config.TEAM_SELECTOR.ENABLED.get() || Config.CONFIG_ACCESSOR.ENABLED.get()) { + final ItemStack teamsSelector = new ItemStackBuilder(Config.TEAM_SELECTOR.ITEM.get()) + /// The title of the item given before the game to select a team + .title(I.t("{green}{bold}Select a team {gray}(Right-Click)")) + /// The lore of the item given before the game to select a team + .longLore(I.t("{gray}Right-click to select your team for this game")) + .hideAllAttributes() + .craftItem(); + + final ItemStack configAccessor = new ItemStackBuilder(Config.CONFIG_ACCESSOR.ITEM.get()) + .title(I.t("{red}{bold}Configure the game {gray}(Right-Click)")) + .longLore(I.t("{gray}Right-click to open the game configuration GUI")) + .hideAllAttributes() + .craftItem(); + + writeAction(teamsSelector, "teams"); + writeAction(configAccessor, "config"); + + final int teamsSlot = configDisplayed ? 2 : 4; + final int configSlot = teamsDisplayed ? 6 : 4; + + clearIfSimilar(player, teamsSelector, 2); + clearIfSimilar(player, teamsSelector, 4); + clearIfSimilar(player, configAccessor, 4); + clearIfSimilar(player, configAccessor, 6); + + if (teamsDisplayed) { + placeIfPossible(player, teamsSelector, teamsSlot); + } + + if (configDisplayed) { + placeIfPossible(player, configAccessor, configSlot); + } + } + } + + private void placeIfPossible(final Player player, final ItemStack item, final int slot) { + final ItemStack previousItem = player.getInventory().getItem(slot); + if (!isBuilder(player) || previousItem == null || previousItem.getType() == org.bukkit.Material.AIR) { + player.getInventory().setItem(slot, item); + } + } + + private void clearIfSimilar(final Player player, final ItemStack ifSimilarTo, final int slot) { + final ItemStack previousItem = player.getInventory().getItem(slot); + if (previousItem != null && previousItem.getType() == ifSimilarTo.getType()) { + player.getInventory().setItem(slot, new ItemStack(Material.AIR)); + } + } + + /** + * If the configuration option is enabled, displays its team in the player's + * action bar. If the player is not in a team, the action bar is cleared. + * + * @param player The player. + */ + private void displayTeamInActionBar(final OfflinePlayer player) { + if (!Config.TEAM_IN_ACTION_BAR.get() || player == null) { + return; + } + + final Player onlinePlayer; + + if (player instanceof Player) { + onlinePlayer = (Player) player; + } else { + onlinePlayer = Bukkit.getPlayer(player.getUniqueId()); + } + + if (onlinePlayer == null) { + return; + } + + final QuartzTeam team = QuartzTeams.get().getTeamForPlayer(player); + + if (team != null) { + ActionBar.sendPermanentMessage(onlinePlayer, I.t("{gold}Your team: {0}", team.getDisplayName())); + } else { + ActionBar.removeMessage(onlinePlayer, true); + } + } + + @EventHandler + public void onPlayerJoin(final PlayerJoinEvent ev) { + if (isGameStarted()) { + return; + } + + handleNewPlayer(ev.getPlayer()); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerInteract(PlayerInteractEvent ev) { + if (ev.getAction() != Action.PHYSICAL && openGUI(ev.getPlayer(), ev.getItem())) { + ev.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent ev) { + if (openGUI(ev.getPlayer(), ev.getPlayer().getItemInHand())) { + ev.setCancelled(true); + } + } + + @EventHandler + public void onPlayerClick(InventoryClickEvent ev) { + if (Config.INVENTORY.PREVENT_USAGE.get()) { + if (isGameStarted()) { + return; + } + if (isBuilder(ev.getWhoClicked())) { + return; + } + if (!ev.getInventory().equals(ev.getWhoClicked().getInventory())) { + return; + } + + ev.setCancelled(true); + } + } + + @EventHandler + public void onPlayerDrag(InventoryDragEvent ev) { + if (Config.INVENTORY.PREVENT_USAGE.get()) { + if (isGameStarted()) { + return; + } + if (isBuilder(ev.getWhoClicked())) { + return; + } + if (!ev.getInventory().equals(ev.getWhoClicked().getInventory())) { + return; + } + + ev.setCancelled(true); + } + } + + @EventHandler + public void onPlayerDrop(PlayerDropItemEvent ev) { + if (Config.INVENTORY.PREVENT_USAGE.get()) { + if (isGameStarted()) { + return; + } + if (isBuilder(ev.getPlayer())) { + return; + } + + ev.setCancelled(true); + } + } + + @EventHandler + public void onPlayerPickup(PlayerPickupItemEvent ev) { + if (isGameStarted()) { + return; + } + if (isBuilder(ev.getPlayer())) { + return; + } + + if (Config.INVENTORY.PREVENT_USAGE.get()) { + ev.setCancelled(true); + } + } + + /** + * Used to disable all damages if the game is not started. + */ + @EventHandler + public void onEntityDamage(final EntityDamageEvent ev) { + if (ev.getEntity() instanceof Player) { + if (!isGameStarted() + || (QSG.module(GameModule.class).getPhase() == GamePhase.WAIT && !Config.ENABLE_PVP.get())) { + ev.setCancelled(true); + } + } + } + + /** + * Used to cancel the spawn of the creatures if the game is not started. + * <p> + * We don't use the peaceful difficulty for that because it causes bugs with Minecraft 1.8 + * (the difficulty is not correctly updated client-side when the game starts). + */ + @EventHandler + public void onCreatureSpawn(CreatureSpawnEvent ev) { + if (!isGameStarted() + && EntitiesUtils.isNaturalSpawn(ev.getSpawnReason()) + && EntitiesUtils.isHostile(ev.getEntityType())) { + ev.setCancelled(true); + } + } + + /** + * Used to prevent the food level from dropping if the game has not started. + */ + @EventHandler + public void onFoodUpdate(final FoodLevelChangeEvent ev) { + if (isGameStarted()) { + return; + } + + if (ev.getEntity() instanceof Player) { + ((Player) ev.getEntity()).setFoodLevel(20); + ((Player) ev.getEntity()).setSaturation(20f); + } + + ev.setCancelled(true); + } + + + /** + * Used to display the team in the action bar (if needed). + */ + @EventHandler + public void onTeamJoin(final PlayerJoinedTeamEvent ev) { + displayTeamInActionBar(ev.getPlayer()); + } + + /** + * Used to display the team in the action bar (if needed). + */ + @EventHandler + public void onTeamUpdated(final TeamUpdatedEvent ev) { + ev.getTeam().getOnlinePlayers().forEach(this::displayTeamInActionBar); + } + + /** + * Used to display the team in the action bar (if needed). + */ + @EventHandler + public void onTeamDeleted(final TeamUnregisteredEvent ev) { + ev.getTeam().getOnlinePlayers().forEach(this::displayTeamInActionBar); + } + + /** + * Used to display the team in the action bar (if needed). + */ + @EventHandler + public void onTeamLeft(final PlayerLeftTeamEvent ev) { + displayTeamInActionBar(ev.getPlayer()); + } + + + /** + * The action bar messages are removed when the starting phase starts. + * This listener will self-disable when the game starts. + */ + @EventHandler + public void onGameStarts(final GamePhaseChangedEvent ev) { + switch (ev.getNewPhase()) { + case STARTING: + Bukkit.getOnlinePlayers().forEach(player -> { + ActionBar.removeMessage(player); + + player.getInventory().clear(); + player.getInventory().setArmorContents(null); + + player.closeInventory(); + }); + break; + + case IN_GAME: + QuartzLib.unregisterEvents(this); + if (inventoriesUpdateTask != null) { + inventoriesUpdateTask.cancel(); + inventoriesUpdateTask = null; + } + break; + } + } + + + /** + * @param player A player + * @return True if an inventory action should not be done because he is a builder. + */ + private boolean isBuilder(final Permissible player) { + return Config.INVENTORY.ALLOW_FOR_BUILDERS.get() && player.hasPermission("uh.build"); + } + + /** + * @return If we are in the right game phase (wait). + */ + private boolean isGameStarted() { + final GamePhase phase = QSG.module(GameModule.class).getPhase(); + return phase != GamePhase.WAIT && phase != GamePhase.STARTING; + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/worldgen/creatures/Config.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/worldgen/creatures/Config.java new file mode 100644 index 0000000..7027b51 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/worldgen/creatures/Config.java @@ -0,0 +1,50 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.worldgen.creatures; + +import static fr.zcraft.quartzlib.components.configuration.ConfigurationItem.list; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationInstance; +import fr.zcraft.quartzlib.components.configuration.ConfigurationList; +import java.io.File; +import java.util.Map; + +public class Config extends ConfigurationInstance { + public static final ConfigurationList<Map> SPAWN_RULES = list("spawn_rules", Map.class); + + public Config(File file) { + super(file); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/worldgen/creatures/CreaturesModule.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/worldgen/creatures/CreaturesModule.java new file mode 100644 index 0000000..73e34ed --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/modules/worldgen/creatures/CreaturesModule.java @@ -0,0 +1,543 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.modules.worldgen.creatures; + +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleCategory; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleInfo; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLoadTime; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import fr.zcraft.quartzlib.components.configuration.ConfigurationParseException; +import fr.zcraft.quartzlib.components.configuration.ConfigurationValueHandlers; +import fr.zcraft.quartzlib.exceptions.IncompatibleMinecraftVersionException; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.reflection.Reflection; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import org.bukkit.Material; +import org.bukkit.block.Biome; +import org.bukkit.entity.EntityType; + +@ModuleInfo( + name = "Creatures Spawn Control", + description = "Alters creatures spawn rules for all or some biomes. " + + "This include disabling spawn of some creatures completely.\n\n" + + "For best results, enable before generating the worlds.", + when = ModuleLoadTime.STARTUP, + category = ModuleCategory.WORLD_GENERATION, + icon = Material.SPAWNER, + settings = Config.class +) +public class CreaturesModule extends QSGModule { + /** + * Map {@link EntityType} -> {@code Class<? extends net.minecraft.server.Entity>} + */ + private final static Map<EntityType, Class<?>> NMS_ENTITY_CLASSES = new HashMap<>(); + /** + * Map {@link EntityType} -> {@code net.minecraft.server.EntityTypes} + */ + private final static Map<EntityType, Object> NMS_ENTITY_TYPES = new HashMap<>(); + /** + * Map {@link Biome} -> {@code net.minecraft.server.BiomeBase} + */ + private final static Map<Biome, Object> NMS_BIOMES = new HashMap<>(); + /** + * {@code true} if successfully hooked into NMS. + */ + private static boolean hooked; + private static Class<?> WEIGHTED_RANDOM_CHOICE_CLASS; + private static Class<?> CREATURE_TYPE_ENUM; + private static Field CREATURE_TYPE_ENUM_CLASS_FIELD; + private static Constructor<?> BIOME_META_CONSTRUCTOR; + + static { + try { + final Class<?> ENTITY_TYPES_CLASS = Reflection.getMinecraftClassByName("EntityTypes"); + final Class<?> BIOME_BASE_BIOME_META_CLASS = Reflection.getMinecraftClassByName("BiomeBase$BiomeMeta"); + + WEIGHTED_RANDOM_CHOICE_CLASS = Reflection.getMinecraftClassByName("WeightedRandom$WeightedRandomChoice"); + CREATURE_TYPE_ENUM = Reflection.getMinecraftClassByName("EnumCreatureType"); + + CREATURE_TYPE_ENUM_CLASS_FIELD = Arrays.stream(CREATURE_TYPE_ENUM.getDeclaredFields()) + .filter(field -> field.getType().equals(Class.class)).findFirst() + .orElseThrow(() -> new IncompatibleMinecraftVersionException( + new Exception("Cannot find the field containing the super class in EnumCreatureType"))); + + CREATURE_TYPE_ENUM_CLASS_FIELD.setAccessible(true); + + try { + BIOME_META_CONSTRUCTOR = + BIOME_BASE_BIOME_META_CLASS.getConstructor(Class.class, int.class, int.class, int.class); + } + catch (final NoSuchMethodException | SecurityException e) { + BIOME_META_CONSTRUCTOR = + BIOME_BASE_BIOME_META_CLASS.getConstructor(ENTITY_TYPES_CLASS, int.class, int.class, int.class); + } + + BIOME_META_CONSTRUCTOR.setAccessible(true); + + // We build the two above maps to access the classes & types faster in all patches. + // We first loop over `EntityTypes` fields to detect the version we have. + + EntityTypesClassVersion version = null; + boolean hadMaps = false; + + for (final Field field : ENTITY_TYPES_CLASS.getDeclaredFields()) { + if (field.getType().equals(ENTITY_TYPES_CLASS)) { + version = EntityTypesClassVersion.STATIC_ATTRIBUTES; + break; + } else if (field.getType().getSimpleName().equals("RegistryMaterials")) { + version = EntityTypesClassVersion.MINECRAFT_KEYS; + break; + } else if (Map.class.isAssignableFrom(field.getType())) { + hadMaps = true; + } + } + + if (version == null && hadMaps) { + version = EntityTypesClassVersion.MAPS; + } + if (version == null) { + throw new IncompatibleMinecraftVersionException(new Exception("EntityTypes class version unsupported")); + } + + switch (version) { + // FIXME UNTESTED + case MAPS: + // We loop over all maps to check the values inside. + // We want to find the map String -> Class<? extends net.minecraft.server.Entity> + for (final Field field : ENTITY_TYPES_CLASS.getDeclaredFields()) { + if (!Map.class.isAssignableFrom(field.getType())) { + continue; + } + field.setAccessible(true); + + final Map<?, ?> map = (Map) field.get(null); + final Map.Entry entry = map.entrySet().stream().findFirst().orElse(null); + + if (entry == null) { + continue; + } + + if (entry.getKey().getClass().equals(String.class) && + entry.getValue().getClass().equals(Class.class)) { + // We found the one, let's save all of this. + // We can't extract EntityTypes for this version because the instances doesn't even exist, + // and we don't need them anyway. + final Map<String, Class<?>> keyToClass = (Map<String, Class<?>>) map; + + for (final EntityType entityType : EntityType.values()) { + final String name = (String) Reflection.getFieldValue(entityType, "name"); + if (name == null) { + continue; + } + NMS_ENTITY_CLASSES.put(entityType, keyToClass.get(name)); + } + + break; + } + } + break; + + case MINECRAFT_KEYS: + // Here we can load this class + final Class<?> REGISTRY_CLASS = Reflection.getMinecraftClassByName("RegistryMaterials"); + final Method REGISTRY_METHOD_GET = REGISTRY_CLASS.getDeclaredMethod("get", Object.class); + final Class<?> MINECRAFT_KEY_CLASS = Reflection.getMinecraftClassByName("MinecraftKey"); + + Object registry = null; + for (final Field field : ENTITY_TYPES_CLASS.getDeclaredFields()) { + if (field.getType().equals(REGISTRY_CLASS)) { + registry = field.get(null); + break; + } + } + + // Should be impossible + if (registry == null) { + throw new IncompatibleMinecraftVersionException( + new NoSuchFieldException("Cannot retrieve the EntityTypes registry.")); + } + + for (final EntityType entityType : EntityType.values()) { + // We can't extract EntityTypes for this version because the instances doesn't even exist, + // and we don't need them anyway. + final String name = (String) Reflection.getFieldValue(entityType, "name"); + if (name == null) { + continue; + } + + NMS_ENTITY_CLASSES.put(entityType, (Class<?>) REGISTRY_METHOD_GET + .invoke(registry, Reflection.instantiate(MINECRAFT_KEY_CLASS, name))); + } + + break; + + // FIXME UNTESTED (can only be tested with 1.13 support) + case STATIC_ATTRIBUTES: + // Intermediate map key -> bukkit entity type + final Map<String, EntityType> BY_KEY = Arrays.stream(EntityType.values()) + .map(entityType -> { + try { + return new AbstractMap.SimpleEntry<>( + (String) Reflection.getFieldValue(entityType, "name"), entityType); + } + catch (NoSuchFieldException | IllegalAccessException e) { + return null; + } + }) + .filter(Objects::nonNull) + .filter(entry -> entry.getKey() != null) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + for (Field field : ENTITY_TYPES_CLASS.getDeclaredFields()) { + if (!field.getType().equals(ENTITY_TYPES_CLASS)) { + continue; + } + + final Object type = field.get(null); + final String key = (String) Reflection.call(type, "d"); // Returns the key (String) + final Class<?> clazz = + (Class<?>) Reflection.call(type, "c"); // Returns the class (Class<? extends Entity>) + + final EntityType bukkitType = BY_KEY.get(key); + if (bukkitType == null) { + continue; + } + + NMS_ENTITY_CLASSES.put(bukkitType, clazz); + NMS_ENTITY_TYPES.put(bukkitType, type); + } + + break; + } + + // We also build a map from Bukkit's to NMS' biomes. + final Class<?> CRAFT_BLOCK_CLASS = Reflection.getBukkitClassByName("block.CraftBlock"); + + for (final Biome biome : Biome.values()) { + NMS_BIOMES.put(biome, Reflection.call(CRAFT_BLOCK_CLASS, "biomeToBiomeBase", biome)); + } + + hooked = true; + } + catch (final Exception e) { + PluginLogger.error("Unable to hook into NMS to patch creatures spawn.", e); + hooked = false; + } + } + + @Override + protected void onEnable() { + for (final Map rule : Config.SPAWN_RULES) { + try { + if (!rule.containsKey("entity")) { + log().warning("Skipping spawn rule without entity."); + continue; + } + + final EntityType entity = ConfigurationValueHandlers.handleValue(rule.get("entity"), EntityType.class); + + final int weight = ConfigurationValueHandlers.handleIntValue(rule.getOrDefault("weight", -1)); + final int minPackSize = + ConfigurationValueHandlers.handleIntValue(rule.getOrDefault("minimal_pack_size", -1)); + final int maxPackSize = + ConfigurationValueHandlers.handleIntValue(rule.getOrDefault("maximal_pack_size", -1)); + + final Biome[] biomes; + final boolean onlyIfPresent; + + if (!rule.containsKey("biomes")) { + biomes = null; + onlyIfPresent = true; + } else { + final Object rawBiomes = rule.get("biomes"); + + if (rawBiomes instanceof String && ((String) rawBiomes).trim().equalsIgnoreCase("ALL")) { + biomes = null; + onlyIfPresent = false; + } else if (rawBiomes instanceof List) { + final List<Biome> biomesList = new ArrayList<>(((List) rawBiomes).size()); + + for (final Object biome : ((List) rawBiomes)) { + try { + biomesList.add(ConfigurationValueHandlers.handleValue(biome, Biome.class)); + } + catch (ConfigurationParseException e) { + log().warning("Ignoring unknown biome {0} in spawn rules.", e.getValue()); + } + } + + biomes = biomesList.toArray(new Biome[0]); + onlyIfPresent = false; + } else { + log().warning("Invalid `biomes` key in spawn rule (neither a string nor a list); ignoring."); + + biomes = null; + onlyIfPresent = true; + } + } + + patchAnimalsSpawn(entity, weight, minPackSize, maxPackSize, onlyIfPresent, biomes); + } + catch (ConfigurationParseException e) { + log().warning("Invalid spawn rule, skipping. {0} (erroneous value: {1}).", e.getMessage(), + e.getValue()); + } + } + } + + /* + CREATURES SPAWN PATCH METHOD + + 1. final BiomeBase base = CraftBlock.biomeToBiomeBase(bukkitBiome); + 2. final Entity entity = craftEntity.getHandle(); + 3. loop EnumCreatureType, check if entity type.a() is subclass of entity + 3b. If given EntityType, + 4. if so, we have ctype = the type + 5. List<BiomeBase.BiomeMeta> metas = base.getMobs(ctype); + 6. Loop over metas to find in meta.b: if it's a class, the entity class; if it's a `EntityTypes` (1.13+), a type + 6b. if it's type, check the class with etypes.c() + 7. If good type found in the biome base metas, update the instance. + meta.a = weight + meta.c = spawnPackMin + meta.d = spawnPackMax + (meta.b = type or class) + 8. If not found, create the instance and att it to the list. Constructors: + 8a. BiomeMeta(Class<? extends Entity> entityClass, int weight, int spawnPackMin, int spawnPackMax); + 8b. BiomeMeta(EntityTypes entityType, int weight, int spawnPackMin, int spawnPackMax); + In this case, loop over static fields of type `EntityTypes` in `EntityTypes` and check their `c()` method + to get the class and compare it (maybe add this into a cache class -> type). + */ + + /** + * Patches the Minecraft Server to update spawning rules for the given entity, in all biomes where the given entity + * already spawn. + * <p> + * If integer values (weight, min & max) are negative, their values will be left untouched (excepted if a new rule + * is created from scratch if {@code onlyIfPresent = false}, then 1 will be used for all of them). + * + * @param entity The entity to alter the spawning rules of. + * @param weight The spawn weight. At each spawn tentative, the higher this number is, the higher the probability + * of this entity to be selected for spawn is. This is also true while generating the chunks. + * @param spawnPackMin While generating the chunks, the server spawns entities in them in groups. This is the + * minimal size of these spawn groups. + * During natural generation, entities are spawned alone, and these parameters are ignored. + * @param spawnPackMax This is the maximal size of a group while generating the chunks (see spawnPackMin). + */ + public void patchAnimalsSpawn(final EntityType entity, final int weight, final int spawnPackMin, + final int spawnPackMax) { + patchAnimalsSpawn(entity, weight, spawnPackMin, spawnPackMax, true, (Biome[]) null); + } + + /** + * Patches the Minecraft Server to update spawning rules for the given entity, in all biomes. + * + * @param entity The entity to alter the spawning rules of. + * @param weight The spawn weight. At each spawn tentative, the higher this number is, the higher the probability + * of this entity to be selected for spawn is. This is also true while generating the chunks. + * @param spawnPackMin While generating the chunks, the server spawns entities in them in groups. This is the + * minimal size of these spawn groups. + * During natural generation, entities are spawned alone, and these parameters are ignored. + * @param spawnPackMax This is the maximal size of a group while generating the chunks (see spawnPackMin). + * @param onlyIfPresent If true, the entity spawning rule will only be altered if the creature spawns in the biome. + * Else, if the creature doesn't already spawn in the given biome, it will be added to the + * biome's entities. This is especially useful for all-biomes alterations. + */ + public void patchAnimalsSpawn(final EntityType entity, final int weight, final int spawnPackMin, + final int spawnPackMax, final boolean onlyIfPresent) { + patchAnimalsSpawn(entity, weight, spawnPackMin, spawnPackMax, onlyIfPresent, (Biome[]) null); + } + + /** + * Patches the Minecraft Server to update spawning rules for the given entity, in the given biome(s). + * <p> + * If integer values (weight, min & max) are negative, their values will be left untouched (excepted if a new rule + * is created from scratch if {@code onlyIfPresent = false}, then 1 will be used for all of them). + * + * @param entity The entity to alter the spawning rules of. + * @param weight The spawn weight. At each spawn tentative, the higher this number is, the higher the probability + * of this entity to be selected for spawn is. This is also true while generating the chunks. + * @param spawnPackMin While generating the chunks, the server spawns entities in them in groups. This is the + * minimal size of these spawn groups. + * During natural generation, entities are spawned alone, and these parameters are ignored. + * @param spawnPackMax This is the maximal size of a group while generating the chunks (see spawnPackMin). + * @param onlyIfPresent If true, the entity spawning rule will only be altered if the creature spawns in the biome. + * Else, if the creature doesn't already spawn in the given biome, it will be added to the + * biome's entities. This is especially useful for all-biomes alterations. + * @param biomes The biomes to alter. Spawning rules are specific to biomes and only these biomes will be patched. + * If {@code null} or empty, all biomes will be patched. + */ + public void patchAnimalsSpawn(final EntityType entity, final int weight, final int spawnPackMin, + final int spawnPackMax, final boolean onlyIfPresent, final Biome... biomes) { + if (!hooked) { + return; // Incompatible Minecraft version + } + + final Class<?> nmsEntityClass = NMS_ENTITY_CLASSES.get(entity); + final Object nmsEntityType = NMS_ENTITY_TYPES.get(entity); + + if (nmsEntityClass == null) { + return; // Unsupported entity + } + + final Enum creatureType = getCreatureType(nmsEntityClass); + if (creatureType == null) { + return; // Non-naturally-spawnable entity + } + + final Biome[] patchedBiomes = biomes != null && biomes.length > 0 ? biomes : Biome.values(); + + for (final Biome biome : patchedBiomes) { + final Object base = NMS_BIOMES.get(biome); + if (base == null) { + continue; + } + + try { + final List<Object> metas = (List<Object>) Reflection.call(base, "getMobs", creatureType); + boolean found = false; + + for (final Object meta : metas) { + final Object entityClassOrType = Reflection.getFieldValue(meta, "b"); + if (!Objects.equals(entityClassOrType, nmsEntityClass) && + !Objects.equals(entityClassOrType, nmsEntityType)) { + continue; // Not the meta we're looking for + } + + if (weight >= 0) { + Reflection.setFieldValue(WEIGHTED_RANDOM_CHOICE_CLASS, meta, "a", weight); + } + if (spawnPackMin >= 0) { + Reflection.setFieldValue(meta, "c", spawnPackMin); + } + if (spawnPackMax >= 0) { + Reflection.setFieldValue(meta, "d", spawnPackMax); + } + + found = true; + } + + // If the entity meta was not present and we want it to be added in this case + if (!found && !onlyIfPresent) { + Object meta; + + try { + meta = BIOME_META_CONSTRUCTOR.newInstance( + nmsEntityClass, + weight >= 0 ? weight : 1, + spawnPackMin >= 0 ? spawnPackMin : 1, + spawnPackMax >= 0 ? spawnPackMax : 1 + ); + } + catch (final IllegalArgumentException | InstantiationException | InvocationTargetException | IllegalAccessException e) { + try { + + if (nmsEntityType == null) { + throw new IncompatibleMinecraftVersionException( + new Exception("Unknown entity type for " + entity)); + } + + meta = BIOME_META_CONSTRUCTOR + .newInstance(nmsEntityType, weight, spawnPackMin, spawnPackMax); + } + catch (final IllegalArgumentException | InstantiationException | InvocationTargetException | IllegalAccessException e1) { + log().warning( + "Unable to construct a new BiomeBase.BiomeMeta (tested two constructors). Nag UHCReloaded authors about this.", + e1); + log().warning("Previous exception was:", e); + continue; + } + } + + metas.add(meta); + } + } + catch (final NoSuchMethodException | IllegalAccessException | InvocationTargetException | NoSuchFieldException e) { + log().error("Unable to patch entities spawn rules for entity {0} and biome {1}", e, entity, biome); + } + } + } + + private Enum getCreatureType(final Class<?> nmsEntityClass) { + try { + for (final Object creatureType : CREATURE_TYPE_ENUM.getEnumConstants()) { + final Class<?> clazz = (Class<?>) CREATURE_TYPE_ENUM_CLASS_FIELD.get(creatureType); + if (clazz.isAssignableFrom(nmsEntityClass)) { + return (Enum) creatureType; + } + } + + return null; + } + catch (IllegalAccessException e) { + return null; + } + } + + + /** + * Represents the version of the class storing the entity types, used to access + * the NMS' entity base class from a Bukkit's EntityType. + */ + private enum EntityTypesClassVersion { + /** + * Entity types stored in maps in the `EntityTypes` class. + * Covers 1.8 -> 1.10. + */ + MAPS, + + /** + * Entity types stored in a registry in `EntityTypes`. + * Covers 1.11 -> 1.12. + */ + MINECRAFT_KEYS, + + /** + * Entity types stored as static attributes of `EntityTypes`. + * Covers 1.13+. + */ + STATIC_ATTRIBUTES + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/shortcuts/QSG.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/shortcuts/QSG.java new file mode 100644 index 0000000..434df01 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/shortcuts/QSG.java @@ -0,0 +1,257 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.shortcuts; + +import com.google.common.reflect.ClassPath; +import eu.carrade.amaury.quartzsurvivalgames.QuartzSurvivalGames; +import eu.carrade.amaury.quartzsurvivalgames.core.ModuleLogger; +import eu.carrade.amaury.quartzsurvivalgames.core.ModulesManager; +import eu.carrade.amaury.quartzsurvivalgames.core.QSGModule; +import eu.carrade.amaury.quartzsurvivalgames.modules.core.game.GameModule; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.reflection.Reflection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import org.apache.commons.lang.ArrayUtils; + + +/** + * Useful shortcuts. + */ +public final class QSG { + private static final Map<Class<?>, Class<? extends QSGModule>> classesModules = new HashMap<>(); + private static final Map<String, Class<? extends QSGModule>> packagesModules = new HashMap<>(); + + /** + * Returns the plugin's instance. + */ + public static QuartzSurvivalGames get() { + return QuartzSurvivalGames.get(); + } + + /** + * Gets a module's instance. This may return null if the module is not currently + * loaded. + * + * @param moduleClass The module's class. + * @param <M> The module's type. + * @return The module's instance. + */ + public static <M extends QSGModule> M module(final Class<M> moduleClass) { + return ModulesManager.getModule(moduleClass); + } + + /** + * Returns the module for the caller class' module. + * <p> + * This works by looking up for the module class in the caller class' + * package or “parent” packages. Throws an exception if no module class can + * be found. + * + * @return The module's instance. + * @throws IllegalArgumentException if no module can be found for the caller + * class. + */ + public static QSGModule module() { + final Class<?> caller = Reflection.getCallerClass(); + if (caller == null) { + throw new IllegalArgumentException("Cannot extract caller class in module()"); + } + + final Class<? extends QSGModule> moduleClass = getModuleFromClass(caller); + + if (moduleClass != null) { + return module(moduleClass); + } + + throw new IllegalArgumentException( + "The class " + caller.getCanonicalName() + " is not inside a module's package."); + } + + /** + * @return The game module, because it is heavily used through the codebase. + */ + public static GameModule game() { + return module(GameModule.class); + } + + /** + * Checks if a module is loaded. If this test is positive, the + * {@link #module(Class)} method called with the same class will be + * non-null and available. + * + * @param moduleClass The module's class. + * @param <M> The module's type. + * @return {@code true} if the given module is loaded. + */ + public static <M extends QSGModule> boolean loaded(Class<M> moduleClass) { + return get().getModulesManager().isLoaded(moduleClass); + } + + /** + * Checks if a module is loaded; if so, executes the consumer with the module's + * instance as argument. + * + * @param moduleClass The module's class. + * @param consumer The module's instance consumer. + * @param <M> The module's type. + */ + public static <M extends QSGModule> void ifLoaded(final Class<M> moduleClass, Consumer<M> consumer) { + final M module = module(moduleClass); + if (module != null) { + consumer.accept(module); + } + } + + /** + * Returns the logger for a given module. This may return null if the module is not + * currently loaded. + * + * @param moduleClass The module's class. + * @return The module's logger. + */ + public static ModuleLogger log(final Class<? extends QSGModule> moduleClass) { + try { + return module(moduleClass).log(); + } + catch (final NullPointerException e) { + // Ensures no NPE so IDEs are happy. + return new ModuleLogger(UnknownModule.class); + } + } + + /** + * Returns the logger for the caller class' module. + * <p> + * This works by looking up for the module class in the caller class' + * package or “parent” packages. Throws an exception if no module class can + * be found. + * + * @return The module's logger. + * @throws IllegalArgumentException if no module can be found for the caller + * class. + */ + public static ModuleLogger log() { + final Class<?> caller = Reflection.getCallerClass(); + if (caller == null) { + throw new IllegalArgumentException("Cannot extract caller class in log()"); + } + + final Class<? extends QSGModule> moduleClass = getModuleFromClass(caller); + + if (moduleClass != null) { + return log(moduleClass); + } + + throw new IllegalArgumentException( + "The class " + caller.getCanonicalName() + " is not inside a module's package."); + } + + /** + * Tries to retrieve the module of a given class. + * <p> + * It will lookup for a class extending {@link QSGModule} in the class's + * package, then in the “parent” package, etc., until the “root” package is + * reached. {@code null} will be returned if no package can be found. + * <p> + * The result of this method is cached at runtime. + * + * @param clazz The class to search the module of. + * @return The module class, or {@code null} if not found. + */ + private static Class<? extends QSGModule> getModuleFromClass(final Class<?> clazz) { + if (classesModules.containsKey(clazz)) { + return classesModules.get(clazz); + } + + try { + final ClassPath classPath = ClassPath.from(clazz.getClassLoader()); + final Set<String> analyzedPackages = new HashSet<>(); + + String packaj = clazz.getPackage().getName(); + while (packaj != null) { + // Cached? + if (packagesModules.containsKey(packaj)) { + return packagesModules.get(packaj); + } + + analyzedPackages.add(packaj); + + // We try to find a class in this package extending UHModule + for (final ClassPath.ClassInfo packajClazzInfo : classPath.getTopLevelClasses(packaj)) { + final Class<?> packajClazz = packajClazzInfo.load(); + + if (QSGModule.class.isAssignableFrom(packajClazz)) { + // We found the One™. + @SuppressWarnings("unchecked") final Class<? extends QSGModule> moduleClazz = + (Class<? extends QSGModule>) packajClazz; + + // We cache as hard as we can as these operations can be heavy. + analyzedPackages.forEach(analyzed -> packagesModules.put(analyzed, moduleClazz)); + classesModules.put(clazz, moduleClazz); + + return moduleClazz; + } + } + + // If we fail, we try with the “parent” package. + if (packaj.contains(".")) { + final String[] packajParts = packaj.split("\\."); + ArrayUtils.remove(packajParts, packajParts.length - 1); + packaj = String.join(".", (String[]) ArrayUtils.remove(packajParts, packajParts.length - 1)); + } else { + packaj = null; + } + } + + PluginLogger.error("Unable to find module for class {0}", clazz.getCanonicalName()); + classesModules.put(clazz, null); + analyzedPackages.forEach(analyzed -> packagesModules.put(analyzed, null)); + + return null; + } + catch (final Throwable e) { + PluginLogger.error("Unable to find module for class {0}", e, clazz.getCanonicalName()); + classesModules.put(clazz, null); + return null; + } + } + + private static class UnknownModule extends QSGModule { + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/CommandUtils.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/CommandUtils.java new file mode 100644 index 0000000..aee02f4 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/CommandUtils.java @@ -0,0 +1,115 @@ +/* + * 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.quartzsurvivalgames.utils; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.List; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + + +public class CommandUtils { + public final static String CHAT_SEPARATOR = ChatColor.GRAY + + "⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅"; + + /** + * Returns a list of autocompletion suggestions based on what the user typed and on a list of + * available commands. + * + * @param typed What the user typed. This string needs to include <em>all</em> the words typed. + * @param suggestionsList The list of the suggestions. + * @param numberOfWordsToIgnore If non-zero, this number of words will be ignored at the beginning of the string. This is used to handle multiple-words autocompletion. + * @return The list of matching suggestions. + */ + public static List<String> getAutocompleteSuggestions(String typed, List<String> suggestionsList, + int numberOfWordsToIgnore) { + List<String> list = new ArrayList<String>(); + + // For each suggestion: + // - if there isn't any world to ignore, we just compare them; + // - else, we removes the correct number of words at the beginning of the string; + // then, if the raw suggestion matches the typed text, we adds to the suggestion list + // the filtered suggestion, because the Bukkit's autocompleter works on a “per-word” basis. + + for (String rawSuggestion : suggestionsList) { + String suggestion; + + if (numberOfWordsToIgnore == 0) { + suggestion = rawSuggestion; + } else { + // Not the primary use, but, hey! It works. + suggestion = QSGUtils.getStringFromCommandArguments(rawSuggestion.split(" "), numberOfWordsToIgnore); + } + + if (rawSuggestion.toLowerCase().startsWith(typed.toLowerCase())) { + list.add(suggestion); + } + } + + list.sort(Collator.getInstance()); + + return list; + } + + /** + * Returns a list of autocompletion suggestions based on what the user typed and on a list of + * available commands. + * + * @param typed What the user typed. + * @param suggestionsList The list of the suggestions. + * @return The list of matching suggestions. + */ + public static List<String> getAutocompleteSuggestions(String typed, List<String> suggestionsList) { + return getAutocompleteSuggestions(typed, suggestionsList, 0); + } + + + /** + * Displays a separator around the output of the commands. + * + * <p> + * To be called before and after the output (prints a line only). + * </p> + * + * @param sender The line will be displayed for this sender. + */ + public static void displaySeparator(CommandSender sender) { + if (!(sender instanceof Player)) { + return; + } + + sender.sendMessage(CHAT_SEPARATOR); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/EntitiesUtils.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/EntitiesUtils.java new file mode 100644 index 0000000..24b6abc --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/EntitiesUtils.java @@ -0,0 +1,78 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.utils; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Ghast; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Slime; +import org.bukkit.event.entity.CreatureSpawnEvent; + +public class EntitiesUtils { + /** + * Checks if a spawn is natural. + * + * @param reason The spawn reason. + * @return {@code true} if it's a natural spawn (not from a player or an interaction + * with another entity, as example). + */ + public static boolean isNaturalSpawn(final CreatureSpawnEvent.SpawnReason reason) { + switch (reason) { + case NATURAL: + case NETHER_PORTAL: + case LIGHTNING: + case SPAWNER: + return true; + + default: + return false; + } + } + + /** + * Checks if the given mod is hostile. + * + * @param entity The entity. + * @return {@code true} if hostile. + */ + public static boolean isHostile(final EntityType entity) { + final Class<? extends Entity> entityClass = entity.getEntityClass(); + + return Monster.class.isAssignableFrom(entityClass) + || Slime.class.isAssignableFrom(entityClass) + || Ghast.class.isAssignableFrom(entityClass); + } +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/ModulesUtils.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/ModulesUtils.java new file mode 100644 index 0000000..f1bbc1c --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/ModulesUtils.java @@ -0,0 +1,111 @@ +/* + * 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.quartzsurvivalgames.utils; + +import java.util.Arrays; +import java.util.List; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; + + +public class ModulesUtils { + /** + * Tries to find a class from its name, by combining suffixes, packages, capitalization. + * + * @param name The class base name to search for. + * @param optionalPackage An optional package to search in. + * @param optionalSuffix An optional suffix to test, appended to the class name. + * @param superClass The superclass this class must have. + * @param <T> The superclass type this class must have. + * @return The {@link Class}, if found; else, {@code null}. + */ + public static <T> Class<? extends T> getClassFromName(final String name, final String optionalPackage, + final String optionalSuffix, final Class<T> superClass) { + final String alternateName; + final String alternativePackage; + + if (name.contains(".")) { + final String[] lastClassPathParts = name.split("\\."); + alternateName = lastClassPathParts[lastClassPathParts.length - 1]; + alternativePackage = + String.join(".", (String[]) ArrayUtils.remove(lastClassPathParts, lastClassPathParts.length - 1)); + } else { + alternateName = name; + alternativePackage = ""; + } + + final List<String> possibilities = Arrays.asList( + optionalPackage + "." + name, + optionalPackage + "." + name + optionalSuffix, + optionalPackage + "." + StringUtils.capitalize(name), + optionalPackage + "." + StringUtils.capitalize(name) + optionalSuffix, + optionalPackage + "." + StringUtils.capitalize(name.toLowerCase()), + optionalPackage + "." + StringUtils.capitalize(name.toLowerCase()) + optionalSuffix, + optionalPackage + "." + StringUtils.uncapitalize(name) + "." + name, + optionalPackage + "." + StringUtils.uncapitalize(name) + "." + name, + optionalPackage + "." + StringUtils.uncapitalize(name) + "." + name + optionalSuffix, + optionalPackage + "." + StringUtils.uncapitalize(name) + "." + StringUtils.capitalize(name), + optionalPackage + "." + StringUtils.uncapitalize(name) + "." + StringUtils.capitalize(name) + + optionalSuffix, + optionalPackage + "." + StringUtils.uncapitalize(name) + "." + alternateName, + optionalPackage + "." + StringUtils.uncapitalize(name) + "." + alternateName + optionalSuffix, + optionalPackage + "." + StringUtils.uncapitalize(name) + "." + StringUtils.capitalize(alternateName), + optionalPackage + "." + StringUtils.uncapitalize(name) + "." + StringUtils.capitalize(alternateName) + + optionalSuffix, + optionalPackage + "." + StringUtils.uncapitalize(name) + "." + optionalSuffix, + optionalPackage + "." + alternativePackage + "." + name, + optionalPackage + "." + alternativePackage + "." + name + optionalSuffix, + optionalPackage + "." + alternativePackage + "." + StringUtils.capitalize(name), + optionalPackage + "." + alternativePackage + "." + StringUtils.capitalize(name) + optionalSuffix, + optionalPackage + "." + alternativePackage + "." + alternateName, + optionalPackage + "." + alternativePackage + "." + alternateName + optionalSuffix, + optionalPackage + "." + alternativePackage + "." + StringUtils.capitalize(alternateName), + optionalPackage + "." + alternativePackage + "." + StringUtils.capitalize(alternateName) + + optionalSuffix, + optionalPackage + "." + alternativePackage + "." + optionalSuffix, + name + ); + + for (final String clazzName : possibilities) { + try { + final Class clazz = Class.forName(clazzName); + if (superClass.isAssignableFrom(clazz)) { + return (Class<? extends T>) clazz; + } + } + catch (ClassNotFoundException e) { /* The search continues... */ } + } + + return null; + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/utils/OfflinePlayersComparator.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/OfflinePlayersComparator.java similarity index 90% rename from src/main/java/eu/carrade/amaury/UHCReloaded/utils/OfflinePlayersComparator.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/OfflinePlayersComparator.java index 56d240c..d6849d6 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/utils/OfflinePlayersComparator.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/OfflinePlayersComparator.java @@ -29,23 +29,22 @@ * 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.utils; -import org.bukkit.OfflinePlayer; +package eu.carrade.amaury.quartzsurvivalgames.utils; import java.util.Comparator; +import org.bukkit.OfflinePlayer; -public class OfflinePlayersComparator implements Comparator<OfflinePlayer> -{ +public class OfflinePlayersComparator implements Comparator<OfflinePlayer> { @Override - public int compare(OfflinePlayer player1, OfflinePlayer player2) - { - if (player1.isOnline() == player2.isOnline()) + public int compare(OfflinePlayer player1, OfflinePlayer player2) { + if (player1.isOnline() == player2.isOnline()) { return player1.getName().toLowerCase().compareTo(player2.getName().toLowerCase()); - else if (player1.isOnline()) + } else if (player1.isOnline()) { return -1; - else + } else { return 1; + } } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/misc/OfflinePlayersLoader.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/OfflinePlayersLoader.java similarity index 70% rename from src/main/java/eu/carrade/amaury/UHCReloaded/misc/OfflinePlayersLoader.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/OfflinePlayersLoader.java index 29b8902..a3a0877 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/misc/OfflinePlayersLoader.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/OfflinePlayersLoader.java @@ -29,19 +29,17 @@ * 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.misc; -import fr.zcraft.zlib.components.worker.Worker; -import fr.zcraft.zlib.components.worker.WorkerCallback; -import fr.zcraft.zlib.components.worker.WorkerRunnable; -import fr.zcraft.zlib.tools.Callback; -import fr.zcraft.zlib.tools.PluginLogger; -import fr.zcraft.zlib.tools.mojang.UUIDFetcher; -import fr.zcraft.zlib.tools.reflection.Reflection; -import org.apache.commons.lang.StringUtils; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; +package eu.carrade.amaury.quartzsurvivalgames.utils; +import fr.zcraft.quartzlib.components.worker.Worker; +import fr.zcraft.quartzlib.components.worker.WorkerAttributes; +import fr.zcraft.quartzlib.components.worker.WorkerCallback; +import fr.zcraft.quartzlib.components.worker.WorkerRunnable; +import fr.zcraft.quartzlib.tools.Callback; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.mojang.UUIDFetcher; +import fr.zcraft.quartzlib.tools.reflection.Reflection; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; @@ -53,11 +51,14 @@ import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; -public class OfflinePlayersLoader extends Worker -{ - private static Map<UUID, OfflinePlayer> offlinePlayers = new HashMap<>(); +@WorkerAttributes(name = "Offline Players Loader") +public class OfflinePlayersLoader extends Worker { + private static final Map<UUID, OfflinePlayer> offlinePlayers = new HashMap<>(); /** * Returns a list of offline players, including the players who logged in the server and the explicitly @@ -65,8 +66,7 @@ public class OfflinePlayersLoader extends Worker * * @return A list of OfflinePlayers. */ - public static Set<OfflinePlayer> getOfflinePlayers() - { + public static Set<OfflinePlayer> getOfflinePlayers() { final Set<OfflinePlayer> players = new HashSet<>(offlinePlayers.values()); Collections.addAll(players, Bukkit.getOfflinePlayers()); @@ -75,7 +75,7 @@ public static Set<OfflinePlayer> getOfflinePlayers() /** * Retrieves an OfflinePlayer by ID. - * + * <p> * Tries to load a logged-in player, then an explicitly loaded player, then * a server-wide OfflinePlayer. * @@ -84,39 +84,39 @@ public static Set<OfflinePlayer> getOfflinePlayers() * be loaded with a name and other data if the player never came to the server and * was not explicitly loaded. */ - public static OfflinePlayer getOfflinePlayer(UUID id) - { + public static OfflinePlayer getOfflinePlayer(UUID id) { OfflinePlayer player = Bukkit.getPlayer(id); - if (player == null) player = offlinePlayers.get(id); - if (player == null) player = Bukkit.getOfflinePlayer(id); + if (player == null) { + player = offlinePlayers.get(id); + } + if (player == null) { + player = Bukkit.getOfflinePlayer(id); + } return player; } /** * Retrieves an OfflinePlayer by name. - * + * <p> * Tries to load a logged-in player, then an explicitly loaded player, then * a server-wide OfflinePlayer. * * @param name The player's name. * @return An OfflinePlayer. {@code null} if no player was found with this name. */ - public static OfflinePlayer getOfflinePlayer(String name) - { + public static OfflinePlayer getOfflinePlayer(String name) { OfflinePlayer player = Bukkit.getOnlinePlayers().stream() .filter(onlinePlayer -> onlinePlayer.getName().equalsIgnoreCase(name)) .findFirst().orElse(null); - if (player == null) - { + if (player == null) { player = Arrays.stream(Bukkit.getOfflinePlayers()) .filter(offlinePlayer -> offlinePlayer.getName().equalsIgnoreCase(name)) .findFirst().orElse(null); } - if (player == null) - { + if (player == null) { player = offlinePlayers.values().stream() .filter(offlinePlayer -> offlinePlayer.getName().equalsIgnoreCase(name)) .findFirst().orElse(null); @@ -128,19 +128,18 @@ public static OfflinePlayer getOfflinePlayer(String name) /** * Loads the given players list in the system, making it available in the players list and to be added in teams. * - * @param pseudonym A pseudonym. + * @param pseudonym A pseudonym. * @param successCallback A callback called when the process ended. Called with {@code null} if no player was found. */ - public static void loadPlayer(final String pseudonym, final Callback<OfflinePlayer> successCallback) - { + public static void loadPlayer(final String pseudonym, final Callback<OfflinePlayer> successCallback) { loadPlayers(Collections.singletonList(pseudonym), retrieved -> { - if (successCallback != null) - { - if (retrieved.size() == 1) + if (successCallback != null) { + if (retrieved.size() == 1) { successCallback.call(retrieved.values().iterator().next()); - else + } else { successCallback.call(null); + } } }); } @@ -148,128 +147,125 @@ public static void loadPlayer(final String pseudonym, final Callback<OfflinePlay /** * Loads the given players list in the system, making it available in the players list and to be added in teams. * - * @param pseudonyms A list of pseudonyms. + * @param pseudonyms A list of pseudonyms. * @param callbackSuccess A callback called when the process ended. */ - public static void loadPlayers(final List<String> pseudonyms, final Callback<Map<UUID, OfflinePlayer>> callbackSuccess) - { + public static void loadPlayers(final List<String> pseudonyms, + final Callback<Map<UUID, OfflinePlayer>> callbackSuccess) { loadPlayers( pseudonyms, callbackSuccess, - errors -> PluginLogger.error("Unable to retrieve the following names: {0}", StringUtils.join(errors, ", ")) + errors -> PluginLogger + .error("Unable to retrieve the following names: {0}", StringUtils.join(errors, ", ")) ); } /** * Loads the given players list in the system, making it available in the players list * and to be added in teams. - * + * <p> * Only works in online mode. In offline mode, the already known players will be sent * to the success callback and the others to the errors one. Use {@link UUIDFetcher} * directly if needed. * - * @param pseudonyms A list of pseudonyms. + * @param pseudonyms A list of pseudonyms. * @param callbackSuccess A callback called when the process ended. */ - public static void loadPlayers(final List<String> pseudonyms, final Callback<Map<UUID, OfflinePlayer>> callbackSuccess, final Callback<List<String>> callbackErrors) - { + public static void loadPlayers(final List<String> pseudonyms, + final Callback<Map<UUID, OfflinePlayer>> callbackSuccess, + final Callback<List<String>> callbackErrors) { final List<String> toRetrieve = new ArrayList<>(pseudonyms); final Map<UUID, OfflinePlayer> alreadyKnown = new HashMap<>(); - for (String pseudonym : pseudonyms) - { + for (String pseudonym : pseudonyms) { OfflinePlayer player = getOfflinePlayer(pseudonym); - if (player != null) - { + if (player != null) { alreadyKnown.put(player.getUniqueId(), player); toRetrieve.remove(pseudonym); } } - if (toRetrieve.size() == 0) - { - if (callbackSuccess != null) callbackSuccess.call(alreadyKnown); + if (toRetrieve.size() == 0) { + if (callbackSuccess != null) { + callbackSuccess.call(alreadyKnown); + } return; } // If the server is in offline mode, we don't even try to load the players, as they will // not be valid and be unusable. - if (!Bukkit.getOnlineMode()) - { - if (callbackSuccess != null) callbackSuccess.call(alreadyKnown); - if (callbackErrors != null && toRetrieve.size() > 0) callbackErrors.call(toRetrieve); + if (!Bukkit.getOnlineMode()) { + if (callbackSuccess != null) { + callbackSuccess.call(alreadyKnown); + } + if (callbackErrors != null && toRetrieve.size() > 0) { + callbackErrors.call(toRetrieve); + } return; } - submitQuery(new WorkerRunnable<Map<String, UUID>>() - { + submitQuery(new WorkerRunnable<Map<String, UUID>>() { @Override - public Map<String, UUID> run() throws Throwable - { + public Map<String, UUID> run() throws Throwable { final Map<String, UUID> uuids = UUIDFetcher.fetch(toRetrieve); UUIDFetcher.fetchRemaining(toRetrieve, uuids); return uuids; } - }, new WorkerCallback<Map<String, UUID>>() - { + }, new WorkerCallback<Map<String, UUID>>() { @Override - public void finished(final Map<String, UUID> result) - { + public void finished(final Map<String, UUID> result) { final Map<UUID, OfflinePlayer> added = new HashMap<>(alreadyKnown); final Class<?> gameProfileClass; - try - { + try { gameProfileClass = Class.forName("com.mojang.authlib.GameProfile"); } - catch (ClassNotFoundException e) - { + catch (ClassNotFoundException e) { PluginLogger.error("Cannot load GameProfile class required to load OfflinePlayers.", e); return; } - for (Map.Entry<String, UUID> playerProfile : result.entrySet()) - { + for (Map.Entry<String, UUID> playerProfile : result.entrySet()) { final String name = playerProfile.getKey(); final UUID uuid = playerProfile.getValue(); - if (uuid == null) - { + if (uuid == null) { PluginLogger.error("Unable to load the player {0}, skipping.", name); continue; } - try - { + try { final Object profile = Reflection.instantiate(gameProfileClass, uuid, name); - final OfflinePlayer player = (OfflinePlayer) Reflection.call(Bukkit.getServer(), "getOfflinePlayer", profile); + final OfflinePlayer player = + (OfflinePlayer) Reflection.call(Bukkit.getServer(), "getOfflinePlayer", profile); offlinePlayers.put(uuid, player); added.put(uuid, player); } - catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) - { + catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) { PluginLogger.error("Unable to load the player {0}, skipping.", e, playerProfile.getKey()); } } - if (callbackSuccess != null) callbackSuccess.call(added); + if (callbackSuccess != null) { + callbackSuccess.call(added); + } - if (callbackErrors != null) - { + if (callbackErrors != null) { final List<String> notRetrieved = toRetrieve.stream() - .filter(pseudonym -> !result.keySet().contains(pseudonym)) + .filter(pseudonym -> !result.containsKey(pseudonym)) .collect(Collectors.toList()); - if (notRetrieved.size() > 0) callbackErrors.call(notRetrieved); + if (notRetrieved.size() > 0) { + callbackErrors.call(notRetrieved); + } } } @Override - public void errored(Throwable exception) - { + public void errored(Throwable exception) { PluginLogger.error("Unable to load players", exception); } }); diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/QSGSound.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/QSGSound.java new file mode 100644 index 0000000..3a5cde7 --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/QSGSound.java @@ -0,0 +1,359 @@ +/* + * 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.quartzsurvivalgames.utils; + +import fr.zcraft.quartzlib.components.configuration.ConfigurationParseException; +import fr.zcraft.quartzlib.components.configuration.ConfigurationValueHandler; +import fr.zcraft.quartzlib.components.configuration.ConfigurationValueHandlers; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import org.apache.commons.lang3.Validate; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; + + +/** + * Represents a sound, with volume and pitch. + * + * @author Amaury Carrade + */ +public class QSGSound { + static { + ConfigurationValueHandlers.registerHandlers(QSGSound.class); + } + + private Sound sound = null; + private Float volume = 1f; + private Float pitch = 1f; + + /** + * Constructs a sound with volume = 1f and pitch = 1f. + * + * @param sound The sound. + */ + public QSGSound(final Sound sound) { + Validate.notNull(sound, "The sound cannot be null."); + this.sound = sound; + } + + public QSGSound(final Sound sound, final Float volume, final Float pitch) { + Validate.notNull(sound, "The sound cannot be null."); + + this.sound = sound; + this.volume = volume; + this.pitch = pitch; + } + + /** + * Constructs a sound from a string name with volume = 1f and pitch = 1f. + * <p> + * This allows to support automatically all Minecraft versions as sounds names changed in enum + * after version 1.10. + * + * @param sound The sound name to be looked up. + */ + public QSGSound(final String sound) { + final Sound bukkitSound = string2Sound(sound); + + if (bukkitSound == null) { + throw new IllegalArgumentException("Cannot find a sound matching " + sound); + } + + this.sound = bukkitSound; + } + + /** + * Constructs a sound from a string name. + * <p> + * This allows to support automatically all Minecraft versions as sounds names changed in enum + * after version 1.10. + * + * @param sound The sound name to be looked up. + * @param volume The sound volume. + * @param pitch The sound pitch. + */ + public QSGSound(final String sound, final Float volume, final Float pitch) { + final Sound bukkitSound = string2Sound(sound); + + if (bukkitSound == null) { + throw new IllegalArgumentException("Cannot find a sound matching " + sound); + } + + this.sound = bukkitSound; + this.volume = volume; + this.pitch = pitch; + } + + /** + * Constructs a sound from string names with volume = 1f and pitch = 1f. + * <p> + * This allows to support automatically all Minecraft versions as sounds names changed in enum + * after version 1.10. + * + * @param sound A list of sounds to be looked up. The first one found will be used. + */ + public QSGSound(final String... sound) { + Sound bukkitSound = null; + + for (String soundCandidate : sound) { + bukkitSound = string2Sound(soundCandidate); + if (bukkitSound != null) { + break; + } + } + + if (bukkitSound == null) { + throw new IllegalArgumentException("Cannot find a sound matching one of these: " + Arrays.toString(sound)); + } + + this.sound = bukkitSound; + } + + /** + * Constructs a sound from a string name. + * <p> + * This allows to support automatically all Minecraft versions as sounds names changed in enum + * after version 1.10. + * + * @param volume The sound volume. + * @param pitch The sound pitch. + * @param sound A list of sounds to be looked up. The first one found will be used. + */ + public QSGSound(final Float volume, final Float pitch, final String... sound) { + Sound bukkitSound = null; + + for (String soundCandidate : sound) { + bukkitSound = string2Sound(soundCandidate); + if (bukkitSound != null) { + break; + } + } + + if (bukkitSound == null) { + throw new IllegalArgumentException("Cannot find a sound matching one of these: " + Arrays.toString(sound)); + } + + this.sound = bukkitSound; + this.volume = volume; + this.pitch = pitch; + } + + /** + * Constructs a sound from a configuration section. + * <p> + * Format: + * <pre> + * key: + * name: string parsable as a sound. If not parsable, null used (i.e. no sound played). + * volume: decimal number + * pitch: decimal number + * </pre> + * + * @param config The configuration section. + */ + public QSGSound(ConfigurationSection config) { + if (config == null) { + return; + } + + this.sound = string2Sound(config.getString("name")); + this.volume = (float) config.getDouble("volume"); + this.pitch = (float) config.getDouble("pitch"); + } + + /** + * Converts a string to a Sound. + * <p> + * "<code>ANVIL_LAND</code>", "<code>Anvil Land</code>" and "<code>ANVIL Land</code>" are recognized as + * <code>Sound.ANVIL_LAND</code>, as example. + * + * <p> + * If no sound match, common prefixes in the sounds name are tested. + * + * @param soundName The text to be converted. + * @return The corresponding Sound, or null if there isn't any match. + */ + public static Sound string2Sound(String soundName) { + if (soundName != null) { + soundName = soundName.trim().toUpperCase().replace(' ', '_').replace('.', '_'); + try { + return Sound.valueOf(soundName); + } + catch (IllegalArgumentException e) { + String[] prefixes = new String[] {"BLOCK_", "ENTITY_", "ITEM_", "MUSIC_", "WEATHER_"}; + for (String prefix : prefixes) { + try { + return Sound.valueOf(prefix + soundName); + } + catch (IllegalArgumentException ignored) { + } + } + + // Non-existent sound + return null; + } + } + + return null; + } + + @ConfigurationValueHandler + public static Sound handleSoundValue(final Object object) { + return string2Sound(object.toString()); + } + + @ConfigurationValueHandler + public static QSGSound handleUHSoundValue(final Map<String, Object> section) throws ConfigurationParseException { + if (!section.containsKey("name")) { + throw new ConfigurationParseException("Missing key `name` in sound (either string or list)", section); + } + + final float volume = ConfigurationValueHandlers.handleFloatValue(section.getOrDefault("volume", 1f)); + final float pitch = ConfigurationValueHandlers.handleFloatValue(section.getOrDefault("pitch", 1f)); + + final Object names = section.get("name"); + + if (names == null) { + throw new ConfigurationParseException("Missing key `name` in sound (either string or list)", section); + } else if (names instanceof Collection) { + final String[] soundNames = new String[((Collection) names).size()]; + + int i = 0; + for (final Object name : (Collection) names) { + soundNames[i++] = name.toString(); + } + + return new QSGSound(volume, pitch, soundNames); + } else { + return new QSGSound(names.toString(), volume, pitch); + } + } + + /** + * Plays the sound for the specified player. + * <p> + * The sound is played at the current location of the player. + * <p> + * If the sound is null, fails silently. + * + * @param player The player. + */ + public void play(Player player) { + play(player, player.getLocation()); + } + + /** + * Plays the sound for the specified player, at the specified location. + * <p> + * If the sound is null, fails silently. + * + * @param player The player. + * @param location The location of the sound. + */ + public void play(Player player, Location location) { + player.playSound(location, sound, volume, pitch); + } + + /** + * Plays this sound for all players, at the current location of the players. + */ + public void broadcast() { + for (Player player : Bukkit.getServer().getOnlinePlayers()) { + play(player); + } + } + + public Sound getSound() { + return sound; + } + + public void setSound(Sound sound) { + this.sound = sound; + } + + public Float getVolume() { + return volume; + } + + public void setVolume(Float volume) { + this.volume = volume; + } + + public Float getPitch() { + return pitch; + } + + public void setPitch(Float pitch) { + this.pitch = pitch; + } + + @Override + public String toString() { + return "UHSound [sound=" + sound + ", volume=" + volume + ", pitch=" + pitch + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((pitch == null) ? 0 : pitch.hashCode()); + result = prime * result + ((sound == null) ? 0 : sound.hashCode()); + result = prime * result + ((volume == null) ? 0 : volume.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof QSGSound)) { + return false; + } + + final QSGSound other = (QSGSound) obj; + if (pitch == null) { + if (other.pitch != null) { + return false; + } + } else if (!pitch.equals(other.pitch)) { + return false; + } + return sound == other.sound && (Objects.equals(volume, other.volume)); + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/utils/UHUtils.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/QSGUtils.java similarity index 58% rename from src/main/java/eu/carrade/amaury/UHCReloaded/utils/UHUtils.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/QSGUtils.java index 1a7cf68..85a6f20 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/utils/UHUtils.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/QSGUtils.java @@ -30,11 +30,17 @@ * knowledge of the CeCILL-B license and that you accept its terms. */ -package eu.carrade.amaury.UHCReloaded.utils; +package eu.carrade.amaury.quartzsurvivalgames.utils; -import fr.zcraft.zlib.tools.Callback; -import fr.zcraft.zlib.tools.PluginLogger; +import fr.zcraft.quartzlib.components.rawtext.RawText; +import fr.zcraft.quartzlib.components.rawtext.RawTextPart; +import fr.zcraft.quartzlib.tools.Callback; +import fr.zcraft.quartzlib.tools.PluginLogger; +import java.util.Random; +import java.util.stream.IntStream; +import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; +import org.bukkit.ChatColor; import org.bukkit.Color; import org.bukkit.FireworkEffect; import org.bukkit.FireworkEffect.Builder; @@ -47,41 +53,30 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.meta.FireworkMeta; -import java.util.Random; -import java.util.stream.IntStream; - -public class UHUtils -{ +public class QSGUtils { private final static Random random = new Random(); /** * Extracts a string from a list of arguments, starting at the given index. * - * @param args The raw arguments. + * @param args The raw arguments. * @param startIndex The index of the first item in the returned string (first argument given: 0). - * * @return The extracted string. - * * @throws IllegalArgumentException if the index of the first element is out of the bounds of the arguments' list. */ - public static String getStringFromCommandArguments(String[] args, int startIndex) - { - if (args.length < startIndex) - { - throw new IllegalArgumentException("The index of the first element is out of the bounds of the arguments' list."); + public static String getStringFromCommandArguments(String[] args, int startIndex) { + if (args.length < startIndex) { + throw new IllegalArgumentException( + "The index of the first element is out of the bounds of the arguments' list."); } final StringBuilder text = new StringBuilder(); - for (int index = startIndex; index < args.length; index++) - { - if (index < args.length - 1) - { + for (int index = startIndex; index < args.length; index++) { + if (index < args.length - 1) { text.append(args[index]).append(" "); - } - else - { + } else { text.append(args[index]); } } @@ -99,31 +94,26 @@ public static String getStringFromCommandArguments(String[] args, int startIndex * <li><tt>hh:mm:ss</tt> – hours, minutes and seconds.</li> * </ul> * - * * @param text The text to be converted. * @return The number of seconds represented by this string. - * * @throws IllegalArgumentException if the text is not formatted as above. - * @throws NumberFormatException if the text between the colons cannot be converted in integers. + * @throws NumberFormatException if the text between the colons cannot be converted in integers. */ - public static int string2Time(String text) - { + public static int string2Time(String text) { String[] split = text.split(":"); - if (text.isEmpty() || split.length > 3) - { - throw new IllegalArgumentException("Badly formatted string in string2time, formats allowed are mm, mm:ss or hh:mm:ss."); + if (text.isEmpty() || split.length > 3) { + throw new IllegalArgumentException( + "Badly formatted string in string2time, formats allowed are mm, mm:ss or hh:mm:ss."); } if (split.length == 1) // "mm" { return Integer.valueOf(split[0]) * 60; - } - else if (split.length == 2) // "mm:ss" + } else if (split.length == 2) // "mm:ss" { return Integer.valueOf(split[0]) * 60 + Integer.valueOf(split[1]); - } - else // "hh:mm:ss" + } else // "hh:mm:ss" { return Integer.valueOf(split[0]) * 3600 + Integer.valueOf(split[1]) * 60 + Integer.valueOf(split[2]); } @@ -131,23 +121,19 @@ else if (split.length == 2) // "mm:ss" /** * Converts a string to a number of seconds. - * + * <p> * Prints a warning if the format is invalid. * - * @param text The text to be converted. + * @param text The text to be converted. * @param defaultValue The default value returned if the format is invalid. - * * @return The extracted seconds, or the default value if invalid. * @see #string2Time(String) */ - public static int string2Time(String text, Integer defaultValue) - { - try - { + public static int string2Time(String text, Integer defaultValue) { + try { return string2Time(text); } - catch (IllegalArgumentException | NullPointerException e) - { + catch (IllegalArgumentException | NullPointerException e) { PluginLogger.warning("Invalid duration '{0}', using {1} seconds instead.", text, defaultValue); return defaultValue; } @@ -157,15 +143,14 @@ public static int string2Time(String text, Integer defaultValue) * Converts a string to a boolean. * * <p> - * {@code true, on, 1, yes} (case insensitive) -> {@code true}.<br /> - * Anything else ({@code null} included) -> {@code false}. + * {@code true, on, 1, yes} (case insensitive) -> {@code true}.<br /> + * Anything else ({@code null} included) -> {@code false}. * </p> * * @param raw The raw string. * @return a boolean. */ - public static boolean stringToBoolean(String raw) - { + public static boolean stringToBoolean(String raw) { return raw != null && ( raw.equalsIgnoreCase("true") @@ -179,9 +164,8 @@ public static boolean stringToBoolean(String raw) * @param integer An integer. * @return A string representation of this integer, with an explicit "+" if positive. */ - public static String integerToStringWithSign(int integer) - { - return (integer < 0 ? "" : "+") + String.valueOf(integer); + public static String integerToStringWithSign(int integer) { + return (integer < 0 ? "" : "+") + integer; } @@ -191,21 +175,18 @@ public static String integerToStringWithSign(int integer) * * @param player * @param location - * @param force If true the player will be teleported to the exact given location if there is no safe spot. + * @param force If true the player will be teleported to the exact given location if there is no safe spot. * @return true if the player was effectively teleported. */ - public static boolean safeTP(Player player, Location location, boolean force) - { + public static boolean safeTP(Player player, Location location, boolean force) { // If the target is safe, let's go - if (isSafeSpot(location)) - { + if (isSafeSpot(location)) { player.teleport(location); return true; } // If the teleportation is forced, let's go - if (force) - { + if (force) { player.teleport(location); return true; } @@ -213,14 +194,12 @@ public static boolean safeTP(Player player, Location location, boolean force) final Location safeSpot = searchSafeSpot(location); // A spot was found, let's teleport. - if (safeSpot != null) - { + if (safeSpot != null) { player.teleport(safeSpot); return true; } // No spot found; the teleportation is cancelled. - else - { + else { return false; } } @@ -233,45 +212,40 @@ public static boolean safeTP(Player player, Location location, boolean force) * @param location * @return true if the player was effectively teleported. */ - public static boolean safeTP(Player player, Location location) - { + public static boolean safeTP(Player player, Location location) { return safeTP(player, location, false); } /** * Searches a safe spot in the given location. - * + * <p> * The spot is in the same X;Z coordinates. * * @param location The location where to find a safe spot. * @return A Location object representing the safe spot, or null if no safe spot is available. */ - public static Location searchSafeSpot(Location location) - { + public static Location searchSafeSpot(Location location) { // We try to find a spot above or below the target Location safeSpot = null; - final int maxHeight = (location.getWorld().getEnvironment() == World.Environment.NETHER) ? 125 : location.getWorld().getMaxHeight() - 2; // (thx to WorldBorder) + final int maxHeight = (location.getWorld().getEnvironment() == World.Environment.NETHER) ? 125 : + location.getWorld().getMaxHeight() - 2; // (thx to WorldBorder) - for (int yGrow = location.getBlockY(), yDecr = location.getBlockY(); yDecr >= 1 || yGrow <= maxHeight; yDecr--, yGrow++) - { + for (int yGrow = location.getBlockY(), yDecr = location.getBlockY(); yDecr >= 1 || yGrow <= maxHeight; + yDecr--, yGrow++) { // Above? - if (yGrow < maxHeight) - { + if (yGrow < maxHeight) { Location spot = new Location(location.getWorld(), location.getBlockX(), yGrow, location.getBlockZ()); - if (isSafeSpot(spot)) - { + if (isSafeSpot(spot)) { safeSpot = spot; break; } } // Below? - if (yDecr > 1 && yDecr != yGrow) - { + if (yDecr > 1 && yDecr != yGrow) { Location spot = new Location(location.getWorld(), location.getX(), yDecr, location.getZ()); - if (isSafeSpot(spot)) - { + if (isSafeSpot(spot)) { safeSpot = spot; break; } @@ -279,8 +253,7 @@ public static Location searchSafeSpot(Location location) } // A spot was found, we changes the pitch & yaw according to the original location. - if (safeSpot != null) - { + if (safeSpot != null) { safeSpot.setPitch(location.getPitch()); safeSpot.setYaw(location.getYaw()); } @@ -296,22 +269,26 @@ public static Location searchSafeSpot(Location location) * @param location * @return true if the location is safe. */ - public static boolean isSafeSpot(Location location) - { - Block blockCenter = location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - Block blockAbove = location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() + 1, location.getBlockZ()); - Block blockBelow = location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() - 1, location.getBlockZ()); - - if ((blockCenter.getType().isTransparent() || (blockCenter.isLiquid() && !blockCenter.getType().equals(Material.LAVA) && !blockCenter.getType().equals(Material.STATIONARY_LAVA))) - && (blockAbove.getType().isTransparent() || (blockAbove.isLiquid() && !blockAbove.getType().equals(Material.LAVA) && !blockCenter.getType().equals(Material.STATIONARY_LAVA)))) - { + public static boolean isSafeSpot(Location location) { + Block blockCenter = + location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + Block blockAbove = + location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() + 1, location.getBlockZ()); + Block blockBelow = + location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() - 1, location.getBlockZ()); + + if ((blockCenter.getType().isTransparent() || + (blockCenter.isLiquid() && !blockCenter.getType().equals(Material.LAVA) && + !blockCenter.getType().equals(Material.LAVA))) + && (blockAbove.getType().isTransparent() || + (blockAbove.isLiquid() && !blockAbove.getType().equals(Material.LAVA) && + !blockCenter.getType().equals(Material.LAVA)))) { // two breathable blocks: ok // The block below is solid, or liquid (but not lava) - return blockBelow.getType().isSolid() || blockBelow.getType().equals(Material.WATER) || blockBelow.getType().equals(Material.STATIONARY_WATER); - } - else - { + return blockBelow.getType().isSolid() || blockBelow.getType().equals(Material.WATER) || + blockBelow.getType().equals(Material.LAVA); + } else { return false; } } @@ -319,22 +296,21 @@ public static boolean isSafeSpot(Location location) /** * Spawns a random firework at the given location. - * + * <p> * Please note: because the power of a firework is an integer, the min/max heights * are with a precision of ±5 blocks. * - * @param location The location where the firework will be spawned. + * @param location The location where the firework will be spawned. * @param heightMin The minimal height of the explosion. * @param heightMax The maximal height of the explosion. - * * @return The random firework generated. */ - public static Firework generateRandomFirework(Location location, int heightMin, int heightMax) - { + public static Firework generateRandomFirework(Location location, int heightMin, int heightMax) { final Firework firework = (Firework) location.getWorld().spawnEntity(location, EntityType.FIREWORK); final FireworkMeta meta = firework.getFireworkMeta(); - IntStream.range(0, random.nextInt(3) + 1).mapToObj(i -> generateRandomFireworkEffect()).forEach(meta::addEffect); + IntStream.range(0, random.nextInt(3) + 1).mapToObj(i -> generateRandomFireworkEffect()) + .forEach(meta::addEffect); // One level of power is half a second of flight time. // In half a second, a firework fly ~5 blocks. @@ -351,15 +327,16 @@ public static Firework generateRandomFirework(Location location, int heightMin, * * @return The firework effect. */ - private static FireworkEffect generateRandomFireworkEffect() - { + private static FireworkEffect generateRandomFireworkEffect() { Builder fireworkBuilder = FireworkEffect.builder(); fireworkBuilder.flicker(random.nextInt(3) == 1); fireworkBuilder.trail(random.nextInt(3) == 1); - IntStream.range(0, random.nextInt(3) + 1).mapToObj(i -> generateRandomColor()).forEach(fireworkBuilder::withColor); - IntStream.range(0, random.nextInt(3) + 1).mapToObj(i -> generateRandomColor()).forEach(fireworkBuilder::withFade); + IntStream.range(0, random.nextInt(3) + 1).mapToObj(i -> generateRandomColor()) + .forEach(fireworkBuilder::withColor); + IntStream.range(0, random.nextInt(3) + 1).mapToObj(i -> generateRandomColor()) + .forEach(fireworkBuilder::withFade); // Random shape FireworkEffect.Type[] types = FireworkEffect.Type.values(); @@ -373,8 +350,7 @@ private static FireworkEffect generateRandomFireworkEffect() * * @return The color. */ - private static Color generateRandomColor() - { + private static Color generateRandomColor() { return Color.fromBGR(random.nextInt(256), random.nextInt(256), random.nextInt(256)); } @@ -383,11 +359,12 @@ private static Color generateRandomColor() * * @param callback The callback * @param argument The callback's argument. - * @param <T> The callback's argument type. + * @param <T> The callback's argument type. */ - public static <T> void callIfDefined(Callback<T> callback, T argument) - { - if (callback != null) callback.call(argument); + public static <T> void callIfDefined(Callback<T> callback, T argument) { + if (callback != null) { + callback.call(argument); + } } /** @@ -395,10 +372,90 @@ public static <T> void callIfDefined(Callback<T> callback, T argument) * * @return the... overworld? */ - public static World getOverworld() - { + public static World getOverworld() { return Bukkit.getServer().getWorlds().stream() - .filter(world -> world.getEnvironment() != World.Environment.NETHER && world.getEnvironment() != World.Environment.THE_END) + .filter(world -> world.getEnvironment() != World.Environment.NETHER && + world.getEnvironment() != World.Environment.THE_END) .findFirst().orElse(null); } + + /** + * Returns the next (or other...) enum value, as declared in the source + * code. + * + * @param enumValue An enum value. + * @param shift A shift. If this is positive, will return the (shift)th + * element after, else the |shift|th element before. The enum + * is visited as a cycle. + * @return The next/previous/other enum value, according to shift. + */ + public static <T extends Enum> T getNextElement(final T enumValue, final int shift) { + return getNextElement(enumValue, shift, false, null); + } + + /** + * Returns the next (or other...) enum value, as declared in the source + * code. + * + * @param enumValue An enum value. + * @param shift A shift. If this is positive, will return the (shift)th + * element after, else the |shift|th element before. The enum + * is visited as a cycle. + * @param shiftThroughNull If {@code true}, will return {@code null} after the + * last element, and the first element after {@code null}. + * Else, will throw an {@link IllegalArgumentException} if + * the given element is {@code null}. + * @param enumClass The (non-empty) enum class, required if + * {@code shiftThroughNull = true}. Else, can be {@code null}. + * @param <T> The enum type. + * @return The next/previous/other enum value, according to shift. + */ + public static <T extends Enum> T getNextElement(final T enumValue, final int shift, final boolean shiftThroughNull, + Class<T> enumClass) { + Validate.isTrue(shiftThroughNull || enumValue != null, + "The enum value cannot be null with shiftThroughNull = false."); + + if (enumValue != null) { + enumClass = (Class<T>) enumValue.getClass(); + } + + final T[] values = enumClass.getEnumConstants(); + final int ord = enumValue != null ? enumValue.ordinal() : values.length; + + final int shiftLength = shiftThroughNull ? values.length + 1 : values.length; + + int newOrd = (ord + shift) % shiftLength; + if (newOrd < 0) { + newOrd += shiftLength; + } + + if (shiftThroughNull && newOrd == values.length) { + return null; + } + return values[newOrd]; + } + + /** + * Generates a message prefixed with a prefix and a separator, for chat. + * + * @param prefix The prefix. + * @param message The message. + * @return The formatted prefixed message. + */ + public static String prefixedMessage(final String prefix, final String message) { + return ChatColor.GREEN + prefix + ChatColor.GRAY + " \u2758 " + ChatColor.RESET + message; + } + + /** + * Generates a RawText containing the prefix of a message plus the separator. Just like {@link #prefixedMessage(String, String)}, + * but compatible with RawTexts. + * + * @param prefix The prefix. + * @return The RawText, ready to be extended. + */ + public static RawTextPart prefixedRaxText(final String prefix) { + return new RawText() + .then(prefix).color(ChatColor.GREEN) + .then(" \u2758 ").color(ChatColor.GRAY); + } } diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipeUtil.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/RecipesUtils.java similarity index 76% rename from src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipeUtil.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/RecipesUtils.java index c34dc3e..cfb728d 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipeUtil.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/RecipesUtils.java @@ -29,35 +29,28 @@ * 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.recipes; -import org.bukkit.inventory.FurnaceRecipe; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.Recipe; -import org.bukkit.inventory.ShapedRecipe; -import org.bukkit.inventory.ShapelessRecipe; +package eu.carrade.amaury.quartzsurvivalgames.utils; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Map; +import org.bukkit.inventory.FurnaceRecipe; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.ShapelessRecipe; /** * Utility class to compare Bukkit recipes.<br> * Useful for identifying your recipes in events, where recipes are re-generated in a different manner. * - * @version R1.3 * @author Digi + * @version R1.3 */ -public class RecipeUtil -{ - /** - * The wildcard data value for ingredients.<br> - * If this is used as data value on an ingredient it will accept any data value. - */ - public static final short DATA_WILDCARD = Short.MAX_VALUE; - +public class RecipesUtils { /** * Checks if both recipes are equal.<br> * Compares both ingredients and results.<br> @@ -67,12 +60,12 @@ public class RecipeUtil * @param recipe1 the first recipe * @param recipe2 the second recipe * @return true if ingredients and results match, false otherwise. - * @throws IllegalArgumentException - * if recipe is other than ShapedRecipe, ShapelessRecipe or FurnaceRecipe. + * @throws IllegalArgumentException if recipe is other than ShapedRecipe, ShapelessRecipe or FurnaceRecipe. */ - public static boolean areEqual(Recipe recipe1, Recipe recipe2) - { - return recipe1 == recipe2 || !(recipe1 == null || recipe2 == null) && recipe1.getResult().equals(recipe2.getResult()) && match(recipe1, recipe2); + public static boolean areEqual(Recipe recipe1, Recipe recipe2) { + return recipe1 == recipe2 || + !(recipe1 == null || recipe2 == null) && recipe1.getResult().equals(recipe2.getResult()) && + match(recipe1, recipe2); } @@ -85,20 +78,15 @@ public static boolean areEqual(Recipe recipe1, Recipe recipe2) * @param recipe1 the first recipe * @param recipe2 the second recipe * @return true if ingredients match, false otherwise. - * @throws IllegalArgumentException - * if recipe is other than ShapedRecipe, ShapelessRecipe or FurnaceRecipe. + * @throws IllegalArgumentException if recipe is other than ShapedRecipe, ShapelessRecipe or FurnaceRecipe. */ - public static boolean areSimilar(Recipe recipe1, Recipe recipe2) - { + public static boolean areSimilar(Recipe recipe1, Recipe recipe2) { return recipe1 == recipe2 || !(recipe1 == null || recipe2 == null) && match(recipe1, recipe2); } - private static boolean match(Recipe recipe1, Recipe recipe2) - { - if (recipe1 instanceof ShapedRecipe) - { - if (!(recipe2 instanceof ShapedRecipe)) - { + private static boolean match(Recipe recipe1, Recipe recipe2) { + if (recipe1 instanceof ShapedRecipe) { + if (!(recipe2 instanceof ShapedRecipe)) { return false; // if other recipe is not the same type then they're not equal. } @@ -109,7 +97,8 @@ private static boolean match(Recipe recipe1, Recipe recipe2) final ItemStack[] matrix1 = shapeToMatrix(r1.getShape(), r1.getIngredientMap()); final ItemStack[] matrix2 = shapeToMatrix(r2.getShape(), r2.getIngredientMap()); - if (!Arrays.equals(matrix1, matrix2)) // compare arrays and if they don't match run another check with one shape mirrored. + if (!Arrays.equals(matrix1, + matrix2)) // compare arrays and if they don't match run another check with one shape mirrored. { mirrorMatrix(matrix1); @@ -117,11 +106,8 @@ private static boolean match(Recipe recipe1, Recipe recipe2) } return true; // ingredients match. - } - else if (recipe1 instanceof ShapelessRecipe) - { - if (!(recipe2 instanceof ShapelessRecipe)) - { + } else if (recipe1 instanceof ShapelessRecipe) { + if (!(recipe2 instanceof ShapelessRecipe)) { return false; // if other recipe is not the same type then they're not equal. } @@ -132,25 +118,19 @@ else if (recipe1 instanceof ShapelessRecipe) final List<ItemStack> find = r1.getIngredientList(); final List<ItemStack> compare = r2.getIngredientList(); - if (find.size() != compare.size()) - { + if (find.size() != compare.size()) { return false; // if they don't have the same amount of ingredients they're not equal. } - for (ItemStack item : compare) - { - if (!find.remove(item)) - { + for (ItemStack item : compare) { + if (!find.remove(item)) { return false; // if ingredient wasn't removed (not found) then they're not equal. } } return find.isEmpty(); // if there are any ingredients not removed then they're not equal. - } - else if (recipe1 instanceof FurnaceRecipe) - { - if (!(recipe2 instanceof FurnaceRecipe)) - { + } else if (recipe1 instanceof FurnaceRecipe) { + if (!(recipe2 instanceof FurnaceRecipe)) { return false; // if other recipe is not the same type then they're not equal. } @@ -158,22 +138,17 @@ else if (recipe1 instanceof FurnaceRecipe) final FurnaceRecipe r2 = (FurnaceRecipe) recipe2; return r1.getInput().getType() == r2.getInput().getType(); - } - else - { + } else { throw new IllegalArgumentException("Unsupported recipe type: '" + recipe1 + "', update this class!"); } } - private static ItemStack[] shapeToMatrix(String[] shape, Map<Character, ItemStack> map) - { + private static ItemStack[] shapeToMatrix(String[] shape, Map<Character, ItemStack> map) { final ItemStack[] matrix = new ItemStack[9]; int slot = 0; - for (int r = 0; r < shape.length; r++) - { - for (char col : shape[r].toCharArray()) - { + for (int r = 0; r < shape.length; r++) { + for (char col : shape[r].toCharArray()) { matrix[slot] = map.get(col); slot++; } @@ -184,12 +159,10 @@ private static ItemStack[] shapeToMatrix(String[] shape, Map<Character, ItemStac return matrix; } - private static void mirrorMatrix(ItemStack[] matrix) - { + private static void mirrorMatrix(ItemStack[] matrix) { ItemStack tmp; - for (int r = 0; r < 3; r++) - { + for (int r = 0; r < 3; r++) { tmp = matrix[(r * 3)]; matrix[(r * 3)] = matrix[(r * 3) + 2]; matrix[(r * 3) + 2] = tmp; @@ -200,22 +173,16 @@ private static void mirrorMatrix(ItemStack[] matrix) /** * Returns the list of the ingredients of the given recipe. * - * @author Amaury Carrade - * * @param recipe The recipe to analyze. * @return A list of the ingredients. + * @author Amaury Carrade */ - public static List<ItemStack> getListOfIngredients(Recipe recipe) - { + public static List<ItemStack> getListOfIngredients(Recipe recipe) { List<ItemStack> listOfItems; - if (recipe instanceof ShapelessRecipe) - { + if (recipe instanceof ShapelessRecipe) { listOfItems = ((ShapelessRecipe) recipe).getIngredientList(); - } - else - { - try - { + } else { + try { listOfItems = new LinkedList<>(((ShapedRecipe) recipe).getIngredientMap().values()); } catch (NullPointerException e) // If the list of items is null @@ -226,4 +193,4 @@ public static List<ItemStack> getListOfIngredients(Recipe recipe) return listOfItems; } -} \ No newline at end of file +} diff --git a/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/Run.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/Run.java new file mode 100644 index 0000000..4d519ee --- /dev/null +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/Run.java @@ -0,0 +1,208 @@ +/* + * Plugin UHCReloaded : Alliances + * + * Copyright ou © ou Copr. Amaury Carrade (2016) + * Idées et réflexions : Alexandre Prokopowicz, Amaury Carrade, "Vayan". + * + * Ce logiciel est régi par la licence CeCILL soumise au droit français et + * respectant les principes de diffusion des logiciels libres. Vous pouvez + * utiliser, modifier et/ou redistribuer ce programme sous les conditions + * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + * sur le site "http://www.cecill.info". + * + * En contrepartie de l'accessibilité au code source et des droits de copie, + * de modification et de redistribution accordés par cette licence, il n'est + * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + * seule une responsabilité restreinte pèse sur l'auteur du programme, le + * titulaire des droits patrimoniaux et les concédants successifs. + * + * A cet égard l'attention de l'utilisateur est attirée sur les risques + * associés au chargement, à l'utilisation, à la modification et/ou au + * développement et à la reproduction du logiciel par l'utilisateur étant + * donné sa spécificité de logiciel libre, qui peut le rendre complexe à + * manipuler et qui le réserve donc à des développeurs et des professionnels + * avertis possédant des connaissances informatiques approfondies. Les + * utilisateurs sont donc invités à charger et tester l'adéquation du + * logiciel à leurs besoins dans des conditions permettant d'assurer la + * sécurité de leurs systèmes et ou de leurs données et, plus généralement, + * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + * + * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + * pris connaissance de la licence CeCILL, et que vous en avez accepté les + * termes. + */ + +package eu.carrade.amaury.quartzsurvivalgames.utils; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.timers.TimeDelta; +import fr.zcraft.quartzlib.tools.runners.RunTask; +import fr.zcraft.quartzlib.tools.text.ActionBar; +import fr.zcraft.quartzlib.tools.text.MessageSender; +import java.util.function.Function; +import java.util.function.Supplier; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +public class Run { + private final static String ACTION_BAR_SEPARATOR = " " + ChatColor.GRAY + "\u2758" + ChatColor.RESET + " "; + + /** + * Executes a task after a delay, displaying a countdown in the players' + * action bar at the end. + * + * @param title A title displayed in the left of the action bar. + * @param subtitle A subtitle displayed during the whole countdown in + * the right of the action bar. If {@code null}, the + * action bar will only display something when the + * countdown will be about to end. + * @param subtitleDuringCountdown A subtitle displayed during the last + * seconds of the cooldown. Receives the + * current second (will be decreasing) and + * returns a subtitle. + * @param subtitleAfter A subtitle displayed a few seconds after the task + * has been run, e.g. to display a message stating that + * the task is done. If {@code null}, the last countdown + * message wil simply fade out. + * @param receivers The players who will receive the countdown in their + * action bar. + * @param task The task to execute after the delay. + * @param delay The delay. + */ + public static void withCountdown( + final String title, + final String subtitle, + final Function<Short, String> subtitleDuringCountdown, + final String subtitleAfter, + final Supplier<Iterable<Player>> receivers, + final Runnable task, + final TimeDelta delay) { + withCountdown(title, subtitle, subtitleDuringCountdown, subtitleAfter, (short) 5, receivers, task, delay); + } + + /** + * Executes a task after a delay, displaying a countdown in the players' + * action bar at the end. + * + * @param title A title displayed in the left of the action bar. + * @param subtitle A subtitle displayed during the whole countdown in + * the right of the action bar. If {@code null}, the + * action bar will only display something when the + * countdown will be about to end. + * @param subtitleDuringCountdown A subtitle displayed during the last + * seconds of the cooldown. Receives the + * current second (will be decreasing) and + * returns a subtitle. + * @param visibleCountdownBefore When there will be less than this number of + * seconds before the end of the countdown, + * the subtitle will switch from the defined + * static subtitle to the visible countdown. + * @param receivers The players who will receive the countdown in their + * action bar. + * @param task The task to execute after the delay. + * @param delay The delay. + */ + public static void withCountdown( + final String title, + final String subtitle, + final Function<Short, String> subtitleDuringCountdown, + final String subtitleAfter, + final short visibleCountdownBefore, + final Supplier<Iterable<Player>> receivers, + final Runnable task, + final TimeDelta delay) { + // The countdown is not visible at the beginning + if (visibleCountdownBefore < delay.getSeconds()) { + if (subtitle != null) { + final Iterable<Player> initialReceivers = receivers.get(); + initialReceivers.forEach( + receiver -> ActionBar.sendPermanentMessage(receiver, title + ACTION_BAR_SEPARATOR + subtitle)); + + // As the receivers list is recalculated each time (to allow for new players), this ensures + // players who received the initial message will not have it kept during the whole game + // if they were disconnected at the end. + RunTask.later(() -> initialReceivers.forEach(ActionBar::removeMessage), + (delay.getSeconds() - visibleCountdownBefore) * 20L); + } + + RunTask.timer( + new CountdownRunnable( + title, + subtitleDuringCountdown, subtitleAfter, + receivers, + visibleCountdownBefore, + task + ), + (delay.getSeconds() - visibleCountdownBefore) * 20L, 20L + ); + } + + // The countdown is immediately visible. + else { + RunTask.timer( + new CountdownRunnable( + title, + subtitleDuringCountdown, subtitleAfter, + receivers, + (short) delay.getSeconds(), + task + ), + 0L, 20L + ); + } + } + + private static class CountdownRunnable extends BukkitRunnable { + private final String title; + private final Function<Short, String> subtitleDuringCountdown; + private final String subtitleAfter; + private final Supplier<Iterable<Player>> receivers; + private final Runnable task; + private short secondsLeft; + + private CountdownRunnable( + final String title, + final Function<Short, String> subtitleDuringCountdown, + final String subtitleAfter, + final Supplier<Iterable<Player>> receivers, + final short secondsLeft, + final Runnable task) { + this.title = title; + this.subtitleDuringCountdown = subtitleDuringCountdown; + this.subtitleAfter = subtitleAfter; + this.receivers = receivers; + this.secondsLeft = secondsLeft; + this.task = task; + } + + @Override + public void run() { + if (secondsLeft == 0) { + if (subtitleAfter != null) { + final Iterable<Player> finalReceivers = receivers.get(); + finalReceivers.forEach(receiver -> ActionBar + .sendPermanentMessage(receiver, title + ACTION_BAR_SEPARATOR + subtitleAfter)); + + RunTask.later(() -> finalReceivers.forEach(ActionBar::removeMessage), 60L); + } else { + receivers.get() + .forEach(receiver -> MessageSender.sendActionBarMessage( + receiver, + title + ACTION_BAR_SEPARATOR + subtitleDuringCountdown.apply(secondsLeft) + )); + } + + task.run(); + cancel(); + } else { + receivers.get() + .forEach(receiver -> MessageSender.sendActionBarMessage( + receiver, + title + ACTION_BAR_SEPARATOR + subtitleDuringCountdown.apply(secondsLeft) + )); + + secondsLeft--; + } + } + } +} diff --git a/src/main/java/eu/carrade/amaury/UHCReloaded/utils/TextUtils.java b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/TextUtils.java similarity index 78% rename from src/main/java/eu/carrade/amaury/UHCReloaded/utils/TextUtils.java rename to src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/TextUtils.java index 6298d81..2cd378c 100644 --- a/src/main/java/eu/carrade/amaury/UHCReloaded/utils/TextUtils.java +++ b/src/main/java/eu/carrade/amaury/quartzsurvivalgames/utils/TextUtils.java @@ -29,37 +29,38 @@ * 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.utils; -import com.google.common.collect.Sets; -import org.apache.commons.lang.WordUtils; +package eu.carrade.amaury.quartzsurvivalgames.utils; +import com.google.common.collect.Sets; import java.util.Set; +import org.apache.commons.lang.WordUtils; -public final class TextUtils -{ - private TextUtils() {} - +public final class TextUtils { private static final Set<String> SMALL_WORDS = Sets.newHashSet( // English "the", "a", "it", "they", "them", "an", "all", "of", "this", "is", "not", "that", // French - "un", "une", "le", "la", "les", "des", "je", "tu", "il", "elle", "on", "nous", "vous", "ils", "elles", "ça", "ca", "sa", "cela", "lui", "l" + "un", "une", "le", "la", "les", "des", "je", "tu", "il", "elle", "on", "nous", "vous", "ils", "elles", "ça", + "ca", "sa", "cela", "lui", "l" ); + private TextUtils() { + } + /** * Tries to find a single alphanumeric character best representing this string. * * @param text The string. * @return An alphanumeric character. A space if the initial text is blank. */ - public static char getInitialLetter(String text) - { + public static char getInitialLetter(String text) { text = toAlphanumeric(text); - if (text == null || text.isEmpty()) + if (text == null || text.isEmpty()) { return ' '; + } // We try to find the main word of the sentence, based on four principles: // - the main word is likely to be at the beginning of the string; @@ -70,32 +71,34 @@ public static char getInitialLetter(String text) String[] words = text.split(" "); Integer bestScore = Integer.MIN_VALUE; - String bestWord = " "; + String bestWord = " "; int averageWordLength = 0; - for (String word : words) + for (String word : words) { averageWordLength += word.length(); + } averageWordLength /= words.length; - for (int i = 0, wordsCount = words.length; i < wordsCount; i++) - { + for (int i = 0, wordsCount = words.length; i < wordsCount; i++) { String word = words[i].toLowerCase(); Integer score = 0; - if (i < 3) + if (i < 3) { score += 5; + } - if (word.length() == 1) + if (word.length() == 1) { score -= 3; - else if (word.length() >= averageWordLength) + } else if (word.length() >= averageWordLength) { score += 5; + } - if (SMALL_WORDS.contains(word)) + if (SMALL_WORDS.contains(word)) { score -= 10; + } - if (score > bestScore) - { + if (score > bestScore) { bestScore = score; bestWord = words[i]; } @@ -110,30 +113,33 @@ else if (word.length() >= averageWordLength) * @param text The text. * @return The same text, without non-alphanumeric characters. */ - public static String toAlphanumeric(String text) - { - if (text == null) return null; + public static String toAlphanumeric(String text) { + if (text == null) { + return null; + } final StringBuilder builder = new StringBuilder(); - for (Character character : text.toCharArray()) - { + for (Character character : text.toCharArray()) { // Convert all kind of spaces (unbreakable...) and apostrophes to basic spaces - if (Character.isSpaceChar(character) || character.equals('\'')) + if (Character.isSpaceChar(character) || character.equals('\'')) { builder.append(" "); + } - if (Character.isTitleCase(character)) + if (Character.isTitleCase(character)) { character = Character.toUpperCase(character); + } // Only keeps alphanumeric characters - if ((character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z') || (character >= '0' && character <= '9')) + if ((character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z') || + (character >= '0' && character <= '9')) { builder.append(character); + } } return builder.toString(); } - public static String friendlyEnumName(Enum<?> enumConstant) - { + public static String friendlyEnumName(Enum<?> enumConstant) { return WordUtils.capitalizeFully(enumConstant.name().replace("_", " ")); } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b5d5558..a20b7bd 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,569 +1,34 @@ # # ## Welcome in the UltraHardcore Reloaded configuration file ## -# -# -# About the "sound" configuration, the format is always the same: -# sound: -# name: The name of the sound. Names: see http://l.carrade.eu/bukkit-sounds . Set to "NONE" to disable. -# volume: The volume of the sound. 1 is the normal volume. You can use a decimal value. -# pitch: The pitch of the sound. 1 is the normal pitch. You can use a decimal value. -# -# Warning: NEVER USE TABS in this file, always spaces, to indent. - - -# Available languages: en_US, fr_FR, pt_PT, pt_BR, cs_CZ, zh_CN. -# Empty value: system language. -lang: - - - -episodes: - enabled: true - - # Format: "mm", "mm:ss" or "hh:mm:ss". If invalid, 20 minutes. - # Don't remove the "quotes" (because of the commas)! - length: "20:00" - - # A title is displayed when the episode changes. - title: true - - - -map: - # The diameter of the map (not the radius!), in blocks. - size: 2000 - - # "squared" or "circular". Affects the WorldBorder pre-configuration, and the - # wall generator used. - shape: "squared" - - wall: - height: 128 - block: - # The replaceAir block will be placed where there where some transparent blocks or trees before. - # The replaceSolid one, where there was an other kind of block. - replaceAir: GLASS - replaceSolid: BEDROCK - - border: - # The world border manager. Can be: - # - "vanilla", to use the vanilla world border; or - # - "brettflan", to use the WorldBorder Bukkit plugin by Brettflan - # (http://dev.bukkit.org/bukkit-plugins/worldborder/). - # - # If the shape is "circular", fallbacks to "brettflan" as the vanilla world border don't - # support circular borders. And if the WorldBorder plugin is not installed, fallbacks to - # no border. - motor: "vanilla" - - # The amount of blocks a player may safely be outside the border before taking damage. - # Only for the vanilla world border. Ignored else. - damagesBuffer: 5 - - # The amount of damage a player takes when outside the border plus the border buffer. - # The damages delt is calculated by multiplying this amount by the number of blocks behind the buffer. - # Only for the vanilla world border. Ignored else. - damagesAmount: 0.2 - - # The warning distance that causes the screen to be tinted red when the player is within the specified - # number of blocks from the border. - # Only for the vanilla world border. Ignored else. - warningDistance: 5 - - - # You can display the border size in the scoreboard; see `scoreboard.border`. - - - # Automatic and progressive border shrinking. - # Notice: if the border is circular, the WorldBorder Bukkit plugin by Brettflan (see above) - # is REQUIRED. Without, the border shrinking will not work. - shrinking: - enabled: false - - # Formats: "mm", "mm:ss" or "hh:mm:ss". - # With the default values, the border eats one block every 8 seconds on each side. - startsAfter: "30:00" - shrinksDuring: "2:00:00" - diameterAfterShrink: 200 - - - # The delay between two warning messages sent to the players out of a future border - # (this warning is set using /uh border warning <futureDiameter>). - warningInterval: 90 # seconds - - spawnPoints: - # Don't generate the spawn points (with /uh spawns generate) above the water? - dontGenerateAboveWater: true - - - -daylightCycle: - do: false - time: 6000 # Initial time (or game time if the daylight cycle is disabled) in ticks. 6000 = noon. - - - -scoreboard: - title: Kill the Patrick - - # Scoreboard displayed on the left of the screen - enabled: true - episode: true - players: true - teams: true - ownTeam: - enabled: true # Displays the player's team in the scoreboard - title: - color: "" # The color of the title. If empty, the team color is used. - useTeamName: false # If true, the title is the team's name. Else, a generic title (« Your team »). - content: - displayHearts: true # Displays hearts colored following the player's life (low = red, high = green) - colorName: false # Color the whole name, not only the heart, following the life. If disabled the name is white (alive) or gray (dead). - strikeDeadPlayers: false # Strike the dead players lines. - loginState: - italic: true # Logged-out players are displayed in italic - suffix: "\u27A5" # This string is displayed after the name of logged-out players - displayMetPlayersOnly: - enabled: false # If enabled, the sidebar will only contains players met at some time. - displayedWhenCloserThan: 10 # If enabled, a teammate will be displayed to the reference player if he/she is closer that this amount of blocks to the player. - border: - displayed: true - displayDiameter: false # If true, displays the border diameter (ex. "2000 blocks wide"). Else, the min/max coordinates (ex. "-1000 +1000"). Ignored if the border is circular. - kills: true - timer: true - freezeStatus: true - - # Health in the list of the players - health: true - - - -# Controls what is displayed in the tab list headers and footers. -# Tags: -# - {title}: contains the scoreboard title (key scoreboard.title). -# - {episodeText}: contains the localized “Episode x” text. -# - {playersText}: contains the localized “x players left” text. -# - {teamsText}: contains the localized “x teams left” text. -# - {episodeNumber}: contains the raw episode number (e.g. “2”). -# - {playersCount}: contains the raw alive players count (e.g. “18”). -# - {teamsCount}: contains the raw alive teams count (e.g. “6”). -# You can use color & formatting codes with either & or §. -# If you want, you can use "\n" to create a new line. -playersList: - waitingTime: - header: "{title}" - footer: "" - inGameTime: - header: "{title}" - footer: "§a{episodeText} §7- §a{playersText} §7- §a{teamsText}" - - - -# Update the MOTD according to the current state of the game? -# This will overwrite the original MOTD. -motd: - enabled: false - - # Display the name of the match ("scoreboard.title") in the first line of the MOTD? - displayMatchName: true - # This will be displayed before the match name (formatting...) - matchNamePrefix: "" - - -# Teleport the players to the spawn point on login if the game is not started? -# Avoids the random spawn point of Minecraft, and teleports them back to -# there if they log out then in. -teleportToSpawnIfNotStarted: true - - - -achievements: - # When a player joins the game before the beginning of the game, his achievements are reset? - resetAchievementsAtStartup: true - - # A player cannot award an achievement if the game is not started? - disableAchievementsBeforeStart: true - - - -statistics: - # A player cannot increment a statistic if the game is not started? - disableStatisticsBeforeStart: true - - - -before-start: - inventory: - # True to clear the inventory of the players before the beginning of the game. - clear: true - - # True to prevent users from using their inventory when the game is not started. - preventUsage: true - - # True to disable all the inventory points above for players with the uh.build permission. - allowForBuilders: true - - teamSelector: - # True to give to the players a team selector, opening the teams inventory GUI (same as /teams). - enabled: true - - # The item to use as the team selector. Right-clicking it will open the GUI. - item: NETHER_STAR - - # Displays the current team in the action bar before the game. Nothing is displayed if the player is - # not in a team. - teamInActionBar: true - - enablePVP: false - - -start: - slow: - delayBetweenTP: 3 # in seconds - broadcastProgress: true # Displays something like « Teleporting... (14/28) » in the action bar for every player. - - cages: - # Instead of flying above the ground, if this is enabled, players will wait for the game start in - # cages, built in the material you want. - enabled: true - - # The cage type. Can be: - # - team_color_transparent (stained glass using the team color, or white without color/for solo); - # - team_color_solid (the same with stained hardened clay); - # - custom (a custom block, configure the one to use after). - type: team_color_transparent - - # If you selected “custom” before, write here the block you want to use. It can be any valid Material. - # You can use safely any falling block here, they will never fall. - customBlock: - - # If true, the cages will be built completly, including the ceiling. Else, they will be open to the sky. - buildCeiling: false - - # If true, the walls will be built using the block above. Else, using barrier blocks. - visibleWalls: true - - # The internal square radius of the cage. - # With 0, you'll have a cage with one block to walk. - # With 1, you'll have a 3×3 cage. - # With 2, a 5×5 cage. Etc. - radius: 1 - - # The internal height of the cages, i.e. the height of the space available to the players inside the cage. - height: 3 - - sound: - name: NONE - volume: 1 - pitch: 1 - - # Display a title to everyone when the game begins - displayTitle: true - - # Damages are enabled after this amount of time. - # Cannot be less than 15 seconds, to avoid initial-fall-related problems. - # Format: "mm", "mm:ss", "hh:mm:ss" - gracePeriod: "00:30" - - # If true, a message will be broadcasted when the grace period ends. - broadcastGraceEnd: true - - # PVP is enabled after this amount of time. - # If 0, enabled immediately. - # Format: "mm", "mm:ss", "hh:mm:ss" - peacePeriod: 0 - - # The hostile mobs will not be allowed to spawn on the surface during this amount of time after - # the beginning of the game. This prevents mobs from lightning errors to cause deaths during the - # early game, when players just started and are not protected. - # This option is here to prevent lightning-bugs-related deaths or damages, so spawns on surface - # areas normally dark (like overhangs or floating islands) are not cancelled. Also, mobs will - # still spawn on caves. - # Format: "mm", "mm:ss", "hh:mm:ss". To disable, set to 0. - surfaceMobsFreePeriod: "15:00" - - - -death: - messages: - notifyIfTeamHasFallen: true - deathMessagesFormat: "§6" # Use this to increase visibility of death messages. - teamDeathMessagesFormat: "§6" - - kick: - do: false - time: 30 - allow-reconnect: true - - head: - drop: true - pvpOnly: false - - give-xp-to-killer: - levels: 2 # set to 0 to disable - onlyOtherTeam: true # Give XP only if the player kills a player from another team? - - announcements: - lightning-strike: false - - sound: - name: WITHER_SPAWN - volume: 1 - pitch: 1 - - - -# If true, the name of the players will be colorized according to the teams. -colorizeChat: true - - - -gameplay-changes: - naturalRegeneration: false # If true, the health will regenerate with food (just like in the default vanilla game). - - weather: true # If false, the "bad" weather (rain, thunder) is disabled. - - replaceGhastTearsWithGold: true - craftGoldenMelonWithGoldBlock: true - - craftGoldenAppleFromHead: - fromHuman: - do: true - numberCrafted: 2 - addLore: true - craftNotchApple: false - fromWither: - do: true - numberCrafted: 1 - addLore: true - craftNotchApple: false - - goldenApple: - regeneration: - # Half-hearts regenerated by one apple. Vanilla: normal 4, notch 180 (yes, 180). - normal: 4 - notch: 180 - fromNormalHead: 4 - fromNotchHead: 180 - - disableNotchApples: false - - disableEnderpearlsDamages: true - - disableLevelIIPotions: false - - witch: - disableNaturalSpawn: false - disableLightningSpawn: false # from a villager - - rabbit: - killerRabbitSpawn: true - # When a rabbit spawns, it will be transformed into a Killer Rabbit following - # this probability (between 0 and 1). - killerRabbitSpawnProbability: 0.05 - # The rabbit will be named after this configuration point, except if empty - then, the - # default vanilla name will be used ("The Killer Bunny"). - killerRabbitName: "The Killer Rabbit of Caerbannog" - - - # If true a compass will show the nearest player, and the craft will be different. - # Else, the craft will be standard and the compass will show the spawn point of the team/player (not the world spawn point). - compass: - enabled: true - - # The special recipe is with an ingredient in the center, and then, - # from the top, clockwise: iron, spider eye, iron, rotten flesh, iron, bone, iron, gunpowder. - # This field change the central ingredient. - # "easy": redstone (like the normal compass). - # "medium": ender pearl. - # "hard": eye of ender. - recipe: "medium" - - - -teams-options: - canSeeFriendlyInvisibles: true - allowFriendlyFire: true - - # 0 = unlimited. - maxPlayersPerTeam: 0 - - # Randoms colors for solo games and solo teams (i.e. all the teams generated when the game starts)? - # If false, no color (aka white) used. - randomColors: true - - # These options are related to the auto-generated banner of each team. - # This banner is used on the teams selector (if set to "banner"), and can be given to the - # players when the game starts. - banner: - shape: - writeLetter: true - addBorder: true - give: - placeOnSpawn: true # Places the team banner on the spawn point. - giveInHotbar: false # Gives a banner to each player. - giveInHead: false # Places the banner on the head of each player. - shields: - addOnShields: true # Crafted shields will have the team banner on them. MC 1.9+ only. - - - # Chat-based GUI to choose a team - gui: - # Display the players in each team, in the tooltip linked to the players count? - displayPlayersInTeams: true - - # Display the GUI when a player login out of any team? - autoDisplay: true - # Delay between the login and the display? (Seconds) - delay: 4 - - # Chest-based GUI to choose a team and manage the teams - chestGui: - display: - teamItem: "banner" # Values: "banner", "glass", "glass_pane", "clay", "wool", "dye" - glowOnSelectedTeam: true # Set to true to display an enchantment glow on the player team - - teamChat: - # Forces disable the team-chat when the player die. - # If you use SpectatorPlus with the block-commands option enabled, this will prevent spectators - # from using the team chat. - disableLockOnDeath: true - - # Log the private team-chat in the console? - log: false - - - -hardcore-hearts: - # Display hardcore hearts instead of normal ones? - display: true - - # If a player die, his client will display an hardcore Game Over screen, without a « Respawn » button. - # But the player CAN respawn, by clicking « Leave server » and then, on the confirmation screen, - # « Respawn ». - # With this option enabled, a short message will notify the player about that. - # Notice: this will be disabled even with this set to true if the hardcore hearts are not enabled (useless). - respawnMessage: false - - - -# Automatically respawn the player after his death. -# Avoid the interrogation about the ability to respawn, if hardcore hearts are enabled. -auto-respawn: - do: true - delay: 6 # seconds - - - -# Controls the behavior of the /uh finish command -finish: - auto: - do: true # Execute /uh finish automatically a few seconds after the final death? - timeAfterLastDeath: 3 # The command will be executed this amount of seconds after the last death. - - message: true # If true, the name of the winner(s) will be broadcasted. - title: true # If true, a title will display the winner(s) of the game. - - fireworks: - enabled: true # If true, some fireworks will be launched at the location of the winners. - duration: 10 # In seconds. - areaSize: 6 # The size of the square, centered on each player, where the fireworks will be launched. - - - -dynmap: - showSpawnLocations: true - showDeathLocations: true - - - -# Enable spectator mode for player joining the game after the beginning -# (only for out-of-the-UHC players of course)? -spectatorModeWhenNewPlayerJoinAfterStart: true - - - -# Rules are a way to display rules & other informations to the players. -# The content is completly up to you, formatting included (using standard -# formatting codes with either § or &). It will be displayed as a list to -# the players (one bullet per line in the `rules.rules` entry). -# Empty entries (« - "" ») are replaced by a completly blank line, if you -# need a separator. -rules: - display: - onJoin: false - onStart: true - rules: - - - - - -# Execute commands during the game or after the end of it, and after a configurable delay? -# Format explained below. -# Respect the spaces before the keywords ("exec" and "delay" need to be aligned). -commands: - # Commands executed when the server starts. - # These commands are also executed when the server is reloaded. - execute-server-start: - #- exec: command args - # delay: "40:00" (format: "mm", "mm:ss" or "hh:mm:ss". If invalid or not present, 0 seconds.) - - - - # Commands executed after the beginning of the game. - # (The moment when /uh start or /uh start slow go is executed.) - execute-start: - - - - # Commands executed after the end of the game. - # (After the last kill, when only one team is left.) - execute-end: - - - - -protips: - sound: - name: NOTE_PLING - volume: 2 - pitch: 3 - - teamchat: - useTCommand: true # Protip: team-chat command - lock: true # Protip: can lock the team-chat - useGCommand: true # Protip: global-chat command - - crafts: - goldenHead: true # ProTip: craft of golden apples with an head - compassEasy: true # Protip: "easy" compass craft - compassMedium: true # Protip: "medium" compass craft - compassHard: true # Protip: "hard" compass craft - glisteringMelon: true # Protip: glistering melon crafted with a gold block - noEnchGoldenApple: true # Protip: enchanted golden apple disabled - - start: - invincibility: true # Protip: 30 seconds (25 after the message) of invincibility. - - - -# Use this to set the spawnpoints of the teams (or the players) -# You can also use the command `/uh spawns add` to add temporary spawn points, -# and `/uh spawns generate` to automatically generate them. (See `/uh spawns` for documentation.) -# (The spawn points added through `/uh spawns` are deleted when the server is stopped.) # -# Format: -# - x,z -# - x,z -# - etc. - -spawnpoints: - - - - +# Configuration for modules is available in the `modules/` sub-folder. You should take a look, as this +# file only contains basic configuration. There's a lot mode available there. +# +# Warning: NEVER USE TABS in these files, always spaces, to indent. -# Use this to pre-register the teams. -# Format: -# - color -# -- OR -- -# - color,name -teams: - - +# Available languages: en-US, fr-FR, pt-PT, pt-BR, cs-CZ, zh-CN. +# Empty value: system language. +lang: + +# If set to false, no built-in modules (except core ones) will be loaded (except if +# re-specified in the `modules` configuration below). +built-in-modules: true + +# The modules to load. You can add modules provided by other plugins. Other plugins also may +# self-register their modules for you. +# Each module's configuration is in plugins/UHPlugin/modules/<modulename>.yml . +# You can put built-in modules or refer to modules classes from other plugins. In all +# cases, replace all dots in class paths by dashes. The value after “:” may be true to +# enable the module by default, or false else. +modules: + # "scenarii-alliances": true + # "eu-my-other-package-moduleName": true + + +# The worlds to use as main worlds. +# If not found, fallbacks on the first world found with the right type. +worlds: + overworld: world + nether: world_nether + the_end: world_the_end diff --git a/src/main/resources/i18n/cs_CZ.po b/src/main/resources/i18n/cs-CZ.po similarity index 99% rename from src/main/resources/i18n/cs_CZ.po rename to src/main/resources/i18n/cs-CZ.po index e84c473..73f26bc 100644 --- a/src/main/resources/i18n/cs_CZ.po +++ b/src/main/resources/i18n/cs-CZ.po @@ -706,13 +706,13 @@ msgstr "{gray}{italic}Nemas zadne shnile maso (rotten flesh)." #. Error message if a player tries to use his pointing compass without a #. player nearby. #: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:335 -msgid "{gray}{italic}Only silence answers your request." -msgstr "{gray}{italic}Tva zadost zmizela v tichu." +msgid "Only silence answers your request." +msgstr "Tva zadost zmizela v tichu." #. Success message when a player uses his pointing compass. #: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:342 -msgid "{gray}The compass now points to the closest player." -msgstr "{gray}Kompas nyni ukazuje smer k nejblizsimu hraci." +msgid "The compass now points to the closest player." +msgstr "Kompas nyni ukazuje smer k nejblizsimu hraci." #. Dynmap marker label of a death point #: src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHDynmapIntegration.java:152 @@ -749,26 +749,8 @@ msgstr "Vyrobeno z hlavy padleho hrace {0}" #. Item name of a golden head (from a player) #: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:393 msgctxt "player_head" -msgid "{aqua}Golden head" -msgstr "{aqua}Zlate jablko" - -#. Item name of an enchanted golden head (from a player) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:399 -msgctxt "player_head" -msgid "{lightpurple}Golden head" -msgstr "{lightpurple}Zlata hlava" - -#. Item name of a golden head (from a monster) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:426 -msgctxt "monster_head" -msgid "{aqua}Golden head" -msgstr "{aqua}Zlate jablko" - -#. Item name of an enchanted golden head (from a monster) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:432 -msgctxt "monster_head" -msgid "{lightpurple}Golden head" -msgstr "{lightpurple}Zlata hlava" +msgid "Golden head" +msgstr "Zlate jablko" #. Current episode in the sidebar #: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:141 diff --git a/src/main/resources/i18n/en_US.po b/src/main/resources/i18n/en-US.po similarity index 100% rename from src/main/resources/i18n/en_US.po rename to src/main/resources/i18n/en-US.po diff --git a/src/main/resources/i18n/fr-FR.po b/src/main/resources/i18n/fr-FR.po new file mode 100644 index 0000000..cf1c3e4 --- /dev/null +++ b/src/main/resources/i18n/fr-FR.po @@ -0,0 +1,2743 @@ +# 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. +# +msgid "" +msgstr "" +"Project-Id-Version: 1.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-12-14 15:48+0100\n" +"PO-Revision-Date: 2018-12-14 16:22+0100\n" +"Last-Translator: Amaury Carrade\n" +"Language-Team: Amaury Carrade\n" +"Language: fr_FR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n>1;\n" +"X-Generator: Poedit 2.2\n" + +#. A simple information, because this start is slower (yeah, Captain Obvious here) +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:393 +msgid "{lightpurple}Teleportation in progress... Please wait." +msgstr "{lightpurple}Téléportation en cours... Merci de patienter." + +#. / Displayed in the action bar while the slow teleportation occurs. +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:408 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:701 +msgid "{lightpurple}Teleporting... {gray}({0}/{1})" +msgstr "{lightpurple}Téléportation... {gray}({0}/{1})" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:425 +msgid "{gray}Player {0}{gray} teleported." +msgstr "{gray}Joueur {0}{gray} téléporté." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:448 +msgid "{ce}Cannot teleport player {0}!" +msgstr "{ce]Impossible de téléporter le joueur {0} !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:458 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:709 +msgid "{cs}All teams are teleported." +msgstr "{cs}Toutes les équipes ont été téléportées." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:459 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:713 +msgid "{gray}Use {cc}/uh start{gray} or click here to start the game." +msgstr "" +"{gray}Utilisez {cc}/uh start{gray} ou cliquez ici pour démarrer le jeu." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:460 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:714 +msgid "Click here to start the game" +msgstr "Cliquez ici pour démarrer la partie" + +#. / Displayed in the action bar when the slow teleportation is finished but the game not started. +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:469 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:726 +msgid "{lightpurple}Teleportation complete. {gray}The game will start soon..." +msgstr "{lightpurple}Téléportation terminée. {gray}Ça ne devrait pas tarder..." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:496 +msgid "{ce}Please execute {cc}/uh start slow:true{ce} before." +msgstr "{ce}Veuillez exécuter {cc}/uh start slow:true{ce} avant." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:502 +msgid "{ce}Please wait while the players are teleported." +msgstr "{ce}Veuillez patienter, les équipes sont en train d'être téléportées." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:591 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/submanagers/GameBeginning.java:100 +msgid "" +"{red}{bold}Warning!{white} The grace period is over, you are now vulnerable." +msgstr "" +"{red}{bold}Attention !{white} La période de grâce est terminée ; vous êtes " +"désormais vulnérable." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:603 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/submanagers/GameBeginning.java:113 +msgid "{red}{bold}Warning!{white} PvP is now enabled." +msgstr "{red}{bold}Attention !{white} Le PvP est désormais actif." + +#. / Spectators list item if the nick cannot be found +#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:927 +#, java-format +msgid "Unknown player with UUID {0}" +msgstr "Joueur inconnu ayant l'UUID {0}" + +#. / Title of the rules box. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/misc/RulesManager.java:120 +msgid "{red}{bold}Rules and informations" +msgstr "{red}{bold}Règles et informations" + +#. / Rule item in the rule box. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/misc/RulesManager.java:131 +msgid "{darkgray}- {reset}{0}" +msgstr "{darkgray}- {reset}{0}" + +#. / Episode in the player list ({episodeText} replacement). {0} = current episode number. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/misc/PlayerListHeaderFooterManager.java:115 +#, java-format +msgid "Episode {0}" +msgstr "Épisode {0}" + +#. / Players in the player list ({playersText} replacement). {0} = current alive players count. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/misc/PlayerListHeaderFooterManager.java:117 +#, java-format +msgid "{0} player" +msgid_plural "{0} players" +msgstr[0] "{0} joueur" +msgstr[1] "{0} joueurs" + +#. / Teams in the player list ({teamsText} replacement). {0} = current alive teams count. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/misc/PlayerListHeaderFooterManager.java:119 +#, java-format +msgid "{0} team" +msgid_plural "{0} teams" +msgstr[0] "{0} équipe" +msgstr[1] "{0} équipes" + +#. / MOTD when the game is not started. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/misc/MOTDManager.java:92 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/cosmetics/motd/MotdModule.java:74 +msgid "Waiting for players..." +msgstr "En attente de joueurs..." + +#. / MOTD when the game is starting (slow TP in progress). +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/misc/MOTDManager.java:101 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/cosmetics/motd/MotdModule.java:77 +msgid "Starting in progress..." +msgstr "Démarrage en cours..." + +#. / Solo game running MOTD. {0} = players alive count. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/misc/MOTDManager.java:116 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/cosmetics/motd/MotdModule.java:88 +#, java-format +msgid "Game running! {0} player alive." +msgid_plural "Game running! {0} players alive." +msgstr[0] "Partie en cours ! {0} joueur encore en vie." +msgstr[1] "Partie en cours ! {0} joueurs encore en vie." + +#. / Teams game running MOTD. {0} = players alive count. {1} = teams alive count. Plural based on players count. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/misc/MOTDManager.java:121 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/cosmetics/motd/MotdModule.java:83 +#, java-format +msgid "Game running! {0} player alive in {1} team." +msgid_plural "Game running! {0} players alive in {1} teams." +msgstr[0] "Partie en cours ! {0} joueur en vie dans {1} équipe." +msgstr[1] "Partie en cours ! {0} joueurs en vie dans {1} équipes." + +#. / Game finished MOTD with solo winner ({0} = winner raw name). +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/misc/MOTDManager.java:138 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/cosmetics/motd/MotdModule.java:103 +#, java-format +msgid "Game finished; congratulation to {0} for his victory!" +msgstr "Partie terminée ; félicitation à {0} pour sa victoire !" + +#. / Game finished MOTD with team winner ({0} = team display name). +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/misc/MOTDManager.java:143 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/cosmetics/motd/MotdModule.java:98 +#, java-format +msgid "Game finished; the team {0} wins this match!" +msgstr "Partie terminée ; l'équipe {0} remporte la victoire !" + +#. / Usage of the /g and /t commands +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/GlobalMessageCommand.java:109 +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/TeamMessageCommand.java:108 +msgid "{ce}Usage: /{0} <message>" +msgstr "{ce}Utilisation : /{0} <message>" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHRulesCommand.java:63 +msgid "{ce}No rules are set in the config file." +msgstr "{ce}Aucune règle n'est enregistrée dans le fichier de configuration." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHRulesCommand.java:75 +msgid "{cs}Rules sent to {0}." +msgstr "{cs}Les règles ont été envoyées à {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHRulesCommand.java:79 +msgid "{ce}Cannot display the rules to {0} because he (or she) is offline." +msgstr "" +"{ce}Impossible d'afficher les règles à {0} car il ou elle est hors-ligne." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHRulesCommand.java:103 +msgid "" +"{cc}/uh rules [player] {ci}: sends the server rules to the server or the " +"given player." +msgstr "" +"{cc}/uh rules [joueur] {ci}: envoie les règles du jeu au serveur ou au " +"joueur spécifié." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:92 +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:118 +msgid "{cst}You where frozen by {0}." +msgstr "{cst}Vous avez été immobilisé(e) par {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:96 +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:123 +msgid "{cst}You where unfrozen by {0}." +msgstr "{cst}Vous avez été libéré(e) par {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:111 +msgid "{ce}{0} is offline!" +msgstr "{ce}{0} est hors-ligne !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:119 +msgid "{cs}{0} is now frozen." +msgstr "{cs}{0} est désormais immobilisé(e)." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:124 +msgid "{cs}{0} is now unfrozen." +msgstr "{cs}{0} est désormais libéré(e)." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:138 +msgid "{darkaqua}The entire game is now frozen." +msgstr "{darkaqua}Le jeu est désormais en pause." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:142 +msgid "{darkaqua}The game is now unfrozen." +msgstr "{darkaqua}Le jeu n'est plus en pause." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:182 +msgid "{aqua}------ Freeze commands ------" +msgstr "{aqua}------ Commandes liées à l'immobilisation ------" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:183 +msgid "" +"{cc}/uh freeze on [player]{ci}: freezes a player, or the sender without a " +"specified player." +msgstr "" +"{cc}/uh freeze on [joueur] {ci}: immobilise un joueur, ou l'exécuteur sans " +"joueur spécifié." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:184 +msgid "" +"{cc}/uh freeze off [player]{ci}: unfreezes a player (or the sender), even if " +"the entire game is frozen." +msgstr "" +"{cc}/uh freeze off [player] {ci}: libère un joueur (ou l'envoyeur), même si " +"le jeu est en pause." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:185 +msgid "{cc}/uh freeze all{ci}: freezes the entire game (players, mobs, timer)." +msgstr "" +"{cc}/uh freeze all {ci}: met le jeu en pause (immobilise les joueurs, mobs, " +"et le compteur)." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:186 +msgid "" +"{cc}/uh freeze none{ci}: unfreezes the entire game. You NEED to execute this " +"in order to relaunch the timer." +msgstr "" +"{cc}/uh freeze none {ci}: relance le jeu. Vous DEVEZ exécuter ceci pour " +"relancer le compteur." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFreezeCommand.java:193 +msgid "" +"{cc}/uh freeze {ci}: (un)freezes the entire game, or a player. See /uh " +"freeze for details." +msgstr "" +"{cc}/uh freeze {ci}: (dés)immobilise l'ensemble du jeu, ou un joueur. " +"Consultez /uh freeze pour plus de détails." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFinishCommand.java:76 +msgid "{ce}The game is not started!" +msgstr "{ce}Le jeu n'est pas encore démarré !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFinishCommand.java:80 +msgid "{ce}There's not one team alive!" +msgstr "{ce}Il n'y a pas qu'une équipe encore en vie !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHFinishCommand.java:104 +msgid "" +"{cc}/uh finish {ci}: displays the name of the winner(s) and launches some " +"fireworks." +msgstr "" +"{cc}/uh finish {ci}: affiche le nom du/des vainqueurs et lance des feux " +"d'artifices." + +#. / Header of the /uh infos command. Plural based on the players count. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:70 +msgid "{ci}{0} player alive in {1} team." +msgid_plural "{ci}{0} players alive in {1} teams." +msgstr[0] "{ci}{0} joueur en vie, dans {1} équipe." +msgstr[1] "{ci}{0} joueurs en vie, répartis dans {1} équipes." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:74 +msgid "{ci}The game is not started." +msgstr "{ci}Le jeu n'est pas encore démarré." + +#. / Online status dot in /uh infos +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:93 +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:150 +msgid "{green} • " +msgstr "{green} • " + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:94 +msgid "Currently online" +msgstr "Actuellement connecté(e)" + +#. / Offline status dot in /uh infos +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:99 +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:154 +msgid "{red} • " +msgstr "{red} • " + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:100 +msgid "Currently offline" +msgstr "Actuellement hors-ligne" + +#. / Team name in tooltip in /uh infos +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:109 +#, java-format +msgid "Team: {0}" +msgstr "Équipe : {0}" + +#. / Separator in /uh infos +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:116 +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:161 +msgid "{gray} - " +msgstr "{gray} - " + +#. / Alive state in /uh infos +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:123 +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:165 +msgid "{green}alive" +msgstr "{green}vivant" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:126 +#, java-format +msgid "{0} half-hearts" +msgstr "{0} demi-cœurs" + +#. / Alive state in /uh infos +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:132 +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:169 +msgid "{red}dead" +msgstr "{red}mort" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/uh/UHInfosCommand.java:197 +msgid "{cc}/uh infos {ci}: prints some infos about the current game." +msgstr "{cc}/uh infos {ci}: affiche des informations à propos du jeu en cours." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/categories/Category.java:39 +msgid "{aqua}------ Game-related commands ------" +msgstr "{aqua}------ Commandes liées au jeu ------" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/categories/Category.java:40 +msgid "{aqua}------ Bugs-related commands ------" +msgstr "{aqua}------ Commandes liées aux bugs ------" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/commands/categories/Category.java:41 +msgid "{aqua}------ Miscellaneous commands ------" +msgstr "{aqua}------ Commandes diverses ------" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/core/AbstractCommandExecutor.java:208 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/about/AboutCommand.java:54 +msgid "{yellow}{0} - version {1}" +msgstr "{yellow}{0} - version {1}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/core/AbstractCommandExecutor.java:209 +msgid "" +"{ci}Legend: {cc}/uh command <required> [optional=default] <spaces allowed ..." +">{ci}." +msgstr "" +"{ci}Légende: {cc}/uh command <requis> [optionnel=valeur par défaut] <espaces " +"autorisées ...>{ci}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/core/AbstractCommandExecutor.java:225 +msgid "{ce}{bold}You cannot execute this command this way." +msgstr "{ce}{bold}Vous ne pouvez exécuter cette commande ainsi." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/core/AbstractCommandExecutor.java:226 +msgid "{ce}The help is displayed above." +msgstr "{ce}L'aide est rappelée ci-dessus." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/core/AbstractCommandExecutor.java:257 +msgid "{ce}You are not allowed to execute this command." +msgstr "{ce}Vous n'avez pas le droit d'exécuter cette commande." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/commands/core/AbstractCommandExecutor.java:261 +msgid "{ce}This can only be executed as a player." +msgstr "{ce}Vous ne pouvez exécuter cela qu'en étant un joueur." + +#. / Golden head lore for withers +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/recipes/RecipesManager.java:280 +msgid "Made from the fallen head of a malignant monster" +msgstr "Fabriquée depuis la tête tranchée d'un monstre maléfique" + +#. / Golden head lore for players. {0} = player name. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/recipes/RecipesManager.java:285 +#, java-format +msgid "Made from the fallen head of {0}" +msgstr "Fabriquée depuis la tête tranchée de {0}" + +#. / Item name of a golden head (from a player) +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/recipes/RecipesManager.java:388 +msgid "Golden head" +msgstr "Tête d'or" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/protips/ProTips.java:42 +msgctxt "protip" +msgid "{gray}You can lock and unlock the team chat with {cc}/togglechat{gray}." +msgstr "" +"{gray}Verrouillez le chat d'équipe avec {cc}/togglechat{gray}, qui permet de " +"passer d'un chat à l'autre." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/protips/ProTips.java:43 +msgctxt "protip" +msgid "{gray}You can send a global message using {cc}/g <message>{gray}." +msgstr "" +"{gray}Vous pouvez envoyer un message à tout le monde avec {cc}/g " +"<message>{gray}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/protips/ProTips.java:44 +msgctxt "protip" +msgid "{gray}You can send a team-chat message with {cc}/t <message>{gray}." +msgstr "" +"{gray}Vous pouvez envoyer un message à votre équipe avec {cc}/t " +"<message>{gray}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/protips/ProTips.java:46 +msgctxt "protip" +msgid "" +"{gray}You can craft golden apples with heads (same recipe with a head " +"instead of an apple)." +msgstr "" +"{gray}Vous pouvez fabriquer des pommes d'or avec les têtes (même recette " +"avec une tête à la place de la pomme)." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/protips/ProTips.java:47 +msgctxt "protip" +msgid "" +"{gray}The compass is crafted with, in the corners, a bone, a rotten flesh, a " +"spider eye and a gunpowder." +msgstr "" +"{gray}La boussole se fabrique avec dans les coins un os, une chaire de " +"zombie, un œil d'araignée et une poudre à canon." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/protips/ProTips.java:48 +msgctxt "protip" +msgid "" +"{gray}The compass is crafted with, in the corners, a bone, a rotten flesh, a " +"spider eye and a gunpowder; in the center, an ender pearl." +msgstr "" +"{gray}La boussole se fabrique avec dans les coins un os, une chaire de " +"zombie, un œil d'araignée et une poudre à canon ; au centre une Perle du " +"Néant." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/protips/ProTips.java:49 +msgctxt "protip" +msgid "" +"{gray}The compass is crafted with, in the corners, a bone, a rotten flesh, a " +"spider eye and a gunpowder; in the center, an Eye of Ender." +msgstr "" +"{gray}La boussole se fabrique avec dans les coins un os, une chaire de " +"zombie, un œil d'araignée et une poudre à canon ; au centre un Œil du Néant." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/protips/ProTips.java:50 +msgctxt "protip" +msgid "{gray}The glistering melon is crafted with a melon and a gold block." +msgstr "" +"{gray}La pastèque scintillante se fabrique avec une pastèque et un bloc d'or." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/protips/ProTips.java:52 +msgctxt "protip" +msgid "{gray}The enchanted golden apple is disabled for this game." +msgstr "{gray}La pomme d'or enchantée est désactivée pour cette partie." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/protips/ProTips.java:54 +msgctxt "protip" +msgid "" +"{gray}Fallen on a tree? Jump, you have a few seconds left to remain " +"invincible." +msgstr "" +"{gray}Tombé(e) sur un arbre ? Sautez, il vous reste quelques dizaines de " +"secondes d'invincibilité." + +#. / ProTip invite, displayed before a ProTip. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/protips/ProTip.java:132 +msgid "{darkpurple}ProTip!" +msgstr "{darkpurple}Astuce !" + +#. / The kick message of a player when death.kick.do = true in config +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/listeners/GameListener.java:133 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/kick/Config.java:53 +msgid "jayjay" +msgstr "jayjay" + +#. / The kick message displayed if a player tries to relog after his death and it's forbidden by the config. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/listeners/GameListener.java:288 +msgid "You are dead!" +msgstr "Vous êtes mort !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/listeners/GameListener.java:491 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/episodes/EpisodesModule.java:125 +msgid "{aqua}-------- End of episode {0} [forced by {1}] --------" +msgstr "{aqua}-------- Fin de l'épisode {0} [forcé par {1}] --------" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/listeners/GameListener.java:495 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/episodes/EpisodesModule.java:129 +msgid "{aqua}-------- End of episode {0} --------" +msgstr "{aqua}-------- Fin de l'épisode {0} --------" + +#. / The title displayed when the episode change. {0} = new episode number; {1} = old. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/listeners/GameListener.java:507 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/episodes/EpisodesModule.java:141 +msgid "{darkaqua}Episode {aqua}{0}" +msgstr "{darkaqua}Épisode {aqua}{0}" + +#. Broadcast +#. / Start message broadcasted in chat +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/listeners/GameListener.java:531 +msgid "{green}--- GO ---" +msgstr "{green}--- GO ---" + +#. / Title of title displayed when the game starts. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/listeners/GameListener.java:539 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:465 +msgid "{darkgreen}Let's go!" +msgstr "{darkgreen}C'est parti !" + +#. / Subtitle of title displayed when the game starts. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/listeners/GameListener.java:541 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:467 +msgid "{green}Good luck, and have fun" +msgstr "{green}Bonne chance et bon jeu à tous" + +#. / Error message if a player tries to use his pointing compass without rotten flesh. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/listeners/GameplayListener.java:311 +msgid "{gray}{italic}You do not have rotten flesh." +msgstr "{gray}{italic}Vous n'avez pas de chair de zombie." + +#. / Error message if a player tries to use his pointing compass without a player nearby. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/listeners/GameplayListener.java:342 +msgid "Only silence answers your request." +msgstr "Seul le silence comble votre requête." + +#. / Success message when a player uses his pointing compass. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/listeners/GameplayListener.java:349 +msgid "The compass now points to the closest player." +msgstr "La boussole cible désormais le joueur le plus proche." + +#. / Dynmap marker label of a death point +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/integration/UHDynmapIntegration.java:151 +#, java-format +msgid "Death point of {0}" +msgstr "Ici disparu {0}" + +#. / Dynmap marker label of a spawn point of a team. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/integration/UHDynmapIntegration.java:230 +#, java-format +msgid "Spawn point of the team {0}" +msgstr "Lieu de démarrage de l'équipe {0}" + +#. / Dynmap marker label of a spawn point of a player, in solo. +#. / Dynmap marker label of a spawn point of a player, when the teleportation ignores the teams. +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/integration/UHDynmapIntegration.java:235 +#: src/main/java/eu/carrade/amaury/UHCReloaded/old/integration/UHDynmapIntegration.java:292 +#, java-format +msgid "Spawn point of {0}" +msgstr "Lieu de démarrage de {0}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/playersLoader/LoadPlayersCommand.java:58 +msgid "{ce}You cannot load unknown players in offline mode, sorry." +msgstr "" +"{ce}Vous ne pouvez pas charger des joueurs inconnus en mode hors-ligne, " +"désolé." + +#. / Error returned if one calls /uh loadplayers without arguments. +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/playersLoader/LoadPlayersCommand.java:65 +msgid "{ce}You need to provide at least one player name." +msgstr "{ce}Vous devez spécifier au moins un nom de joueur." + +#. / Message displayed when the /uh loadplayers command is used, as the execution may take some time. +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/playersLoader/LoadPlayersCommand.java:70 +msgid "{cst}Loading players..." +msgstr "{cst}Chargement des joueurs..." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/playersLoader/LoadPlayersCommand.java:76 +msgid "{cs}Loaded {0} player successfully." +msgid_plural "{cs}Loaded {0} players successfully." +msgstr[0] "{cs}{0} joueur a été chargé." +msgstr[1] "{cs}{0} joueurs ont été chargés." + +#. / Message sent if some players cannot be loaded while /uh loadplayers is used. 0 = amount of players missing; 1 = list of nicknames (format "nick1, nick2, nick3"). +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/playersLoader/LoadPlayersCommand.java:79 +msgid "{ce}{0} player is missing: {1}." +msgid_plural "{ce}{0} players are missing: {1}." +msgstr[0] "{ce}Il manque {0} joueur : {1}." +msgstr[1] "{ce}Il manque {0} joueurs : {1}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/about/AboutModule.java:110 +msgid "{yellow}Beta version" +msgstr "{yellow}Version bêta" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/about/AboutModule.java:118 +msgid "{red}Development version" +msgstr "{red}Version de développement" + +#. / The "and" in the authors list (like "Amaury Carrade, azenet and João Roda") +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/about/AboutModule.java:197 +msgctxt "authors_list" +msgid "and" +msgstr "et" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/about/AboutCommand.java:55 +#, java-format +msgid "Plugin made with love by {0}." +msgstr "Plugin réalisé avec amour par {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/about/AboutCommand.java:59 +#, java-format +msgid "Build number: {0}." +msgstr "Numéro de construction : {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/about/AboutCommand.java:63 +msgid "Build number not available." +msgstr "Numéro de construction indisponible." + +#. Translation +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/about/AboutCommand.java:68 +msgid "{aqua}------ Translations ------" +msgstr "{aqua}------ Traductions ------" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/about/AboutCommand.java:69 +#, java-format +msgid "Current language: {0} (translated by {1})." +msgstr "Langue courante : {0} (traduit par {1})." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/about/AboutCommand.java:70 +#, java-format +msgid "Fallback language: {0} (translated by {1})." +msgstr "Langue par défaut : {0} (traduit par {1})." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/about/AboutCommand.java:71 +msgid "{aqua}------ License ------" +msgstr "{aqua}------ Licence ------" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/other/about/AboutCommand.java:72 +msgid "Published under the CeCILL-B License." +msgstr "Publié sous la licence CeCILL-B." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/health/commands/HealAllCommand.java:75 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/health/commands/HealCommand.java:85 +msgid "{ce}Hey, this is not a number of half-hearts. It's a text. Pfff." +msgstr "" +"{ce}Hey, ce n'est pas un nombre de demi-coeurs... C'est un texte... Pfff." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/health/commands/HealAllCommand.java:82 +msgid "{ce}Serial killer!" +msgstr "{ce}S'pèce de tueur en série !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/health/commands/HealAllCommand.java:91 +msgid "{ce}The health of {0} was not updated to avoid a kill." +msgstr "{ce}La vie de {0} n'a pas été changée, pour ne pas le/la tuer." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/health/commands/HealAllCommand.java:107 +msgid "The health of all players was completely filled." +msgstr "La vie de l'ensemble des joueurs a été régénérée." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/health/commands/HealAllCommand.java:111 +#, java-format +msgid "The health of all players was set to {0}." +msgstr "La vie de l'ensemble des joueurs a été mise à {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/health/commands/HealAllCommand.java:116 +#, java-format +msgid "The health of all players was increased by {0}." +msgstr "La vie de l'ensemble des joueurs a été augmentée de {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/health/commands/HealAllCommand.java:120 +#, java-format +msgid "The health of all players was decreased by {0}." +msgstr "La vie de l'ensemble des joueurs a été diminuée de {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/health/commands/HealCommand.java:55 +msgid "A player is required" +msgstr "Un joueur est requis" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/health/commands/HealCommand.java:93 +msgid "{ce}You can't kill a player with this command, to avoid typo fails." +msgstr "" +"{ce}Vous ne pouvez pas tuer un joueur avec cette commande, pour éviter toute " +"faute de frappe." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/health/commands/HealCommand.java:106 +#, java-format +msgid "The health of {0} was set to {1}." +msgstr "La vie de {0} a été mise à {1}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPDeathCommand.java:61 +msgid "{ce}No death location available for the player {0}." +msgstr "{ce}Pas de localisation de mort enregistrée pour le joueur {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPDeathCommand.java:69 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPDeathCommand.java:73 +msgid "{cs}The player {0} was teleported back." +msgstr "{cs}Le joueur {0} a été téléporté là où il est mort." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPDeathCommand.java:77 +msgid "" +"{ce}The player {0} was NOT teleported back because no safe spot was found." +msgstr "" +"{ce}Le joueur {0} n'a PAS été téléporté car aucun point de téléportation sûr " +"n'a été trouvé." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPDeathCommand.java:78 +msgid "" +"{ci}Use {cc}/uh tpback {0} force{ci} to teleport the player regardless this " +"point." +msgstr "" +"{ci}Utilisez {cc}/uh tpback {0} force{ci} pour le téléporter malgré tout." + +#. / {0}: world name. {1-3}: x, y, z. +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPSpectatorsCommand.java:74 +#, java-format +msgid "All spectators were teleported to ({0} ; {1} ; {2} ; {3})." +msgstr "Tous les spectateurs ont été téléportés en ({0} ; {1} ; {2} ; {3})." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPSpectatorsCommand.java:78 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPTeamCommand.java:87 +msgid "{ce}The coordinates must be three valid numbers." +msgstr "{ce}Les coordonnées doivent être trois nombres." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPSpectatorsCommand.java:91 +#, java-format +msgid "All spectators were teleported to the player {0}." +msgstr "Tous les spectateurs ont été téléportés sur {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPSpectatorsCommand.java:94 +msgid "You must specify either three coordinates or a player name." +msgstr "Vous devez spécifier ou bien trois coordonnées, ou un joueur." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPSpawnCommand.java:61 +msgid "" +"{ce}The spawn points are not already assigned to the player, because the " +"game is not started." +msgstr "" +"{ce}Les points de démarrage n'ont pas encore été assignés aux joueurs, car " +"le jeu n'a pas encore démarré." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPSpawnCommand.java:71 +msgid "{ce}No spawn location available for the player {0}." +msgstr "{ce}Pas de localisation de démarrage enregistrée pour le joueur {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPSpawnCommand.java:78 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPSpawnCommand.java:82 +msgid "{cs}The player {0} was teleported to his spawn location." +msgstr "{cs}Le joueur {0} a été téléporté à son point de démarrage attribué." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPSpawnCommand.java:86 +msgid "" +"{ce}The player {0} was NOT teleported to his spawn because no safe spot was " +"found." +msgstr "" +"{ce}Le joueur {0} n'a PAS été téléporté car aucun point de téléportation sûr " +"n'a été trouvé." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPSpawnCommand.java:87 +msgid "" +"{ci}Use {cc}/uh tpspawn {0} force{ci} to teleport the player regardless this " +"point." +msgstr "" +"{ci}Utilisez {cc}/uh tpspawn {0} force{ci} pour le téléporter malgré tout." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPTeamCommand.java:77 +#, java-format +msgid "" +"The players in the team {0} ({1}) were teleported to ({2} ; {3} ; {4} ; {5})." +msgstr "" +"Les joueurs de l'équipe {0} ({1}) ont été téléportés en ({2} ; {3} ; {4} ; " +"{5})." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPTeamCommand.java:99 +msgid "{ce}This team is not registered." +msgstr "{ce}Cette équipe n'est pas enregistrée." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/teleportation/commands/TPTeamCommand.java:108 +#, java-format +msgid "The players in the team {0} ({1}) were teleported to the player {2}." +msgstr "Les joueurs de l'équipe {0} ({1} ont été téléportés sur {2}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/food/commands/FeedAllCommand.java:62 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/food/commands/FeedAllCommand.java:75 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/food/commands/FeedCommand.java:65 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/food/commands/FeedCommand.java:78 +msgid "" +"{ce}Food points and saturation must be numbers (floats for the saturation)!" +msgstr "" +"{ce}Les valeurs de faim et de saturation doivent être des nombres " +"(possiblement à virgule pour la saturation) !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/food/commands/FeedAllCommand.java:86 +#, java-format +msgid "Set food level to {0} and saturation to {1} for every player." +msgstr "" +"Les niveaux de faim et de saturation ont été configurés à respectivement {0} " +"et {1} pour l'ensemble des joueurs." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/food/commands/FeedCommand.java:86 +#, java-format +msgid "Set food level to {0} and saturation to {1} for {2}." +msgstr "" +"Les niveaux de faim et de saturation ont été configurés à respectivement {0} " +"et {1} pour {2}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/deathAnnouncement/DeathAnnouncementModule.java:92 +#, java-format +msgid "{0} died, following a game master's order." +msgstr "{0} est mort, par volonté d'un maître du jeu." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/deathAnnouncement/DeathAnnouncementModule.java:125 +#, java-format +msgid "{0}The team {1} has fallen!" +msgstr "{0}L'équipe {1} est vaincue !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/episodes/commands/ShiftCommand.java:54 +msgid "" +"{ce}You can't shift the current episode because the game is not started." +msgstr "" +"{ce}Vous ne pouvez pas passer l'épisode actuel car le jeu n'a pas démarré." + +#. / Current episode in the sidebar +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/episodes/EpisodesModule.java:102 +#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:142 +msgid "{gray}Episode {white}{0}" +msgstr "{gray}Épisode {white}{0}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/ingame/episodes/EpisodesModule.java:124 +msgid "the console" +msgstr "la console" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AlliancesModule.java:236 +msgid "Alone" +msgstr "Seul" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/RequestAnswerCommand.java:56 +msgid "" +"Invalid command usage. But, you shouldn't use this command directly. What " +"are you doing?" +msgstr "" +"Utilisation invalide de cette commande. Mais, vous ne devriez pas vous en " +"servir directement. Que faites-vous donc ?" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/RequestAnswerCommand.java:77 +msgid "You weren't asked for your opinion regarding this request." +msgstr "Votre opinion n'a jamais été demandée concernant cette requête." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/RequestAnswerCommand.java:80 +msgid "This request has expired." +msgstr "Cette requête a expiré." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:65 +msgid "You must provide a player name." +msgstr "Vous devez spécifier un nom de joueur." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:74 +msgid "You cannot create an alliance with yourself." +msgstr "Vous ne pouvez créer une alliance avec vous-même." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:78 +#, java-format +msgid "" +"You already have an ongoing alliance request sent to {0}. Please be patient!" +msgstr "Vous avez déjà envoyé une requête d'alliance à {0}. Soyez patient !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:91 +#, java-format +msgid "{0} is too far. You must be within {1} blocks of each other." +msgstr "" +"{0} est trop éloigné. Vous devez être à moins de {1} blocs l'un⋅e de l'autre." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:95 +msgid "You can no longer join an alliance." +msgstr "Vous ne pouvez plus rejoindre d'alliance." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:102 +msgid "" +"{gray}{bold}{0} just sent you an alliance request, but you cannot accept it " +"because you have no alliance left." +msgstr "" +"{gray}{bold}{0} vient de vous envoyer une requête d'alliance, mais vous ne " +"pouvez l'accepter car vous n'avez plus d'alliances disponibles." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:103 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:119 +msgid "" +"{gray}{0} is not aware of this, but I preferred to warn you so that you " +"would not be caught off guard if he or she mentions it." +msgstr "" +"{gray}{0} l'ignore, mais je préfère vous prévenir afin que vous puissiez " +"réagir convenablement s'il ou elle le mentionne." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:118 +msgid "" +"{gray}{bold}{0} just sent you an alliance request, but you cannot accept it " +"because your alliance is already at full capacity." +msgstr "" +"{gray}{bold}{0} vient de vous envoyer une requête d'alliance, mais vous ne " +"pouvez l'accepter car votre alliance est pleine." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:125 +msgid "" +"You cannot send a request alliance as your alliance is already at full " +"capacity. Don't be too greedy!" +msgstr "" +"Vous ne pouvez envoyer une requête car votre alliance est déjà pleine. Ne " +"soyez pas trop gourmand !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:136 +msgid "You're already allied with {0}!" +msgstr "Vous êtes déjà allié avec {0} !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:140 +msgid "You cannot create this alliance as it would end the game." +msgstr "Vous ne pouvez créer cette alliance, car cela terminerait le jeu." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:162 +msgid "{bold}Your request has been sent to {0}." +msgstr "{bold}Votre requête a été envoyée à {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/commands/AllianceRequestCommand.java:163 +msgid "Wait until it is accepted. Let's hope you don't hear only silence..." +msgstr "" +"Patientez le temps qu'elle soit acceptée. Espérons que vous n'entendrez pas " +"uniquement le bruit du silence..." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:198 +msgid "{green}{bold}{0} would like to join you in an alliance." +msgstr "{green}{bold}{0} aimerait s'allier avec vous." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:202 +msgid "" +"{gray}This request was sent to {0}, but everyone in the alliance also need " +"to accept." +msgstr "" +"{gray}Cette requête a été envoyée à {0}, mais l'ensemble des membres de " +"l'alliance doit également l'accepter." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:208 +msgid "{darkgreen}{bold}» {green}{bold}Accept {darkgreen}{bold}«" +msgstr "{darkgreen}{bold}» {green}{bold}Accepter {darkgreen}{bold}«" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:210 +msgid "{green}{bold}Accept {green}this alliance" +msgstr "{green}{bold}Accepter {green}cette alliance" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:212 +msgid "{darkred}{bold}» {red}{bold}Decline {darkred}{bold}«" +msgstr "{darkred}{bold}» {red}{bold}Refuser {darkred}{bold}«" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:214 +msgid "{red}{bold}Decline {red}this alliance" +msgstr "{red}{bold}Refuser {red}cette alliance" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:248 +msgid "{gray}Still waiting for {0}'s answer." +msgid_plural "{gray}Still waiting for answers from: {0}." +msgstr[0] "{gray}Nous attendons toujours la réponse de {0}." +msgstr[1] "{gray}Nous attendons toujours la réponse de ces joueurs : {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:262 +#, java-format +msgid "You accepted the request for an alliance with {0}." +msgstr "Vous avez accepté la requête d'alliance avec {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:293 +msgid "{green}The request for an alliance with {0} was accepted by {1}." +msgstr "{green}La requête d'alliance avec {0} a été acceptée par {1}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:339 +msgid "{red}The alliance with {0} was {bold}denied{red} by {1}." +msgstr "{red}La requête d'alliance avec {0} a été {bold}refusée{red} par {1}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:347 +msgid "{red}You declined {0}'s alliance request." +msgstr "{red}Vous avez refusé la requête d'alliance de {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:369 +msgid "{ce}This alliance request is no longer valid. Please re-send it." +msgstr "" +"{ce}Cette requête d'alliance n'est plus valide. Merci de la ré-envoyer." + +#. We create a new team for this new alliance. Old teams are dropped. +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:376 +msgid "Your alliance" +msgstr "Votre alliance" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:410 +msgid "{green}{bold}You are now allied with {0}!" +msgstr "{green}{bold}Vous êtes désormais allié avec {0} !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:411 +msgid "" +"{green}Your objective is to win together. But chhhh! Other players are not " +"aware of your alliance..." +msgstr "" +"{green}Votre objectif est de gagner ensemble. Mais chhhh ! Les autres " +"joueurs ignorent que vous êtes alliés..." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:415 +msgid "{green}{bold}The alliance expands!" +msgstr "{green}{bold}L'alliance s'agrandit !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/scenarii/alliances/AllianceRequest.java:416 +msgid "{gray}Players in the alliance: {0}" +msgstr "{gray}Joueurs dans l'alliance : {0}" + +#. / The title of the item given before the game to select a team +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/beginning/wait/WaitModule.java:144 +msgid "{green}{bold}Select a team {gray}(Right-Click)" +msgstr "{green}{bold}Choisir une équipe {gray}(Clic droit)" + +#. / The lore of the item given before the game to select a team +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/beginning/wait/WaitModule.java:146 +msgid "{gray}Right-click to select your team for this game" +msgstr "{gray}Cliquez-droit pour sélectionner votre équipe pour ce jeu" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/beginning/wait/WaitModule.java:178 +msgid "{gold}Your team: {0}" +msgstr "{gold}Votre équipe : {0}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/warning/BorderWarningTask.java:63 +msgid "{ce}You are currently out of the future border (diameter of {0} block)." +msgid_plural "" +"{ce}You are currently out of the future border (diameter of {0} blocks)." +msgstr[0] "{ce}Vous êtes hors de la future bordure de {0} bloc de diamètre." +msgstr[1] "{ce}Vous êtes hors de la future bordure de {0} blocs de diamètre." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/warning/BorderWarningTask.java:67 +msgid "{ce}You are currently out of the future border of {0}×{0} blocks." +msgstr "{ce}Vous êtes hors de la future bordure de {0}×{0} blocs." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/warning/BorderWarningTask.java:70 +msgid "{ci}You have {0} block to go before being inside." +msgid_plural "{ci}You have {0} blocks to go before being inside." +msgstr[0] "{ci}Il vous reste {0} blocs à parcourir avant d'y être." +msgstr[1] "{ci}Il vous reste {0} bloc à parcourir avant d'y être." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/warning/WarningCommand.java:60 +msgid "Missing future border size." +msgstr "La future taille de la bordure est manquante." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/warning/WarningCommand.java:67 +msgid "{cs}Warning canceled." +msgstr "{cs}Avertissement annulé." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/warning/WarningCommand.java:87 +msgid "" +"{cs}Future size saved. All players outside this future border will be warned " +"every {0} second." +msgid_plural "" +"{cs}Future size saved. All players outside this future border will be warned " +"every {0} seconds." +msgstr[0] "" +"{cs}Future taille enregistrée. Les joueurs hors de la bordure vont être " +"avertis toutes les {0} seconde." +msgstr[1] "" +"{cs}Future taille enregistrée. Les joueurs hors de la bordure vont être " +"avertis toutes les {0} secondes." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/warning/WarningCommand.java:92 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/check/CheckCommand.java:60 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:107 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:131 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:152 +msgid "{ce}“{0}” is not a number..." +msgstr "{ce}“{0}” n'est pas un nombre..." + +#. / The name of the warning timer displaying the time left before the next border +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/warning/WarningModule.java:75 +msgid "Border shrinking" +msgstr "Réduction de la bordure" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/walls/WallsCommand.java:52 +msgid "{cst}Generating the walls..." +msgstr "{cst}Génération des murs en cours..." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/walls/WallsCommand.java:67 +msgid "{ci}From the console, generating the walls of the default world, {0}" +msgstr "{ci}Depuis la console, génération du mur du monde par défaut, {0}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/walls/WallsCommand.java:76 +msgid "" +"{ce}Unable to generate the wall: see logs for details. The blocks set in the " +"config are probably invalid." +msgstr "" +"{ce}Impossible de générer le mur: voir logs pour plus de détails. Les blocs " +"configurés sont probablement invalide." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/walls/WallsCommand.java:82 +msgid "{ce}An error occurred, see console for details." +msgstr "" +"{ce}Une erreur s'est produite, consultez la console pour plus de détails." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/walls/WallsCommand.java:87 +msgid "{cst}Generation done." +msgstr "{cst}Génération terminée." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/border/check/CheckCommand.java:51 +msgid "You must provide a check radius." +msgstr "Vous devez spécifier un rayon de vérification." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/submanagers/GameBeginning.java:88 +msgid "{green}Grace period {gray}-{green} All damages are disabled" +msgstr "{green}Période de grâce {gray}-{green} Tous les dégâts sont désactivés" + +#. / Players alive in the sidebar +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:172 +#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:151 +#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:160 +msgid "{white}{0}{gray} player" +msgid_plural "{white}{0}{gray} players" +msgstr[0] "{white}{0}{gray} joueur" +msgstr[1] "{white}{0}{gray} joueurs" + +#. / Teams alive in the sidebar +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:179 +#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:164 +msgid "{white}{0}{gray} team" +msgid_plural "{white}{0}{gray} teams" +msgstr[0] "{white}{0}{gray} équipe" +msgstr[1] "{white}{0}{gray} équipes" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:189 +msgid "{gray}Waiting for players..." +msgstr "{gray}En attente de joueurs..." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:196 +msgid "{gray}The game is starting..." +msgstr "{gray}Le jeu démarre..." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:197 +msgid "{gray}Please wait." +msgstr "{gray}Veuillez patienter." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:562 +msgid "{ce}Unable to start the game: not enough teleportation spots." +msgstr "{ce}Impossible de démarrer : pas assez de points de téléportation." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:563 +msgid "" +"{ci}You can use {cc}/uh spawns generate <random|circular|grid>{ci} to " +"generate the missing spawns automatically." +msgstr "" +"{ci}Vous pouvez utiliser {cc}/uh spawns generate <random|circular|grid>{ci} " +"pour automatiquement générer les points de téléportation manquant." + +#. / In the sentence: "Or click here to generate the spawns randomly." +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:566 +msgid "Or" +msgstr "Ou" + +#. / In the sentence: "Or click here to generate the spawns randomly." +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:569 +msgid "click here" +msgstr "cliquez ici" + +#. / In the sentence: "Or click here to generate the spawns randomly." +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:575 +msgid "to generate the spawns randomly." +msgstr "afin de générer les points de démarrage aléatoirement." + +#. / Resurrection notification. {0} = raw resurrected player name. +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/GameModule.java:790 +msgid "{gold}{0} returned from the dead!" +msgstr "{gold}{0} est revenu d'entre les morts !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/commands/StartCommand.java:66 +msgid "{green}{bold}The game is now starting." +msgstr "{green}{bold}Le jeu démarre." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/commands/StartCommand.java:67 +msgid "" +"{green}Wait for the teleportation to finish; you'll then be prompted to " +"start the game." +msgstr "" +"{green}Patientez le temps que la téléportation s'achève ; il vous sera alors " +"demandé de démarrer le jeu." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/commands/StartCommand.java:81 +msgid "The starting process is not finished yet. Please be patient." +msgstr "Le processus de démarrage n'est pas achevé. Soyez patient." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/commands/StartCommand.java:87 +msgid "" +"{ce}The game is already started! Reload or restart the server to restart the " +"game." +msgstr "" +"{ce}Le jeu est déjà démarré ! Rechargez ou redémarrez le serveur pour " +"redémarrer." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/commands/KillCommand.java:57 +msgid "You must specify the player to kill." +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/commands/KillCommand.java:66 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/commands/ResurrectCommand.java:67 +msgid "{ce}This player was never seen on this server." +msgstr "{ce}Cette personne n'a jamais été vue sur le serveur." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/commands/KillCommand.java:85 +msgid "{cs}The player {0} is now marked as dead." +msgstr "{cs}Le joueur {0} est désormais marqué comme mort." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/commands/KillCommand.java:89 +msgid "{ce}{0} is not an alive player." +msgstr "{ce}{0} n'est pas un joueur vivant." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/commands/ResurrectCommand.java:58 +msgid "You must specify the player to resurrect." +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/commands/ResurrectCommand.java:71 +#, java-format +msgid "{0} was resurrected." +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/game/commands/ResurrectCommand.java:75 +msgid "{ce}This player is not playing or dead!" +msgstr "{ce}Ce joueur ne joue pas ou n'est pas mort !" + +#. / Timer. {0} = hours; {1} = minutes; {2} = seconds. +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/Timer.java:393 +msgid "{0}{gray}:{white}{1}{gray}:{white}{2}" +msgstr "{0}{gray}:{white}{1}{gray}:{white}{2}" + +#. / Timer. {0} = minutes; {1} = seconds. +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/Timer.java:398 +msgid "{white}{0}{gray}:{white}{1}" +msgstr "{white}{0}{gray}:{white}{1}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:108 +msgid "{blue}{bold}Command help for {cc}{bold}/uh timers" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:109 +msgid "{cc}/uh timers add <duration> <title ...> {ci}: adds a timer." +msgstr "" +"{cc}/uh timers add <durée> <titre ...> {ci}: ajoute un compte à rebours." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:110 +msgid "" +"{cc}/uh timers display <title ...> [--without-name] {ci}: displays a timer " +"in the scoreboard. Automatic when a timer is started." +msgstr "" +"{cc}/uh timers display <titre ...> [--without-name] {ci}: affiche un " +"compteur dans la barre latérale. Automatique au démarrage du compteur." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:111 +msgid "" +"{cc}/uh timers hide <title ...> {ci}: removes a timer from the scoreboard. " +"Don't stops the timer." +msgstr "" +"{cc}/uh timers hide <titre ...> {ci}: retire un compteur du scoreboard. " +"N'arrête pas le compteur." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:112 +msgid "{cc}/uh timers list {ci}: lists the registered timers." +msgstr "{cc}/uh timers list {ci}: liste les compteurs enregistrés." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:113 +msgid "{cc}/uh timers pause <title ...> {ci}: pauses a timer." +msgstr "{cc}/uh timers pause <titre ...> {ci}: met en pause un comparateur." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:114 +msgid "{cc}/uh timers resume <title ...> {ci}: resumes a timer." +msgstr "" +"{cc}/uh timers resume <title ...> {ci}: redémarre un compteur après une " +"pause." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:115 +msgid "{cc}/uh timers remove <title ...> {ci}: deletes a timer." +msgstr "{cc}/uh timers remove <title ...> {ci}: supprime un compteur." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:116 +msgid "" +"{cc}/uh timers set <duration> <title ...> {ci}: sets the duration of a timer." +msgstr "" +"{cc}/uh timers set <durée> <titre ...> {ci}: modifie la durée d'un compte à " +"rebours." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:117 +msgid "{cc}/uh timers start <title ...> {ci}: starts a timer." +msgstr "{cc}/uh timers start <titre ...> {ci}: démarre un compte à rebours." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:118 +msgid "" +"{cc}/uh timers stop <title ...> {ci}: stops a timer. The timer will be " +"removed from the scoreboard." +msgstr "" +"{cc}/uh timers stop <title ...> {ci}: force l'arrêt d'un compteur. Il est " +"retiré du scoraboard." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:123 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:300 +msgid "You must specify both a duration and a name." +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:128 +msgid "{ce}A timer called {0}{ce} already exists; please choose another name." +msgstr "{ce}Un compteur nommé {0}{ce} existe déjà, choisissez un autre nom." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:133 +msgid "{cs}The timer {0}{cs} (duration {1}) has been registered." +msgstr "{cs}Le compteur {0}{cs}, de durée {1}, a bien été enregistré." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:143 +msgid "{cs}The timer {0}{cs} is now displayed." +msgstr "{cs}Le compteur {0}{cs} est désormais affiché." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:152 +msgid "{cs}The timer {0}{cs} is now hidden." +msgstr "{cs}Le compteur {0}{cs} est désormais masqué." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:160 +msgid "{ci}{0} timer is registered." +msgid_plural "{ci}{0} timers are registered." +msgstr[0] "{ci}Il y a {0} compteur enregistré." +msgstr[1] "{ci}Il y a {0} compteurs enregistrés." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:171 +msgid "Paused" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:171 +msgid "Running" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:171 +msgid "Not started" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:173 +msgid "{gray}(total: {0}{gray})" +msgstr "{gray}(total : {0}{gray})" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:174 +msgid "{gray}{bold}System timer" +msgstr "{gray}{bold}Compteur système" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:175 +msgid "" +"{gray}This timer is a system timer, it cannot be modified (you can still " +"display or hide it to/from the sidebar)." +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:183 +msgid "{white}Hide this timer from the sidebar" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:183 +msgid "{white}Show this timer in the sidebar" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:198 +msgid "{white}Start this timer" +msgstr "{white}Démarrer ce compteur" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:210 +msgid "{white}Stop this timer" +msgstr "{white}Arrêter ce compteur" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:225 +msgid "{white}Resume this timer" +msgstr "{white}Redémarrer ce compteur" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:225 +msgid "{white}Pause this timer" +msgstr "{white}Mettre ce compteur en pause" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:237 +msgid "{white}Delete this timer" +msgstr "{white}Supprimer ce compteur" + +#. / Button in /uh timers +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:249 +msgid "[ Create a new timer ]" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:251 +msgid "" +"{white}Click here to create a timer\n" +"{gray}/uh timers add mm:ss <name>" +msgstr "" + +#. / Button in /uh timers +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:255 +msgid "[ Display Help ]" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:257 +msgid "" +"{white}Get some help about the commands\n" +"{gray}/uh timers help" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:272 +msgid "{cs}The timer {0}{cs} is now paused." +msgstr "{cs}Le compteur {0}{cs} est désormais en pause." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:283 +msgid "{cs}The timer {0}{cs} was resumed." +msgstr "{cs}Le compteur {0}{cs} n'est plus en pause." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:295 +msgid "{cs}The timer {0}{cs} has been deleted." +msgstr "{cs}Le compteur {0}{cs} a été supprimé." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:307 +msgid "{cs}The duration of the timer {0}{cs} is now {1}." +msgstr "{cs}La durée du compteur {0}{cs} est désormais {1}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:325 +msgid "{cs}The timer {0}{cs} was started." +msgstr "{cs}Le compteur {0}{cs} a démarré." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:336 +msgid "{cs}The timer {0}{cs} was stopped." +msgstr "{cs}Le compteur {0}{cs} a été arrêté." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:360 +msgid "{ce}This timer is not registered." +msgstr "{ce}Ce compteur n'est pas enregistré." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:366 +#, java-format +msgid "A timer name is required as argument #{0}" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:379 +#, java-format +msgid "" +"A duration is required as argument #{0}. Format: “mm”, “mm:ss” or “hh:mm:ss”." +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/timers/commands/TimersCommand.java:384 +#, java-format +msgid "" +"The duration provided as argument #{0} is invalid. Format: “mm”, “mm:ss” or " +"“hh:mm:ss”." +msgstr "" +"{ce}La syntaxe de la durée entrée en argument #{0} est invalide. Les formats " +"acceptés sont “mm”, “mm:ss” ou “hh:mm:ss”." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:109 +msgid "{blue}{bold}Command help for {cc}{bold}/uh spawns" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:110 +msgid "{cc}/uh spawns list {ci}: lists the registered spawn points." +msgstr "{cc}/uh spawns list {ci}: liste les points de démarrage enregistrés." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:111 +msgid "" +"{cc}/uh spawns dump {ci}: displays the registered spawn points in an " +"exportable format. {gray}Use this to plot the spawn points, as example." +msgstr "" +"{cc}/uh spawns dump {ci}: affiche les points de démarrage dans un format " +"exportable. {gray}Utilisez ceci pour afficher les points sur un graph, par " +"exemple." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:112 +msgid "" +"{cc}/uh spawns add {ci}: adds a spawn point for a team or a player, at the " +"current location of the sender or at the provided coordinates." +msgstr "" +"{cc}/uh spawns add [<x> <z>]{ci}: ajoute un point de démarrage à la position " +"de l'exécutant ou aux coordonnées données." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:113 +msgid "" +"{cc}/uh spawns remove [<x> <z>] {ci}: removes the spawn points at the " +"specified coordinates, or at the current location if the sender without " +"coordinates." +msgstr "" +"{cc}/uh spawns remove [<x> <z>] {ci}: supprime les points de démarrage aux " +"coordonnées spécifiées, ou à la position de l'envoyeur sans coordonnées." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:114 +msgid "" +"{cc}/uh spawns generate {ci}: automagically generates spawn points. See /uh " +"spawns generate for details." +msgstr "" +"{cc}/uh spawns generate {ci}: génère automatiquement des points de " +"démarrage. Consultez /uh spawns generate pour plus de détails." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:115 +msgid "{cc}/uh spawns reset {ci}: removes all registered spawn points." +msgstr "" +"{cc}/uh spawns reset {ci}: supprime tous les points de démarrage enregistrés." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:125 +msgid "{ce}There isn't any registered spawn point." +msgstr "{ce}Il n'y a pas de point de démarrage enregistré." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:136 +msgid "{ci}There are {0} registered spawn points." +msgstr "{ci}Il y a {0} points de démarrage enregistrés." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:153 +msgid "{lightpurple}World {0}" +msgstr "{lightpurple}Monde {0}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:231 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:314 +#, java-format +msgid "There is no world named {0}." +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:244 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:268 +msgid "{cs}Spawn added in the world {0}: {1};{2}" +msgstr "{cs}Point de démarrage ajouté dans le monde {0} : {1};{2}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:248 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:276 +msgid "{ce}You cannot add a spawn point out of the borders." +msgstr "" +"{ce}Vous ne pouvez pas ajouter un point de démarrage hors des bordures." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:252 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:280 +msgid "{ce}Unable to add this spawn point: no safe spot found in the Nether." +msgstr "" +"{ce}Impossible d'ajouter ce point de démarrage : aucun endroit sûr trouvé " +"dans le Nether." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:259 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:298 +msgid "{ce}You need to specify two coordinates." +msgstr "{ce}Vous devez spécifier deux coordonnées." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:272 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:331 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:477 +msgid "{ce}This is not a number!" +msgstr "{ce}Ceci n'est pas un nombre !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:291 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:327 +msgid "{cs}The spawn point {1};{2} in the world {0} was removed." +msgstr "{cs}Le point de démarrage {1};{2} du monde {0} a été supprimé." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:339 +msgid "{cs}All the spawn points were removed." +msgstr "{cs}Tous les points de démarrage ont été supprimés." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:349 +msgid "{aqua}Command" +msgstr "{aqua}Commande" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:350 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:478 +msgid "" +"{cc}/uh spawns generate <circular|grid|random> [size] [distanceMin] [count] " +"[xCenter] [zCenter] [world]" +msgstr "" +"{cc}/uh spawns generate <circular|grid|random> [taille] [distanceMin] " +"[nombre] [xCentre] [zCentre] [monde]" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:352 +msgid "{aqua}Shapes" +msgstr "{aqua}Formes" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:353 +msgid "" +" - {cc}random{ci}: generates random spawn points on the map, with a minimal " +"distance between them." +msgstr "" +" - {cc}random{ci} : génère des points aléatoirement sur la carte, avec une " +"distance minimale entre eux." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:354 +msgid "" +" - {cc}grid{ci}: generates the spawn points on concentric squares, with a " +"constant distance between two generated points." +msgstr "" +" - {cc}grid{ci} : génère les points sur des carrés concentriques, en " +"commençant par le plus grand. La distance entre deux points est constante." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:355 +msgid "" +" - {cc}circular{ci}: generates the spawn points on concentric circles, with " +"a minimal distance between two generated points. In each circle, the angle " +"(and the distance) between two spawn points is constant." +msgstr "" +" - {cc}circular{ci}: génère les points sur des cercles concentriques, avec " +"une distance minimale entre deux points. Sur chaque cercle, l'angle (et donc " +"la distance) entre deux points est constant." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:357 +msgid "{aqua} Arguments " +msgstr "{aqua}Arguments " + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:358 +msgid "" +" - {cc}size{ci}: the size of the region where the spawn points will be " +"generated. Squared or circular, following the shape of the map. Default: " +"map' size." +msgstr "" +" - {cc}taille{ci} : la taille de la région dans laquelle les points vont " +"être générés. La région est carrée ou circulaire, selon la configuration. " +"Par défaut : la taille de la carte." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:359 +msgid "" +" - {cc}distanceMin{ci}: the minimal distance between two spawn points. " +"Default: 250 blocks." +msgstr "" +" - {cc}distanceMin{ci} : la distance minimale entre deux points. Par " +"défaut : 250 blocs." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:360 +msgid "" +" - {cc}count{ci}: the number of spawn points to generate. Default: the " +"number of players or teams." +msgstr "" +" - {cc}nombre{ci} : le nombre de points à générer. Par défaut : le nombre de " +"joueurs ou d'équipes." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:361 +msgid "" +" - {cc}xCenter{ci}, {cc}zCenter{ci}: the center of the region where the " +"points are generated. Default: world' spawn point." +msgstr "" +" - {cc}xCentre{ci}, {cc}zCentre{ci} : le centre de la région dans laquelle " +"les points sont générés. Par défaut : le point d'apparition du monde." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:362 +msgid " - {cc}world{ci}: the world where the spawn points will be generated." +msgstr " - {cc}monde{ci} : le monde dans lequel les points seront générés." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:406 +msgid "{ci}No team found: assuming the game is a solo game." +msgstr "{ci}Aucune équipe trouvée : le jeu est considéré comme solo." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:423 +msgid "" +"{ci}Some players are not in a team; their number was added to the spawn " +"count." +msgstr "" +"{ci}Certains joueurs ne sont pas dans une équipe ; leur nombre a été ajoutés " +"aux points de démarrage à générer." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:466 +msgid "{ce}The world {0} doesn't exists." +msgstr "{ce}Le monde {0} n'existe pas." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:485 +msgid "{ci}You asked for a void generation. Thus, the generation is empty." +msgstr "{ci}Vous avez demandé de ne rien générer. Rien ne sera généré." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:497 +msgid "{ce}The generation method “{0}” is not (yet?) supported." +msgstr "{ce}La méthode de génération « {0} » n'est actuellement pas supportée." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:502 +msgid "" +"{ce}You asked for the impossible: there are too many spawn points on a too " +"small surface. Decrease the spawn count or the minimal distance between two " +"points." +msgstr "" +"{ce}Vous avez demandé l'impossible : il y a trop de points sur une trop " +"petite surface. Diminuez le nombre de points à générer ou la distance " +"minimale entre deux points." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:506 +msgid "{cs}Successfully generated the asked spawn points." +msgstr "{cs}Génération des points de démarrage effectuée avec succès." + +#. / A spawn point in the /uh spawns list command (in the overworld) +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:542 +msgid "{green}{0}{darkgreen};{green}{1}" +msgstr "{green}{0}{darkgreen};{green}{1}" + +#. / A spawn point in the /uh spawns list command (in the Nether) +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:546 +msgid "{red}{0}{darkred};{red}{1}" +msgstr "{red}{0}{darkred};{red}{1}" + +#. / A spawn point in the /uh spawns list command (in the End) +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:550 +msgid "{yellow}{0}{gold};{yellow}{1}" +msgstr "{yellow}{0}{gold};{yellow}{1}" + +#. / A spawn point in the /uh spawns list command (in a custom world) +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spawns/commands/SpawnsCommand.java:554 +msgid "{gray}{0}{darkgray};{gray}{1}" +msgstr "{gray}{0}{darkgray};{gray}{1}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/commands/SpectatorsCommand.java:68 +msgid "{ce}There isn't any spectator to list." +msgstr "{ce}Il n'y a pas de spectateur à lister." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/commands/SpectatorsCommand.java:73 +msgid "{ci}{0} registered spectator." +msgid_plural "{ci}{0} registered spectators." +msgstr[0] "{ci}{0} spectateur enregistré." +msgstr[1] "{ci}{0} spectateurs enregistrés." + +#. / A list item in the startup spectators list +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/commands/SpectatorsCommand.java:76 +msgctxt "startup_specs" +msgid "{lightpurple} - {0}" +msgstr "{lightpurple} - {0}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/commands/SpectatorsCommand.java:89 +msgid "Please add the player you want to register as spectator." +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/commands/SpectatorsCommand.java:98 +msgid "{ce}Unable to retrieve the player {0}." +msgstr "{ce]Impossible de trouver le joueur {0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/commands/SpectatorsCommand.java:101 +msgid "" +"{ce}In offline mode, you cannot add players if they never came to this " +"server." +msgstr "" +"{ce}En mode hors-ligne, vous ne pouvez pas ajouter de joueurs qui ne se sont " +"jamais connectés." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/commands/SpectatorsCommand.java:107 +msgid "{cs}The player {0} is now a spectator." +msgstr "{cs}Le joueur {0} est désormais un spectateur." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/commands/SpectatorsCommand.java:118 +msgid "Please add the player you want to unregister from spectators." +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/commands/SpectatorsCommand.java:127 +msgid "{ce}The player {0} was not found." +msgstr "{ce}Le joueur {0} n'a pas été trouvé." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/commands/SpectatorsCommand.java:132 +msgid "{cs}The player {0} is now a player." +msgstr "{cs}Le joueur {0} est désormais un joueur." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/SpectatorsModule.java:222 +msgid "Spectators are not allowed for this game." +msgstr "Les spectateurs ne sont pas autorisés à rejoindre cette partie." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/SpectatorsModule.java:228 +msgid "External spectators are not allowed for this game." +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/SpectatorsModule.java:235 +msgid "" +"{gray}The unknown player {0} just tried to join. To allow him to spectate, " +"execute {cc}{1} or click here." +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/spectators/SpectatorsModule.java:236 +#, java-format +msgid "" +"Click here to execute\n" +"{0}" +msgstr "" +"Cliquez ici pour exécuter\n" +"{0}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:60 +msgid "{ci}The current diameter of the map is {0} block." +msgid_plural "{ci}The current diameter of the map is {0} blocks." +msgstr[0] "{ci}La carte a actuellement un diamètre de {0} bloc." +msgstr[1] "{ci}La carte a actuellement un diamètre de {0} blocs." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:64 +msgid "{ci}The current map size is {0}×{0}." +msgstr "{ci}La taille actuelle de la carte est {0}×{0}." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:80 +msgid "" +"{ce}Some players are outside the future border, so this operation was " +"cancelled." +msgstr "" +"{ce}Certains joueurs étant hors de cette nouvelle bordure, l'opération a été " +"annulée." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:81 +msgid "" +"{ci}Use {cc}/uh border set {0} force{ci} to resize the border regardless to " +"this point." +msgstr "" +"{ci}Utilisez {cc}/uh border set {0} force{ci} pour changer la taille de la " +"carte malgré tout." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:97 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:122 +msgid "{lightpurple}The diameter of the map is now {0} block." +msgid_plural "{lightpurple}The diameter of the map is now {0} blocks." +msgstr[0] "{lightpurple}La carte a désormais un diamètre de {0} bloc." +msgstr[1] "{lightpurple}La carte a désormais un diamètre de {0} blocs." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:101 +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:126 +msgid "{lightpurple}The size of the map is now {0}×{0}." +msgstr "{lightpurple}La taille de la carte est désormais de {0}×{0}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:140 +#, java-format +msgid "The border motor ({0}) does not supports progressive resizes." +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:162 +msgid "" +"{ce}“{0}” is not a valid time delta... Accepted formats are mm, mm:ss or hh:" +"mm:ss." +msgstr "" +"{ce}La syntaxe de la durée « {0} » est invalide : les formats acceptés sont " +"mm, mm:ss ou hh:mm:ss." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:170 +#, fuzzy +#| msgid "{lightpurple}The diameter of the map is now {0} block." +#| msgid_plural "{lightpurple}The diameter of the map is now {0} blocks." +msgid "{lightpurple}The diameter of the map will be set to {0} block over {1}." +msgid_plural "" +"{lightpurple}The diameter of the map will be set to {0} blocks over {1}." +msgstr[0] "{lightpurple}La carte a désormais un diamètre de {0} bloc." +msgstr[1] "{lightpurple}La carte a désormais un diamètre de {0} blocs." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/commands/BorderCommand.java:174 +#, fuzzy +#| msgid "{lightpurple}The size of the map is now {0}×{0}." +msgid "{lightpurple}The size of the map will be set to {0}×{0} over {1}." +msgstr "{lightpurple}La taille de la carte est désormais de {0}×{0}" + +#. / Title of the border section in the sidebar +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:116 +#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:312 +msgid "{blue}{bold}Border" +msgstr "{blue}{bold}Bordure" + +#. / Border diameter for a squared map in the sidebar +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:124 +#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:320 +msgid "{white}{0} block wide" +msgid_plural "{white}{0} blocks wide" +msgstr[0] "{white}{0} bloc de large" +msgstr[1] "{white}{0} blocs de large" + +#. / Border diameter for a circular map in the sidebar +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:127 +#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:323 +msgid "{gray}Diameter: {white}{0} block" +msgid_plural "{gray}Diameter: {white}{0} blocks" +msgstr[0] "{gray}Diamètre : {white}{0} bloc" +msgstr[1] "{gray}Diamètre : {white}{0} blocs" + +#. / Min & max coordinates in the sidebar, to locate the border. Ex: "-500 +500". {0} = minimal coord, {1} = maximal coord. +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:143 +#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:339 +msgid "{white}{0} {1}" +msgstr "{white}{0} {1}" + +#. / Min & max X coordinates in the sidebar, to locate the border. Ex: "X: -500 +500". {0} = minimal coord, {1} = maximal coord. +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:148 +#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:344 +msgid "{gray}X: {white}{0} {1}" +msgstr "{gray}X: {white}{0} {1}" + +#. / Min & max Z coordinates in the sidebar, to locate the border. Ex: "Z: -500 +500". {0} = minimal coord, {1} = maximal coord. +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:150 +#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:346 +msgid "{gray}Z: {white}{0} {1}" +msgstr "{gray}Z: {white}{0} {1}" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:285 +msgid "{cs}All players are inside the given border." +msgstr "{cs}Tous les joueurs sont à l'intérieur de cette bordure." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:289 +msgid "{ci}There are {0} players outside the given border." +msgstr "{ci}Il y a {0} joueurs hors de cette bordure." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:295 +msgid "{lightpurple} - {red}{0}{ci} (far away from the border)" +msgstr "{lightpurple} - {red}{0}{ci} (loin de la bordure)" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:299 +msgid "{lightpurple} - {yellow}{0}{ci} (close to the border)" +msgstr "{lightpurple} - {yellow}{0}{ci} (proche de la bordure)" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:303 +msgid "{lightpurple} - {green}{0}{ci} (very close to the border)" +msgstr "{lightpurple} - {green}{0}{ci} (très proche de la bordure)" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:323 +msgid "{red}Warning!" +msgstr "{red}Attention !" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:323 +msgid "{white}The border begins to shrink..." +msgstr "{white}La bordure commence à se réduire..." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:325 +msgid "{red}{bold}The border begins to shrink..." +msgstr "{red}{bold}La bordure commence à se réduire..." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:326 +msgid "" +"{gray}It will shrink by one block every {0} second(s) until {1} blocks in " +"diameter." +msgstr "" +"{gray}Elle réduira d'un bloc toutes les {0} seconde(s) jusqu'à atteindre {1} " +"blocs de diamètre." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/border/BorderModule.java:343 +msgid "{red}The border will start to shrink in {0} minute..." +msgid_plural "{red}The border will start to shrink in {0} minutes..." +msgstr[0] "{red}La bordure va commencer à se réduire dans {0} minute..." +msgstr[1] "{red}La bordure va commencer à se réduire dans {0} minutes..." + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/modules/ModulesManagerModule.java:79 +msgid "{gold}To configure the game," +msgstr "{gold}Pour configurer le jeu," + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/modules/ModulesManagerModule.java:80 +msgid "{gold}use {bold}/config" +msgstr "{gold}utilisez {bold}/config" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/modules/ModulesCommand.java:70 +msgid "{0} module registered {gray}(hover for details)" +msgid_plural "{0} modules registered {gray}(hover for details)" +msgstr[0] "" +msgstr[1] "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/modules/ModulesCommand.java:98 +msgid "Enabled" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/modules/ModulesCommand.java:98 +msgid "Disabled" +msgstr "" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/modules/ModulesCommand.java:100 +msgid "Load time" +msgstr "Période de chargement" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/modules/ModulesCommand.java:104 +msgid "Provided commands" +msgstr "Commandes fournies" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/modules/ModulesCommand.java:110 +msgid "External dependencies" +msgstr "Dépendances externes" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/modules/ModulesCommand.java:116 +msgid "Internal module" +msgstr "Module interne" + +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/modules/ModulesCommand.java:120 +msgid "Cannot be disabled" +msgstr "Non désactivable" + +#. / Title of the team section in the sidebar +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/teams/TeamsModule.java:167 +#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:207 +msgid "{bold}Your team" +msgstr "{bold}Votre équipe" + +#. / Default nick name when a player cannot be recognized. +#: src/main/java/eu/carrade/amaury/UHCReloaded/modules/core/teams/sidebar/SidebarPlayerCache.java:133 +msgid "Unknown" +msgstr "Inconnu" + +#. / Notice displayed at the bottom of the sidebar if the game is paused (/uh freeze all). +#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:383 +msgid "{darkaqua}Game frozen" +msgstr "{darkaqua}En pause" + +#. *** Ready *** +#: src/main/java/eu/carrade/amaury/UHCReloaded/UHCReloaded.java:196 +msgid "Ultra Hardcore plugin loaded." +msgstr "Plugin Ultra Hardcore chargé." + +#~ msgid "{red}Team deleted" +#~ msgstr "{red}Équipe supprimée." + +#~ msgid "{gray}Press {white}Escape{gray} to go back to the teams list." +#~ msgstr "" +#~ "{gray}Appuyez sur {white}Échap{gray} pour retourner à la liste des " +#~ "équipes." + +#~ msgid "{0} » {darkred}Delete" +#~ msgstr "{0} » {darkred}Supprimer" + +#~ msgid "{green}Keep this team alive" +#~ msgstr "{green}Garder cette équipe en vie" + +#~ msgid "{red}Delete this team {italic}forever" +#~ msgstr "{red}Supprimer cette équipe {italic}pour l'éternité" + +#~ msgid "{0} » {black}Members" +#~ msgstr "{0} » {black}Membres" + +#~ msgid "{green}« Go back" +#~ msgstr "{green}« Retour" + +#~ msgid "{reset}{0}" +#~ msgstr "{reset}{0}" + +#~ msgid "{gray}Online" +#~ msgstr "{gray}En ligne" + +#~ msgid "{gray}Offline" +#~ msgstr "{gray}Hors ligne" + +#~ msgid "{gray}Current team: {0}" +#~ msgstr "{gray}Équipe : {0}" + +#~ msgid "{gray}Current team: none" +#~ msgstr "{gray}Équipe : aucune" + +#~ msgid "{darkgray}» {white}Click {gray}to remove this player" +#~ msgstr "{darkgray}» {white}Cliquez {gray}pour retirer ce joueur" + +#~ msgid "{darkgray}» {white}Click {gray}to add this player" +#~ msgstr "{darkgray}» {white}Cliquez {gray}pour ajouter ce joueur" + +#~ msgid "{0} » {black}Color" +#~ msgstr "{0} » {black}Couleur" + +#~ msgid "Teams » {black}{0}" +#~ msgstr "Équipes » {black}{0}" + +#~ msgid "{white}{0} {gray}member" +#~ msgid_plural "{white}{0} {gray}members" +#~ msgstr[0] "{white}{0} {gray}membre" +#~ msgstr[1] "{white}{0} {gray}membres" + +#~ msgid "{white}Click with a banner {gray}to update this team's banner" +#~ msgstr "" +#~ "{white}Cliquez avec une bannière {gray}pour changer la bannière de " +#~ "l'équipe" + +#~ msgid "{green}Update the color" +#~ msgstr "{green}Changer la couleur" + +#~ msgctxt "current_team_color" +#~ msgid "{gray}Current: {white}{0}" +#~ msgstr "{gray}Actuelle : {white}{0}" + +#~ msgid "{green}Rename the team" +#~ msgstr "{green}Renommer l'équipe" + +#~ msgctxt "current_team_name" +#~ msgid "{gray}Current: {white}{0}" +#~ msgstr "{gray}Actuel : {white}{0}" + +#~ msgid "{green}Add or remove players" +#~ msgstr "{green}Modifier les membres" + +#~ msgid "{black}Select a team {reset}({0})" +#~ msgstr "{black}Sélectionnez votre équipe {reset}({0})" + +#~ msgid "{white}Rename your team" +#~ msgstr "{white}Renommer votre équipe" + +#~ msgid "{gray}You have to be in a team" +#~ msgstr "{gray}Vous devez être dans une équipe" + +#~ msgid "{white}New team" +#~ msgstr "{white}Nouvelle équipe" + +#~ msgid "{blue}Players" +#~ msgstr "{blue}Joueurs" + +#~ msgid "{darkgray}- {white}{0}" +#~ msgstr "{darkgray}- {white}{0}" + +#~ msgid "{darkgray}» {white}Click {gray}to join this team" +#~ msgstr "{darkgray}» {white}Cliquez {gray}pour rejoindre l'équipe" + +#~ msgid "{darkgray}» {red}This team is full" +#~ msgstr "{darkgray}» {red}Cette équipe est pleine" + +#~ msgid "{darkgray}» {white}Click {gray}to leave this team" +#~ msgstr "{darkgray}» {white}Cliquez {gray}pour quitter l'équipe" + +#~ msgid "{darkgray}» {white}Right-click {gray}to manage this team" +#~ msgstr "{darkgray}» {white}Cliquez droit {gray}pour gérer cette équipe" + +#~ msgid "{white}Team {0} {gray}({1}/{2})" +#~ msgstr "{white}Équipe {0} {gray}({1}/{2})" + +#~ msgid "{white}Team {0} {gray}({1} player)" +#~ msgid_plural "{white}Team {0} {gray}({1} players)" +#~ msgstr[0] "{white}Équipe {0} {gray}({1} joueur)" +#~ msgstr[1] "{white}Équipe {0} {gray}({1} joueurs)" + +#~ msgid "{red}No team created" +#~ msgstr "{cs}Aucune équipe créée" + +#~ msgid "{gray}Click the emerald button below to create one." +#~ msgstr "" +#~ "{gray}Cliquez sur le bouton d'émeraude ci-dessous pour en créer une." + +#~ msgid "{gray}Wait for an administrator to create one." +#~ msgstr "{gray}Patientez le temps qu'un administrateur en ajoute une." + +#~ msgid "{gray}1. {white}{bold}Team color" +#~ msgstr "{gray}1. {white}{bold}Couleur de l'équipe" + +#~ msgid "{gray}2. {white}{bold}Team name" +#~ msgstr "{gray}2. {white}{bold}Nom de l'équipe" + +#~ msgid "New team » {black}Name" +#~ msgstr "Nouvelle équipe » {black}Nom" + +#~ msgid "" +#~ "{gray}When clicked, a sign will open; write the name of the team inside." +#~ msgstr "" +#~ "{gray}Cliquez ici pour ouvrir un panneau, et écrivez le nom de l'équipe " +#~ "dedans." + +#~ msgid "New team » {black}Color" +#~ msgstr "Nouvelle équipe » {black}Couleur" + +#~ msgid "{lightpurple}Random color" +#~ msgstr "{lightpurple}Couleur aléatoire" + +#~ msgid "New team » {black}Members" +#~ msgstr "Nouvelle équipe » {black}Membres" + +#~ msgid "{blue}{bold}Summary" +#~ msgstr "{blue}{bold}Récapitulatif" + +#~ msgid "{gray}Team name: {white}{0}" +#~ msgstr "{gray}Nom : {white}{0}" + +#~ msgid "{gray}Color: {0}" +#~ msgstr "{gray}Couleur : {0}" + +#~ msgid "{gray}Members: {white}{0}" +#~ msgstr "{gray}Membres : {white}{0}" + +#~ msgid "{green}Create the team" +#~ msgstr "{green}Créer l'équipe" + +#~ msgid "{lightpurple}Selected!" +#~ msgstr "{lightpurple}Ajouté !" + +#~ msgid "{darkgray}» {white}Click {gray}to add to the team" +#~ msgstr "{darkgray}» {white}Cliquez {gray}pour l'ajouter à l'équipe" + +#~ msgid "{cs}Team created." +#~ msgstr "{cs}Équipe créée." + +#~ msgid "{ce}This team already exists." +#~ msgstr "{ce}Cette équipe existe déjà." + +#~ msgid "{cs}Your team is now called {0}{cs}." +#~ msgstr "{cs}Votre équipe s'appelle désormais {0}{cs}." + +#~ msgid "{aqua}You are now in the {0}{aqua} team." +#~ msgstr "{aqua}Vous faites désormais partie de l'équipe {0}{aqua}." + +#~ msgid "{darkaqua}You are no longer part of the {0}{darkaqua} team." +#~ msgstr "{darkaqua}Vous ne faites plus partie de l'équipe {0}{darkaqua}." + +#~ msgid "{ce}You are not allowed to send a private message to your team." +#~ msgstr "" +#~ "{ce}Vous n'avez pas le droit d'envoyer des messages privés à votre équipe." + +#~ msgid "" +#~ "{ce}You are not allowed to enter in the private chat of another team." +#~ msgstr "" +#~ "{ce}Vous n'avez pas le droit d'entrer dans le chat privé d'une autre " +#~ "équipe." + +#~ msgid "{gold}[{0}{gold} -> his team] {reset}{1}" +#~ msgstr "{gold}[{0}{gold} -> son équipe] {reset}{1}" + +#~ msgid "{ce}You are not in a team!" +#~ msgstr "{ce}Vous n'êtes pas dans une équipe !" + +#~ msgid "{gold}[{0}{gold} -> team {1}{gold}] {reset}{2}" +#~ msgstr "{gold}[{0}{gold} -> équipe {1}{gold}] {reset}{2}" + +#~ msgid "{gold}Click on the names below to join a team" +#~ msgstr "{gold}Cliquez ci-dessous pour rejoindre une équipe" + +#~ msgid "{0} ({red}dead{reset})" +#~ msgstr "{0} ({red}mort{reset})" + +#~ msgid "{0} ({green}alive{reset})" +#~ msgstr "{0} ({green}en vie{reset})" + +#~ msgid "{gray}[{white}{0}{gray}/{white}{1}{gray}]" +#~ msgstr "{gray}[{white}{0}{gray}/{white}{1}{gray}]" + +#~ msgid "{0} player in this team" +#~ msgid_plural "{0} players in this team" +#~ msgstr[0] "{0} joueur dans cette équipe" +#~ msgstr[1] "{0} joueurs dans cette équipe" + +#~ msgid "You are in the team {0}" +#~ msgstr "Vous êtes dans l'équipe {0}" + +#~ msgid "{darkred}[×] {red}Click here to leave your team" +#~ msgstr "{darkred}[×] {red}Cliquez ici pour quitter votre équipe" + +#~ msgid "{gray}Run /join to display this again" +#~ msgstr "{gray}Exécutez /join pour réafficher ceci" + +#~ msgid "{ce}There isn't any team available." +#~ msgstr "{ce}Il n'y a aucune équipe disponible." + +#~ msgid "" +#~ "{darkpurple}{obfuscated}----{lightpurple}{italic} YOU CAN " +#~ "RESPAWN{lightpurple}, just click {italic}Respawn {lightpurple}on the next " +#~ "screen." +#~ msgstr "" +#~ "{darkpurple}{obfuscated}----{lightpurple}{italic} VOUS POUVEZ " +#~ "REVENIR{lightpurple}, cliquez sur {italic}Ressusciter {lightpurple}sur " +#~ "l'écran suivant." + +#~ msgid "{darkred}[UHC] {ce}WorldBorder is not installed: no borders' check!" +#~ msgstr "" +#~ "{darkred}[UHC] {ce}WorldBorder pas installé : bordures non surveillées !" + +#~ msgid "" +#~ "{gray}Also, without WorldBorder, the border can't be reduced during the " +#~ "game (warnings excluded)." +#~ msgstr "" +#~ "{gray}Aussi, sans WorldBorder, impossible de réduire la bordure pendant " +#~ "le jeu (sauf avertissements)." + +#~ msgid "" +#~ "{gray}Just install the plugin; UHPlugin will automatically configure it." +#~ msgstr "" +#~ "{gray}Installez le plugin ; UHPlugin va automatiquement le configurer." + +#~ msgid "{darkred}[UHC] {ce}ProtocolLib is needed but not installed!" +#~ msgstr "{darkred}[UHC] {ce}ProtocolLib est requis mais non installé !" + +#~ msgid "{gray}The following options require the presence of ProtocolLib:" +#~ msgstr "{gray}Les options suivantes requièrent la présence de ProtocolLib :" + +#~ msgctxt "protocollib_option" +#~ msgid "{darkgray} - {gray}{0}" +#~ msgstr "{darkgray} - {gray}{0}" + +#~ msgid "{gray}ProtocolLib is available here: {0}" +#~ msgstr "{gray}ProtocolLib est disponible ici : {0}" + +#~ msgid "{cs}The timer before the new border is up!" +#~ msgstr "{cs}Le temps imparti avant la nouvelle bordure est écoulé !" + +#~ msgid "{white}{0}{gray} player killed" +#~ msgid_plural "{white}{0}{gray} players killed" +#~ msgstr[0] "{white}{0}{gray} joueur tué" +#~ msgstr[1] "{white}{0}{gray} joueurs tués" + +#~ msgid "{aqua}------ Spawns points commands ------" +#~ msgstr "{aqua}------ Commandes de gestion des points de démarrage ------" + +#~ msgid "" +#~ "{cc}/uh spawns {ci}: manages the spawn points. Execute /uh spawns for " +#~ "details." +#~ msgstr "" +#~ "{cc}/uh spawns {ci}: gère les points de démarrage. Exécutez /uh spawns " +#~ "pour plus de détails." + +#~ msgid "{aqua}------ Teleportation commands ------" +#~ msgstr "{aqua}------ Commandes de téléportation ------" + +#~ msgid "" +#~ "{cc}/uh tp team <x> <y> <z> | <target> <team ...> {ci}: teleports the " +#~ "team to the given location/target." +#~ msgstr "" +#~ "{cc}/uh tp team <x> <y> <z> | <target> <team ...> {ci}: téléporte une " +#~ "équipe au lieu ou au joueur indiqué." + +#~ msgid "" +#~ "{cc}/uh tp spectators <x> <y> <z> | <target> {ci}: teleports the " +#~ "spectators (aka non-alive players) to the given location/target." +#~ msgstr "" +#~ "{cc}/uh tp spectators <x> <y> <z> | <target> {ci}: téléporte les " +#~ "spectateurs (i.e. les joueurs non-vivants) au lieu ou au joueur indiqué." + +#~ msgid "" +#~ "{cc}/uh tp {ci}: teleports the spectators or an entire team. See /uh tp " +#~ "for details." +#~ msgstr "" +#~ "{cc}/uh tp {ci}: téléporte les spectateurs ou une équipe. Consultez /uh " +#~ "tp pour plus de détails." + +#~ msgid "" +#~ "{cc}/uh about {ci}: informations about the plugin and the translation." +#~ msgstr "" +#~ "{cc}/uh about {ci}: informations à propos du plugin et des traductions." + +#~ msgid "" +#~ "{cc}/uh border warning <futureDiameter> [minutesBeforeReduction]{ci}: " +#~ "warns all players outside the given future diameter. It's just a notice, " +#~ "nothing else." +#~ msgstr "" +#~ "{cc}/uh border warning <futurDiamètre> [minutesAvantRéduction] {ci}: " +#~ "avertit tous les joueurs hors de la future bordure donnée. Ce n'est qu'un " +#~ "avertissement, rien de plus." + +#~ msgid "{cc}/uh border warning cancel{ci}: cancels a previously-set warning." +#~ msgstr "" +#~ "{cc}/uh border warning cancel {ci}: annule un précédent avertissement." + +#~ msgid "" +#~ "{ce}WARNING: {ci}because WorldBorder is not installed, players out of the " +#~ "border will not be teleported!" +#~ msgstr "" +#~ "{ce}ATTENTION: {ci}WorldBorder n'étant pas installé, les joueurs hors de " +#~ "la bordure ne seront pas téléportés !" + +#~ msgid "" +#~ "{cc}/uh border set <diameter> [force]{ci}: changes the size of the map. " +#~ "If force is not given, the operation will be canceled if there is a " +#~ "player outside the border." +#~ msgstr "" +#~ "{cc}/uh border set <diamètre> [force] {ci}: change la taille de la carte. " +#~ "Si le paramètre “force” n'est pas donné, l'opération sera annulée s'il " +#~ "existe des joueurs hors de la bordure." + +#~ msgid "" +#~ "{cc}/uh border check <diameter>{ci}: returns a list of the players " +#~ "outside the given border size." +#~ msgstr "" +#~ "{cc}/uh border check <diamètre> {ci}: retourne la liste des joueurs hors " +#~ "de la bordure." + +#~ msgid "{cc}/uh border get{ci}: returns the current size of the map." +#~ msgstr "{cc}/uh border get {ci}: retourne la taille actuelle de la carte." + +#~ msgid "" +#~ "{cc}/uh feedall [foodPoints=20] [saturation=max] {ci}: feeds all players." +#~ msgstr "" +#~ "{cc}/uh feedall [faim=20] [saturation=max] {ci}: nourrit tous les joueurs." + +#~ msgid "{ce}The player {0} is not online." +#~ msgstr "{ce}Le joueur {0} n'est pas connecté." + +#~ msgid "" +#~ "{cc}/uh tpback <player> [force] {ci}: safely teleports back a player to " +#~ "his death location." +#~ msgstr "" +#~ "{cc}/uh tpback <joueur> [force] {ci}: téléporte un joueur au lieu de sa " +#~ "mort en toute sécurité." + +#~ msgid "" +#~ "{cc}/uh tpspawn <player> [force] {ci}: safely teleports back a player to " +#~ "his spawn location." +#~ msgstr "" +#~ "{cc}/uh tpspawn <joueur> [force] {ci}: téléporte un joueur à son point de " +#~ "démarrage attribué en toute sécurité." + +#~ msgid "" +#~ "{cs}Because {0} is offline, he will be resurrected when he logins. If he " +#~ "was, he is no longer banned." +#~ msgstr "" +#~ "{cs}Comme {0} est déconnecté, il sera ressuscité dés qu'il se connectera. " +#~ "S'il l'était, il n'est plus banni." + +#~ msgid "{ce}{0} is not dead!" +#~ msgstr "{ce}{0} n'est pas mort !" + +#~ msgid "{cc}/uh resurrect <player> {ci}: resurrects a player." +#~ msgstr "{cc}/uh resurrect <joueur> {ci}: fait revivre un joueur." + +#~ msgid "{ce}This team does not exists." +#~ msgstr "{ce}Cette équipe n'existe pas." + +#~ msgid "{cs}The player {0} was successfully added to the team {1}" +#~ msgstr "{cs}Le joueur {0} a été ajouté à l'équipe {1}{cs} avec succès." + +#~ msgid "" +#~ "{cc}/uh team join <player> <teamName ...> {ci}: adds a player inside the " +#~ "given team. The name of the team is it color, or the explicit name given." +#~ msgstr "" +#~ "{cc}/uh team join <joueur> <nomÉquipe ...> {ci}: ajoute un joueur dans " +#~ "l'équipe donnée. Le nom de l'équipe est sa couleur, ou le nom explicite " +#~ "donné." + +#~ msgid "{cs}All teams where removed." +#~ msgstr "{cs}Toutes les équipes ont été supprimées." + +#~ msgid "{cc}/uh team reset {ci}: removes all teams." +#~ msgstr "{cc}/uh team reset {ci}: supprime toutes les équipes." + +#~ msgid "" +#~ "{ce}Unable to add the team, check the color name. Tip: use Tab to " +#~ "autocomplete." +#~ msgstr "" +#~ "{ce}Impossible d'ajouter l'équipe ; vérifiez le nom de la couleur. " +#~ "Conseil : utilisez l'autocomplétion." + +#~ msgid "{cs}Team {0}{cs} added." +#~ msgstr "{cs}Équipe {0}{cs} ajoutée." + +#~ msgid "" +#~ "{cc}/uh team add <color> [<name ...>] {ci}: adds a team with the provided " +#~ "color." +#~ msgstr "" +#~ "{cc}/uh team add <couleur> [<nom ...>]{ci}: ajoute une équipe de la " +#~ "couleur donnée." + +#~ msgid "{ce}The player {0} is disconnected and never logged in before!" +#~ msgstr "" +#~ "{ce}Le joueur {0} est déconnecté et ne s'est jamais connecté au serveur " +#~ "auparavant !" + +#~ msgid "{cs}The player {0} was successfully removed from his team." +#~ msgstr "{cs}Le joueur {0} a été retiré de son équipe avec succès." + +#~ msgid "{cc}/uh team leave <player> {ci}: removes a player from his team." +#~ msgstr "{cc}/uh team leave <joueur> {ci}: retire un joueur de son équipe." + +#~ msgid "{cs}Team {0} deleted." +#~ msgstr "{cs}Équipe {0} supprimée." + +#~ msgid "{cc}/uh team remove <name ...> {ci}: removes a team" +#~ msgstr "{cc}/uh team remove <nom ...> {ci}: supprime une équipe." + +#~ msgid "{ce}There isn't any team to show." +#~ msgstr "{ce}Il n'y a pas d'équipe à lister." + +#~ msgid "{0} ({1} player)" +#~ msgid_plural "{0} ({1} players)" +#~ msgstr[0] "{0} ({1} joueur)" +#~ msgstr[1] "{0} ({1} joueurs)" + +#~ msgctxt "teams_list" +#~ msgid "{0}" +#~ msgstr "{0}" + +#~ msgid "{cc}/uh team list {ci}: lists the teams and their players." +#~ msgstr "{cc}/uh team list {ci}: liste toutes les équipes et leurs membres." + +#~ msgid "{ce}Either this team does not exists, or you are not in a team." +#~ msgstr "{ce}Cette équipe n'existe pas, ou vous n'êtes pas dans une équipe." + +#~ msgid "{ce}You must run this command with a banner in your main hand." +#~ msgstr "" +#~ "{ce}Vous devez avoir une bannière dans votre main principale pour lancer " +#~ "cette commande." + +#~ msgid "{cs}The banner of the team {0}{cs} was successfully updated." +#~ msgstr "{cs}La bannière de l'équipe {0}{cs} a été mise à jour avec succès." + +#~ msgid "" +#~ "{cc}/uh team banner [team name ...] {ci}: updates the team's banner using " +#~ "the banner in the sender hand. If the team name is not provided, uses the " +#~ "sender's team." +#~ msgstr "" +#~ "{cc}/uh team banner [nom de l'équipe ...] {ci}: change la bannière de " +#~ "l'équipe en utilisant la bannière dans la main de l'exécuteur. Si le nom " +#~ "de l'équipe n'est pas spécifié, celle de l'exécuteur est utilisée." + +#~ msgid "{ce}From the console, you must provide a team name." +#~ msgstr "{ce}Depuis la console, vous devez préciser le nom d'une équipe." + +#~ msgid "" +#~ "{cs}The banner of the team {0}{cs} was successfully reset to the default " +#~ "one." +#~ msgstr "" +#~ "{cs}La bannière de l'équipe {0}{cs} a été réinitialisée avec succès." + +#~ msgid "" +#~ "{cc}/uh team bannerreset [team name ...] {ci}: resets the banner of the " +#~ "team to the default. If the team name is not provided, uses the sender's " +#~ "team." +#~ msgstr "" +#~ "{cc}/uh team bannerreset [nom de l'équipe ...] {ci}: réinitialise la " +#~ "bannière de l'équipe à celle générée par défaut. Si le nom de l'équipe " +#~ "n'est pas spécifié, celle de l'exécuteur est utilisée." + +#~ msgid "{cc}/uh team gui {ci}: opens a GUI to join and manage the teams." +#~ msgstr "" +#~ "{cc}/uh team gui {ci}: ouvre une interface graphique pour gérer et " +#~ "rejoindre les équipes." + +#~ msgid "{ce}Cannot toggle the spy mode of {0} because he/she is offline." +#~ msgstr "" +#~ "{ce}Impossible d'inverser le mode d'espoinnage de {0} car il (ou elle) " +#~ "n'est pas connecté(e)." + +#~ msgid "{cs}Spy mode {darkred}disabled{cs} for {0}." +#~ msgstr "{cs}Espoinnage {darkred}désactivé{cs} pour {0}." + +#~ msgid "{cs}Spy mode {darkgreen}enabled{cs} for {0}." +#~ msgstr "{cs}Espionnage {darkgreen}activé{cs} pour {0}." + +#~ msgid "" +#~ "{cc}/uh team spy [player] {ci}: allows yourself (or the target player) to " +#~ "receive all the team chats (read-only). Execute again to stop." +#~ msgstr "" +#~ "{cc}/uh team spy [joueur] {ci}: permet de recevoir (soit-même ou le " +#~ "joueur ciblé) tous les chats d'équipe (en lecture seule). Exécutez une " +#~ "autre fois pour interrompre." + +#~ msgid "{aqua}------ Timers commands ------" +#~ msgstr "{aqua}------ Commandes liées aux comptes à rebours ------" + +#~ msgid "{cc}/uh timers {ci}: manages the timers. See /uh timers for details." +#~ msgstr "" +#~ "{cc}/uh timers {ci}: gère les comptes à rebours. Consultez /uh timers " +#~ "pour plus de détails." + +#~ msgid "{aqua}------ Team commands ------" +#~ msgstr "{aqua}------ Commandes liées aux équipes ------" + +#~ msgid "" +#~ "{cc}/join [player] <team ...> {ci}: adds “player” (or the sender) inside " +#~ "the given team. Without arguments, displays the chat-based team selector." +#~ msgstr "" +#~ "{cc}/join [joueur] <équipe ...> {ci}: ajoute “joueur” (ou l'envoyeur) " +#~ "dans l'équipe donnée. Sans argument, affiche le sélecteur d'équipe." + +#~ msgid "" +#~ "{cc}/leave [player] {ci}: removes “player” (or the sender) from his team." +#~ msgstr "" +#~ "{cc}/leave [joueur] {ci}: retire “joueur” (ou l'envoyeur) de son équipe." + +#~ msgid "{cc}/uh team {ci}: manages the teams. Execute /uh team for details." +#~ msgstr "" +#~ "{cc}/uh team {ci}: gère les équipes. Exécutez /uh team pour plus de " +#~ "détails." + +#~ msgid "{aqua}------ Border commands ------" +#~ msgstr "{aqua}------ Commandes liées aux bordures ------" + +#~ msgid "" +#~ "{cc}/uh border {ci}: manages borders. Execute /uh border for details." +#~ msgstr "" +#~ "{cc}/uh border {ci}: gère la bordure. Exécutez /uh border pour plus de " +#~ "détails." + +#~ msgid "" +#~ "{cc}/uh healall [half-hearts=20|±diff] {ci}: heals all players instead of " +#~ "only one." +#~ msgstr "" +#~ "{cc}/uh healall [demi-coeurs=20|±diff] {ci}: change la vie de tous les " +#~ "joueurs, et non d'un seul." + +#~ msgid "{cc}/uh shift {ci}: shifts an episode." +#~ msgstr "{cc}/uh shift {ci}: passe un épisode." + +#~ msgid "" +#~ "{cc}/uh generatewalls {ci}: generates the walls according to the " +#~ "configuration." +#~ msgstr "" +#~ "{cc}/uh generatewalls {ci}: génère les murs suivant la configuration." + +#~ msgid "{yellow} • {{ci}{0}{ci} - total {1} second - {2}" +#~ msgid_plural "{yellow} • {{ci}{0}{ci} - total {1} seconds - {2}" +#~ msgstr[0] "{yellow} • {ci}{0}{ci} - {1} seconde au total - {2}" +#~ msgstr[1] "{yellow} • {ci}{0}{ci} - {1} secondes au total - {2}" + +#~ msgid "{green} • {ci}{0}{ci} - total {1} second - {2}" +#~ msgid_plural "{green} • {ci}{0}{ci} - total {1} seconds - {2}" +#~ msgstr[0] "{green} • {ci}{0}{ci} - {1} seconde au total - {2}" +#~ msgstr[1] "{green} • {ci}{0}{ci} - {1} secondes au total - {2}" + +#~ msgid "{red} • {ci}{0}{ci} - total {1} second" +#~ msgid_plural "{red} • {ci}{0}{ci} - total {1} seconds" +#~ msgstr[0] "{red} • {ci}{0}{ci} - {1} seconde au total" +#~ msgstr[1] "{red} • {ci}{0}{ci} - {1} secondes au total" + +#~ msgid "" +#~ "{cc}/uh loadplayers <pseudo> [pseudo] ... {ci}: loads the given players " +#~ "in the server so they can be added to teams even if they never logged in." +#~ msgstr "" +#~ "{cc}/uh loadplayers <pseudo> [pseudo] ... {ci}: charges les joueurs " +#~ "spécifiés afin qu'il puissent être ajoutés dans une équipe même s'ils ne " +#~ "se sont jamais connectés au serveur." + +#~ msgid "{ce}This player is offline." +#~ msgstr "{ce}Ce joueur n'est pas connecté." + +#~ msgid "" +#~ "{cc}/uh heal <player> [half-hearts=20|±diff] {ci}: heals a player to the " +#~ "number of half-hearts provided (default 20)." +#~ msgstr "" +#~ "{cc}/uh heal <joueur> [demi-coeurs=20|±diff] {ci}: change la vie d'un " +#~ "joueur avec le nombre de demi-coeurs donné (par défaut, 20)." + +#~ msgid "" +#~ "{cc}/uh feed <player> [foodPoints=20] [saturation=max] {ci}: feeds a " +#~ "player." +#~ msgstr "" +#~ "{cc}/uh feed <joueur> [faim=20] [saturation=max] {ci}: nourrit un joueur." + +#~ msgid "" +#~ "{cc}/uh kill <player> {ci}: mark a player as dead, even if he is offline." +#~ msgstr "" +#~ "{cc}/uh kill <joueur> {ci}: marque un joueur comme mort, même s'il est " +#~ "hors-ligne." + +#~ msgid "{aqua}------ Beginning of the game ------" +#~ msgstr "{aqua}------ Démarrage du jeu ------" + +#~ msgid "{cc}/uh start {ci}: starts the game. Period." +#~ msgstr "{cc}/uh start {ci}: démarre le jeu, tout simplement." + +#~ msgid "{aqua}Startup options" +#~ msgstr "{aqua}Options de démarrage" + +#~ msgid "" +#~ "{ci}You can add some tags to change the way the game is started, just " +#~ "append them to the command with spaces." +#~ msgstr "" +#~ "{ci}Vous pouvez ajouter des options pour changer la manière dont le jeu " +#~ "est démarré. Pour ce faire, ajoutez les tags suivant après la commande " +#~ "(séparés par des espaces)." + +#~ msgid "" +#~ "{cc}slow:true {ci}: launches the game slowly, in two steps (teleportation " +#~ "then beginning of the game), for smaller servers." +#~ msgstr "" +#~ "{cc}slow:true {ci}: lance le jeu doucement, en deux étapes (téléportation " +#~ "puis commencement), pour les plus petits serveurs." + +#~ msgid "" +#~ "{cc}ignoreTeams:true {ci}: even with teams, teleports the players like in " +#~ "a solo game (only one player per spawn point, not a spawn point per team)." +#~ msgstr "" +#~ "{cc}ignoreTeams:true {ci}: même avec des équipes, téléporte les joueurs " +#~ "comme pour un jeu solo (uniquement un joueur par point de démarrage, et " +#~ "non un point par équipe)." + +#~ msgid "" +#~ "{cc}/uh start {ci}: launches the game. See /uh start help for options " +#~ "(slow and ignoreTeams)." +#~ msgstr "" +#~ "{cc}/uh start {ci}: lance le jeu. Consultez /uh start help pour les " +#~ "options de démarrage (lent, en ignorant les équipes)." + +#~ msgid "{ci}This count includes only the initial spectators." +#~ msgstr "{ci}Ce compte inclue uniquement les spectateurs initiaux." + +#~ msgid "{aqua}------ Startup spectators commands ------" +#~ msgstr "{aqua}------ Commandes liées aux spectateurs initiaux ------" + +#~ msgid "{cc}/uh spec add <player>{ci}: adds a startup spectator." +#~ msgstr "{cc}/uh spec add <joueur> {ci}: ajoute un spectateur initial." + +#~ msgid "{cc}/uh spec remove <player>{ci}: removes a startup spectator." +#~ msgstr "{cc}/uh spec remove <joueur> {ci}: supprime un spectateur initial." + +#~ msgid "{cc}/uh spec list{ci}: lists the startup spectators." +#~ msgstr "{cc}/uh spec list {ci}: liste les spectateurs initiaux." + +#~ msgid "" +#~ "{cc}/uh spec {ci}: manages the spectators. Execute /uh spec for details." +#~ msgstr "" +#~ "{cc}/uh spec {ci}: gère les spectateurs. Exécutez /uh spec pour plus de " +#~ "détails." + +#~ msgid "{cs}You are now chatting with your team only." +#~ msgstr "{cs}Vous discutez désormais avec votre équipe." + +#~ msgid "{cs}You are now chatting with everyone." +#~ msgstr "{cs}Vous discutez désormais avec tous le monde." + +#~ msgid "{cs}You are now chatting with the team {0}{cs}." +#~ msgstr "{cs}Vous discutez désormais avec l'équipe {0}{cs}." + +#~ msgctxt "winners_list" +#~ msgid "and" +#~ msgstr "et" + +#~ msgid "" +#~ "{darkgreen}{obfuscated}--{green} Congratulations to {0} (team {1}{green}) " +#~ "for their victory! {darkgreen}{obfuscated}--" +#~ msgstr "" +#~ "{darkgreen}{obfuscated}--{green} Félicitations à {0} (équipe {1}{green}) " +#~ "pour leur victoire ! {darkgreen}{obfuscated}--" + +#~ msgid "" +#~ "{darkgreen}{obfuscated}--{green} Congratulations to {0} for his victory! " +#~ "{darkgreen}{obfuscated}--" +#~ msgstr "" +#~ "{darkgreen}{obfuscated}--{green} Félicitation à {0} pour sa victoire ! " +#~ "{darkgreen}{obfuscated}--" + +#~ msgid "{darkgreen}{0}" +#~ msgstr "{darkgreen}{0}" + +#~ msgid "{green}This team wins the game!" +#~ msgstr "{green}Cette équipe remporte la victoire !" + +#~ msgid "{green}wins the game!" +#~ msgstr "{green}remporte la partie !" + +#~ msgid "" +#~ "{ce}Unable to add the player {0} to the team {1}. This player is unknown " +#~ "in the server." +#~ msgstr "" +#~ "{ce}Impossible d'ajouter le joueur {0} dans l'équipe {1}. Ce joueur n'est " +#~ "jamais venu sur ce serveur." + +#~ msgid "Spawn point {0},{1} added from the config file" +#~ msgstr "" +#~ "Point de démarrage {0},{1} ajouté depuis le fichier de configuration." + +#~ msgid "Invalid spawn point set in config: {0}" +#~ msgstr "Point de démarrage invalide dans la configuration : {0}" + +#~ msgid "Invalid team set in config: {0}" +#~ msgstr "Équipe invalide dans la configuration : {0}" + +#~ msgid "Team {0} ({1}) added from the config file" +#~ msgstr "Équipe {0} ({1}) ajoutée depuis le fichier de configuration." + +#~ msgid "Team {0} added from the config file" +#~ msgstr "Équipe {0} ajoutée depuis le fichier de configuration." diff --git a/src/main/resources/i18n/fr_FR.po b/src/main/resources/i18n/fr_FR.po deleted file mode 100644 index cd773ab..0000000 --- a/src/main/resources/i18n/fr_FR.po +++ /dev/null @@ -1,2505 +0,0 @@ -# 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. -# -msgid "" -msgstr "" -"Project-Id-Version: 1.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-12-19 16:34+0100\n" -"PO-Revision-Date: 2016-12-19 16:35+0100\n" -"Last-Translator: Amaury Carrade\n" -"Language-Team: Amaury Carrade\n" -"Language: fr_FR\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n>1;\n" -"X-Generator: Poedit 1.7.5\n" - -#. The name of the warning timer displaying the time left before the next border -#: src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java:86 -msgid "Border shrinking" -msgstr "Réduction" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java:365 -msgid "{cs}All players are inside the given border." -msgstr "{cs}Tous les joueurs sont à l'intérieur de cette bordure." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java:369 -msgid "{ci}There are {0} players outside the given border." -msgstr "{ci}Il y a {0} joueurs hors de cette bordure." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java:375 -msgid "{lightpurple} - {red}{0}{ci} (far away from the border)" -msgstr "{lightpurple} - {red}{0}{ci} (loin de la bordure)" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java:379 -msgid "{lightpurple} - {yellow}{0}{ci} (close to the border)" -msgstr "{lightpurple} - {yellow}{0}{ci} (proche de la bordure)" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java:383 -msgid "{lightpurple} - {green}{0}{ci} (very close to the border)" -msgstr "{lightpurple} - {green}{0}{ci} (très proche de la bordure)" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java:429 -msgid "{red}Warning!" -msgstr "{red}Attention !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java:429 -msgid "{white}The border begins to shrink..." -msgstr "{white}La bordure commence à se réduire..." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java:431 -msgid "{red}{bold}The border begins to shrink..." -msgstr "{red}{bold}La bordure commence à se réduire..." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/borders/BorderManager.java:432 -msgid "" -"{gray}It will shrink by one block every {0} second(s) until {1} blocks in " -"diameter." -msgstr "" -"{gray}Elle réduira d'un bloc toutes les {0} seconde(s) jusqu'à atteindre {1} " -"blocs de diamètre." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java:42 -msgctxt "protip" -msgid "{gray}You can lock and unlock the team chat with {cc}/togglechat{gray}." -msgstr "" -"{gray}Verrouillez le chat d'équipe avec {cc}/togglechat{gray}, qui permet de " -"passer d'un chat à l'autre." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java:43 -msgctxt "protip" -msgid "{gray}You can send a global message using {cc}/g <message>{gray}." -msgstr "" -"{gray}Vous pouvez envoyer un message à tout le monde avec {cc}/g " -"<message>{gray}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java:44 -msgctxt "protip" -msgid "{gray}You can send a team-chat message with {cc}/t <message>{gray}." -msgstr "" -"{gray}Vous pouvez envoyer un message à votre équipe avec {cc}/t " -"<message>{gray}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java:46 -msgctxt "protip" -msgid "" -"{gray}You can craft golden apples with heads (same recipe with a head " -"instead of an apple)." -msgstr "" -"{gray}Vous pouvez fabriquer des pommes d'or avec les têtes (même recette " -"avec une tête à la place de la pomme)." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java:47 -msgctxt "protip" -msgid "" -"{gray}The compass is crafted with, in the corners, a bone, a rotten flesh, a " -"spider eye and a gunpowder." -msgstr "" -"{gray}La boussole se fabrique avec dans les coins un os, une chaire de " -"zombie, un œil d'araignée et une poudre à canon." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java:48 -msgctxt "protip" -msgid "" -"{gray}The compass is crafted with, in the corners, a bone, a rotten flesh, a " -"spider eye and a gunpowder; in the center, an ender pearl." -msgstr "" -"{gray}La boussole se fabrique avec dans les coins un os, une chaire de " -"zombie, un œil d'araignée et une poudre à canon ; au centre une Perle du " -"Néant." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java:49 -msgctxt "protip" -msgid "" -"{gray}The compass is crafted with, in the corners, a bone, a rotten flesh, a " -"spider eye and a gunpowder; in the center, an Eye of Ender." -msgstr "" -"{gray}La boussole se fabrique avec dans les coins un os, une chaire de " -"zombie, un œil d'araignée et une poudre à canon ; au centre un Œil du Néant." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java:50 -msgctxt "protip" -msgid "{gray}The glistering melon is crafted with a melon and a gold block." -msgstr "" -"{gray}La pastèque scintillante se fabrique avec une pastèque et un bloc d'or." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java:52 -msgctxt "protip" -msgid "{gray}The enchanted golden apple is disabled for this game." -msgstr "{gray}La pomme d'or enchantée est désactivée pour cette partie." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTips.java:54 -msgctxt "protip" -msgid "" -"{gray}Fallen on a tree? Jump, you have a few seconds left to remain " -"invincible." -msgstr "" -"{gray}Tombé(e) sur un arbre ? Sautez, il vous reste quelques dizaines de " -"secondes d'invincibilité." - -#. ProTip invite, displayed before a ProTip. -#: src/main/java/eu/carrade/amaury/UHCReloaded/protips/ProTip.java:132 -msgid "{darkpurple}ProTip!" -msgstr "{darkpurple}Astuce !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/UHCReloaded.java:209 -msgid "Ultra Hardcore plugin loaded." -msgstr "Plugin Ultra Hardcore chargé." - -#. Title of the item displayed if a team was deleted while someone edited it in a GUI. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamActionGUI.java:70 -msgid "{red}Team deleted" -msgstr "{red}Équipe supprimée." - -#. Lore of the item displayed if a team was deleted while someone edited it in a GUI. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamActionGUI.java:72 -msgid "{gray}The team {0}{gray} was deleted by another player." -msgstr "{gray}L'équipe {0}{gray} a été supprimée par un autre joueur." - -#. Lore of the item displayed if a team was deleted while someone edited it in a GUI. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamActionGUI.java:75 -msgid "{gray}Press {white}Escape{gray} to go back to the teams list." -msgstr "" -"{gray}Appuyez sur {white}Échap{gray} pour retourner à la liste des équipes." - -#. The title of the delete team GUI. {0} = team name (raw). -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditDeleteGUI.java:58 -msgid "{0} » {darkred}Delete" -msgstr "{0} » {darkred}Supprimer" - -#. The title of the "keep" button in the delete team GUI -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditDeleteGUI.java:72 -msgid "{green}Keep this team alive" -msgstr "{green}Garder cette équipe en vie" - -#. The title of the "delete" button in the delete team GUI -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditDeleteGUI.java:84 -msgid "{red}Delete this team {italic}forever" -msgstr "{red}Supprimer cette équipe {italic}pour l'éternité" - -#. The title of the edit team members GUI. {0} = team name (raw). -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditMembersGUI.java:67 -msgid "{0} » {black}Members" -msgstr "{0} » {black}Membres" - -#. Go back button in GUIs. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditMembersGUI.java:76 -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:131 -msgid "{green}« Go back" -msgstr "{green}« Retour" - -#. The title of a button to select a player (a skull button). {0} = player's display name. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditMembersGUI.java:93 -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:135 -msgid "{reset}{0}" -msgstr "{reset}{0}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditMembersGUI.java:95 -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:137 -msgid "{gray}Online" -msgstr "{gray}En ligne" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditMembersGUI.java:95 -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:137 -msgid "{gray}Offline" -msgstr "{gray}Hors ligne" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditMembersGUI.java:96 -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:138 -msgid "{gray}Current team: {0}" -msgstr "{gray}Équipe : {0}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditMembersGUI.java:96 -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:138 -msgid "{gray}Current team: none" -msgstr "{gray}Équipe : aucune" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditMembersGUI.java:98 -msgid "{darkgray}» {white}Click {gray}to remove this player" -msgstr "{darkgray}» {white}Cliquez {gray}pour retirer ce joueur" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditMembersGUI.java:98 -msgid "{darkgray}» {white}Click {gray}to add this player" -msgstr "{darkgray}» {white}Cliquez {gray}pour ajouter ce joueur" - -#. The title of the edit team color GUI. {0} = team name (raw). -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditColorGUI.java:54 -msgid "{0} » {black}Color" -msgstr "{0} » {black}Couleur" - -#. The title of the edit team GUI. {0} = team display name. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:66 -msgid "Teams » {black}{0}" -msgstr "Équipes » {black}{0}" - -#. Members count in the banner description, in the team edit GUI. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:79 -msgid "{white}{0} {gray}member" -msgid_plural "{white}{0} {gray}members" -msgstr[0] "{white}{0} {gray}membre" -msgstr[1] "{white}{0} {gray}membres" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:81 -msgid "{white}Click with a banner {gray}to update this team's banner" -msgstr "" -"{white}Cliquez avec une bannière {gray}pour changer la bannière de l'équipe" - -#. Update team color button in edit GUI. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:89 -msgid "{green}Update the color" -msgstr "{green}Changer la couleur" - -#. Current team color in edit GUI. {0} = formatted color name. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:91 -msgctxt "current_team_color" -msgid "{gray}Current: {white}{0}" -msgstr "{gray}Actuelle : {white}{0}" - -#. Rename team button in edit GUI. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:98 -msgid "{green}Rename the team" -msgstr "{green}Renommer l'équipe" - -#. Current team name in edit GUI. {0} = raw team name. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:100 -msgctxt "current_team_name" -msgid "{gray}Current: {white}{0}" -msgstr "{gray}Actuel : {white}{0}" - -#. Online status dot in /uh infos -#. Online dot in /uh team list -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:107 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:92 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:149 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamListCommand.java:83 -msgid "{green} • " -msgstr "{green} • " - -#. Offline status dot in /uh infos -#. Offline dot in /uh team list -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:109 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:98 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:153 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamListCommand.java:88 -msgid "{red} • " -msgstr "{red} • " - -#. Update team members button in edit GUI. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:114 -msgid "{green}Add or remove players" -msgstr "{green}Modifier les membres" - -#. Delete team button in edit GUI. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:122 -msgid "{red}Delete this team" -msgstr "{red}Supprimer cette équipe" - -#. Warning under the "delete team" button title. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/editor/TeamEditGUI.java:124 -msgid "{gray}Cannot be undone" -msgstr "{gray}Non annulable" - -#. The title of the teams selector GUI. {0} = teams count. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:75 -msgid "{black}Select a team {reset}({0})" -msgstr "{black}Sélectionnez votre équipe {reset}({0})" - -#. The title of a button to rename our team, in the selector GUI. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:87 -msgid "{white}Rename your team" -msgstr "{white}Renommer votre équipe" - -#. Warning displayed in the "Rename your team" button, if the player is not in a team -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:89 -msgid "{gray}You have to be in a team" -msgstr "{gray}Vous devez être dans une équipe" - -#. The title of a button to create a new team, in the selector GUI. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:98 -msgid "{white}New team" -msgstr "{white}Nouvelle équipe" - -#. The "Players" title in the selector GUI, on a team's tooltip -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:116 -msgid "{blue}Players" -msgstr "{blue}Joueurs" - -#. An item of the players list in the selector GUI, on a team's tooltip -#. A member bullet in the final « create the team » button of the create team GUIs -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:120 -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:118 -msgid "{darkgray}- {white}{0}" -msgstr "{darkgray}- {white}{0}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:130 -msgid "{darkgray}» {white}Click {gray}to join this team" -msgstr "{darkgray}» {white}Cliquez {gray}pour rejoindre l'équipe" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:134 -msgid "{darkgray}» {red}This team is full" -msgstr "{darkgray}» {red}Cette équipe est pleine" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:139 -msgid "{darkgray}» {white}Click {gray}to leave this team" -msgstr "{darkgray}» {white}Cliquez {gray}pour quitter l'équipe" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:144 -msgid "{darkgray}» {white}Right-click {gray}to manage this team" -msgstr "{darkgray}» {white}Cliquez droit {gray}pour gérer cette équipe" - -#. Title of the team item in the teams selector GUI (with max). {0}: team display name. {1}: players count. {2}: max count. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:182 -msgid "{white}Team {0} {gray}({1}/{2})" -msgstr "{white}Équipe {0} {gray}({1}/{2})" - -#. Title of the team item in the teams selector GUI (without max) {0}: team display name. {1}: players count. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:184 -msgid "{white}Team {0} {gray}({1} player)" -msgid_plural "{white}Team {0} {gray}({1} players)" -msgstr[0] "{white}Équipe {0} {gray}({1} joueur)" -msgstr[1] "{white}Équipe {0} {gray}({1} joueurs)" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:198 -msgid "{red}No team created" -msgstr "{cs}Aucune équipe créée" - -#. Subtitle of the item displayed in the teams selector GUI if there isn't anything to display. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:201 -msgid "{gray}Click the emerald button below to create one." -msgstr "{gray}Cliquez sur le bouton d'émeraude ci-dessous pour en créer une." - -#. Subtitle of the item displayed in the teams selector GUI if there isn't anything to display and the player cannot create a team. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/TeamsSelectorGUI.java:203 -msgid "{gray}Wait for an administrator to create one." -msgstr "{gray}Patientez le temps qu'un administrateur en ajoute une." - -#. The title of the first step in the team creator GUIs -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderBaseGUI.java:109 -msgid "{gray}1. {white}{bold}Team color" -msgstr "{gray}1. {white}{bold}Couleur de l'équipe" - -#. The title of the second step in the team creator GUIs -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderBaseGUI.java:111 -msgid "{gray}2. {white}{bold}Team name" -msgstr "{gray}2. {white}{bold}Nom de l'équipe" - -#. The title of the third step in the team creator GUIs -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderBaseGUI.java:113 -msgid "{gray}3. {white}{bold}Team members" -msgstr "{gray}3. {white}{bold}Membres de l'équipe" - -#. The title of the name selector GUI, in the create team GUIs -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepNameGUI.java:57 -msgid "New team » {black}Name" -msgstr "Nouvelle équipe » {black}Nom" - -#. The title of the button opening the sign to write the team name (creator GUIs) -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepNameGUI.java:65 -msgid "{white}Name the team" -msgstr "{white}Nommer l'équipe" - -#. The legend of the button opening the sign to write the team name (creator GUIs) -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepNameGUI.java:67 -msgid "" -"{gray}When clicked, a sign will open; write the name of the team inside." -msgstr "" -"{gray}Cliquez ici pour ouvrir un panneau, et écrivez le nom de l'équipe " -"dedans." - -#. The title of the color selector GUI, in the create team GUIs -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepColorGUI.java:61 -msgid "New team » {black}Color" -msgstr "Nouvelle équipe » {black}Couleur" - -#. The random color button in a colors selector GUI. -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepColorGUI.java:74 -msgid "{lightpurple}Random color" -msgstr "{lightpurple}Couleur aléatoire" - -#. The title of the members selector GUI, in the create team GUIs -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:80 -msgid "New team » {black}Members" -msgstr "Nouvelle équipe » {black}Membres" - -#. The summary title in the final « create the team » button of the create team GUIs -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:106 -msgid "{blue}{bold}Summary" -msgstr "{blue}{bold}Récapitulatif" - -#. The team name in the final « create the team » button of the create team GUIs -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:108 -msgid "{gray}Team name: {white}{0}" -msgstr "{gray}Nom : {white}{0}" - -#. The team color in the final « create the team » button of the create team GUIs -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:110 -msgid "{gray}Color: {0}" -msgstr "{gray}Couleur : {0}" - -#. The team members count in the final « create the team » button of the create team GUIs -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:112 -msgid "{gray}Members: {white}{0}" -msgstr "{gray}Membres : {white}{0}" - -#. The title of the final « create the team » button of the create team GUIs -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:122 -msgid "{green}Create the team" -msgstr "{green}Créer l'équipe" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:140 -msgid "{lightpurple}Selected!" -msgstr "{lightpurple}Ajouté !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:140 -msgid "{darkgray}» {white}Click {gray}to add to the team" -msgstr "{darkgray}» {white}Cliquez {gray}pour l'ajouter à l'équipe" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:170 -msgid "{cs}Team created." -msgstr "{cs}Équipe créée." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/gui/teams/builder/TeamBuilderStepPlayersGUI.java:176 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamAddCommand.java:89 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamAddCommand.java:117 -msgid "{ce}This team already exists." -msgstr "{ce}Cette équipe existe déjà." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/UHTeam.java:148 -msgid "{cs}Your team is now called {0}{cs}." -msgstr "{cs}Votre équipe s'appelle désormais {0}{cs}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/UHTeam.java:321 -msgid "{aqua}You are now in the {0}{aqua} team." -msgstr "{aqua}Vous faites désormais partie de l'équipe {0}{aqua}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/UHTeam.java:374 -msgid "{darkaqua}You are no longer part of the {0}{darkaqua} team." -msgstr "{darkaqua}Vous ne faites plus partie de l'équipe {0}{darkaqua}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamChatManager.java:85 -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamChatManager.java:212 -msgid "{ce}You are not allowed to send a private message to your team." -msgstr "" -"{ce}Vous n'avez pas le droit d'envoyer des messages privés à votre équipe." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamChatManager.java:90 -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamChatManager.java:217 -msgid "{ce}You are not allowed to enter in the private chat of another team." -msgstr "" -"{ce}Vous n'avez pas le droit d'entrer dans le chat privé d'une autre équipe." - -#. Format of a private team message from a team member. {0} = sender display name, {1} = message. -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamChatManager.java:100 -msgid "{gold}[{0}{gold} -> his team] {reset}{1}" -msgstr "{gold}[{0}{gold} -> son équipe] {reset}{1}" - -#. Error message if someone try to send a team private message out of any team -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamChatManager.java:106 -msgid "{ce}You are not in a team!" -msgstr "{ce}Vous n'êtes pas dans une équipe !" - -#. Format of a private team message from a non-team-member. {0} = sender display name, {1} = team display name, {2} = message. -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamChatManager.java:113 -msgid "{gold}[{0}{gold} -> team {1}{gold}] {reset}{2}" -msgstr "{gold}[{0}{gold} -> équipe {1}{gold}] {reset}{2}" - -#. Invite displayed in the chat team selector -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java:514 -msgid "{gold}Click on the names below to join a team" -msgstr "{gold}Cliquez ci-dessous pour rejoindre une équipe" - -#. Displayed in team tooltip of the chat team selector for a dead player -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java:535 -msgid "{0} ({red}dead{reset})" -msgstr "{0} ({red}mort{reset})" - -#. Displayed in team tooltip of the chat team selector for an alive player -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java:540 -msgid "{0} ({green}alive{reset})" -msgstr "{0} ({green}en vie{reset})" - -#. Team count with max players (ex. [3/5]) followed in-game by the team name. {0} = current count, {1} = max. -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java:550 -msgid "{gray}[{white}{0}{gray}/{white}{1}{gray}]" -msgstr "{gray}[{white}{0}{gray}/{white}{1}{gray}]" - -#. Team count without max players (ex. [3]) followed in-game by the team name. {0} = current count. -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java:552 -msgid "{gray}[{white}{0}{gray}]" -msgstr "{gray}[{white}{0}{gray}]" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java:554 -#, java-format -msgid "{0} player in this team" -msgid_plural "{0} players in this team" -msgstr[0] "{0} joueur dans cette équipe" -msgstr[1] "{0} joueurs dans cette équipe" - -#. Tooltip on the chat team selector GUI when the player is in the team. {0} = team display name. -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java:565 -#, java-format -msgid "You are in the team {0}" -msgstr "Vous êtes dans l'équipe {0}" - -#. Tooltip on the chat team selector GUI when the player is not in the team. {0} = team display name. -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java:567 -#, java-format -msgid "Click here to join the team {0}" -msgstr "Cliquez ici pour rejoindre l'équipe {0}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java:577 -msgid "{darkred}[×] {red}Click here to leave your team" -msgstr "{darkred}[×] {red}Cliquez ici pour quitter votre équipe" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java:582 -msgid "{gray}Run /join to display this again" -msgstr "{gray}Exécutez /join pour réafficher ceci" - -#. No teams. -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java:588 -msgid "{ce}There isn't any team available." -msgstr "{ce}Il n'y a aucune équipe disponible." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/teams/TeamManager.java:621 -msgid "{gold}Your team: {0}" -msgstr "{gold}Votre équipe : {0}" - -#. The kick message of a player when death.kick.do = true in config -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:158 -msgid "jayjay" -msgstr "jayjay" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:236 -#, java-format -msgid "{0}The team {1} has fallen!" -msgstr "{0}L'équipe {1} est vaincue !" - -#. A message displayed to the players under the death screen, about the respawn possibility even if the death screen says the opposite (in hardcore mode) -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:280 -msgid "" -"{darkpurple}{obfuscated}----{lightpurple}{italic} YOU CAN " -"RESPAWN{lightpurple}, just click {italic}Respawn {lightpurple}on the next " -"screen." -msgstr "" -"{darkpurple}{obfuscated}----{lightpurple}{italic} VOUS POUVEZ " -"REVENIR{lightpurple}, cliquez sur {italic}Ressusciter {lightpurple}sur " -"l'écran suivant." - -#. The kick message displayed if a player tries to relog after his death and it's forbidden by the config. -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:385 -msgid "You are dead!" -msgstr "Vous êtes mort !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:458 -msgid "{darkred}[UHC] {ce}WorldBorder is not installed: no borders' check!" -msgstr "" -"{darkred}[UHC] {ce}WorldBorder pas installé : bordures non surveillées !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:459 -msgid "" -"{gray}Also, without WorldBorder, the border can't be reduced during the game " -"(warnings excluded)." -msgstr "" -"{gray}Aussi, sans WorldBorder, impossible de réduire la bordure pendant le " -"jeu (sauf avertissements)." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:460 -msgid "" -"{gray}Just install the plugin; UHPlugin will automatically configure it." -msgstr "{gray}Installez le plugin ; UHPlugin va automatiquement le configurer." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:470 -msgid "{darkred}[UHC] {ce}ProtocolLib is needed but not installed!" -msgstr "{darkred}[UHC] {ce}ProtocolLib est requis mais non installé !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:471 -msgid "{gray}The following options require the presence of ProtocolLib:" -msgstr "{gray}Les options suivantes requièrent la présence de ProtocolLib :" - -#. An option requiring ProtocolLib, in the “missing PLib” message. {0} = option path. -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:475 -msgctxt "protocollib_option" -msgid "{darkgray} - {gray}{0}" -msgstr "{darkgray} - {gray}{0}" - -#. {0} = ProtocolLib download URL for the current Minecraft version. -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:488 -msgid "{gray}ProtocolLib is available here: {0}" -msgstr "{gray}ProtocolLib est disponible ici : {0}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:607 -msgid "{cs}The timer before the new border is up!" -msgstr "{cs}Le temps imparti avant la nouvelle bordure est écoulé !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:639 -msgid "{aqua}-------- End of episode {0} [forced by {1}] --------" -msgstr "{aqua}-------- Fin de l'épisode {0} [forcé par {1}] --------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:643 -msgid "{aqua}-------- End of episode {0} --------" -msgstr "{aqua}-------- Fin de l'épisode {0} --------" - -#. The title displayed when the episode change. {0} = new episode number; {1} = old. -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:655 -msgid "{darkaqua}Episode {aqua}{0}" -msgstr "{darkaqua}Épisode {aqua}{0}" - -#. Broadcast -#. Start message broadcasted in chat -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:679 -msgid "{green}--- GO ---" -msgstr "{green}--- GO ---" - -#. Title of title displayed when the game starts. -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:687 -msgid "{darkgreen}Let's go!" -msgstr "{darkgreen}C'est parti !" - -#. Subtitle of title displayed when the game starts. -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:689 -msgid "{green}Good luck, and have fun" -msgstr "{green}Bonne chance et bon jeu à tous" - -#. All players are notified -#. Resurrection notification. {0} = raw resurrected player name. -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameListener.java:821 -msgid "{gold}{0} returned from the dead!" -msgstr "{gold}{0} est revenu d'entre les morts !" - -#. The title of the item given before the game to select a team -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/BeforeGameListener.java:110 -msgid "{green}{bold}Select a team {gray}(Right-Click)" -msgstr "{green}{bold}Choisir une équipe {gray}(Clic droit)" - -#. The lore of the item given before the game to select a team -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/BeforeGameListener.java:112 -msgid "{gray}Right-click to select your team for this game" -msgstr "{gray}Cliquez-droit pour sélectionner votre équipe pour ce jeu." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:201 -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/CraftingListener.java:285 -msgid "{aqua}Golden head" -msgstr "{aqua}Tête d'or" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:202 -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/CraftingListener.java:286 -msgid "{lightpurple}Golden head" -msgstr "{lightpurple}Tête d'or" - -#. Error message if a player tries to use his pointing compass without rotten flesh. -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:305 -msgid "{gray}{italic}You do not have rotten flesh." -msgstr "{gray}{italic}Vous n'avez pas de chair de zombie." - -#. Error message if a player tries to use his pointing compass without a player nearby. -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:336 -msgid "{gray}{italic}Only silence answers your request." -msgstr "{gray}{italic}Seul le silence comble votre requête." - -#. Success message when a player uses his pointing compass. -#: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:343 -msgid "{gray}The compass now points to the closest player." -msgstr "{gray}Le compas pointe désormais vers le joueur le plus proche." - -#. Dynmap marker label of a death point -#: src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHDynmapIntegration.java:153 -#, java-format -msgid "Death point of {0}" -msgstr "Ici disparu {0}" - -#. Dynmap marker label of a spawn point of a team. -#: src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHDynmapIntegration.java:232 -#, java-format -msgid "Spawn point of the team {0}" -msgstr "Lieu de démarrage de l'équipe {0}" - -#. Dynmap marker label of a spawn point of a player, in solo. -#. Dynmap marker label of a spawn point of a player, when the teleportation ignores the teams. -#: src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHDynmapIntegration.java:237 -#: src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHDynmapIntegration.java:294 -#, java-format -msgid "Spawn point of {0}" -msgstr "Lieu de démarrage de {0}" - -#. Golden head lore for withers -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:280 -msgid "Made from the fallen head of a malignant monster" -msgstr "Fabriquée depuis la tête tranchée d'un monstre maléfique" - -#. Golden head lore for players. {0} = player name. -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:285 -#, java-format -msgid "Made from the fallen head of {0}" -msgstr "Fabriquée depuis la tête tranchée de {0}" - -#. Item name of a golden head (from a player) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:388 -msgctxt "player_head" -msgid "{aqua}Golden head" -msgstr "{aqua}Tête d'or" - -#. Item name of an enchanted golden head (from a player) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:394 -msgctxt "player_head" -msgid "{lightpurple}Golden head" -msgstr "{lightpurple}Tête d'or" - -#. Item name of a golden head (from a monster) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:421 -msgctxt "monster_head" -msgid "{aqua}Golden head" -msgstr "{aqua}Tête d'or" - -#. Item name of an enchanted golden head (from a monster) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:427 -msgctxt "monster_head" -msgid "{lightpurple}Golden head" -msgstr "{lightpurple}Tête d'or" - -#. Current episode in the sidebar -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:140 -msgid "{gray}Episode {white}{0}" -msgstr "{gray}Épisode {white}{0}" - -#. Players alive in the sidebar -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:149 -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:158 -msgid "{white}{0}{gray} player" -msgid_plural "{white}{0}{gray} players" -msgstr[0] "{white}{0}{gray} joueur" -msgstr[1] "{white}{0}{gray} joueurs" - -#. Teams alive in the sidebar -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:162 -msgid "{white}{0}{gray} team" -msgid_plural "{white}{0}{gray} teams" -msgstr[0] "{white}{0}{gray} équipe" -msgstr[1] "{white}{0}{gray} équipes" - -#. Title of the team section in the sidebar -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:207 -msgid "{bold}Your team" -msgstr "{bold}Votre équipe" - -#. Kills count in the sidebar -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:280 -msgid "{white}{0}{gray} player killed" -msgid_plural "{white}{0}{gray} players killed" -msgstr[0] "{white}{0}{gray} joueur tué" -msgstr[1] "{white}{0}{gray} joueurs tués" - -#. Title of the border section in the sidebar -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:311 -msgid "{blue}{bold}Border" -msgstr "{blue}{bold}Bordure" - -#. Border diameter for a squared map in the sidebar -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:319 -msgid "{white}{0} block wide" -msgid_plural "{white}{0} blocks wide" -msgstr[0] "{white}{0} bloc de large" -msgstr[1] "{white}{0} blocs de large" - -#. Border diameter for a circular map in the sidebar -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:322 -msgid "{gray}Diameter: {white}{0} block" -msgid_plural "{gray}Diameter: {white}{0} blocks" -msgstr[0] "{gray}Diamètre : {white}{0} bloc" -msgstr[1] "{gray}Diamètre : {white}{0} blocs" - -#. Min & max coordinates in the sidebar, to locate the border. Ex: "-500 +500". {0} = minimal coord, {1} = maximal coord. -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:338 -msgid "{white}{0} {1}" -msgstr "{white}{0} {1}" - -#. Min & max X coordinates in the sidebar, to locate the border. Ex: "X: -500 +500". {0} = minimal coord, {1} = maximal coord. -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:343 -msgid "{gray}X: {white}{0} {1}" -msgstr "{gray}X: {white}{0} {1}" - -#. Min & max Z coordinates in the sidebar, to locate the border. Ex: "Z: -500 +500". {0} = minimal coord, {1} = maximal coord. -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:345 -msgid "{gray}Z: {white}{0} {1}" -msgstr "{gray}Z: {white}{0} {1}" - -#. Notice displayed at the bottom of the sidebar if the game is paused (/uh freeze all). -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:386 -msgid "{darkaqua}Game frozen" -msgstr "{darkaqua}En pause" - -#. Default nick name when a player cannot be recognized. -#: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/SidebarPlayerCache.java:133 -msgid "Unknown" -msgstr "Inconnu" - -#. Title of the rules box. -#: src/main/java/eu/carrade/amaury/UHCReloaded/misc/RulesManager.java:120 -msgid "{red}{bold}Rules and informations" -msgstr "{red}{bold}Règles et informations" - -#. Rule item in the rule box. -#: src/main/java/eu/carrade/amaury/UHCReloaded/misc/RulesManager.java:131 -msgid "{darkgray}- {reset}{0}" -msgstr "{darkgray}- {reset}{0}" - -#. Episode in the player list ({episodeText} replacement). {0} = current episode number. -#: src/main/java/eu/carrade/amaury/UHCReloaded/misc/PlayerListHeaderFooterManager.java:115 -#, java-format -msgid "Episode {0}" -msgstr "Épisode {0}" - -#. Players in the player list ({playersText} replacement). {0} = current alive players count. -#: src/main/java/eu/carrade/amaury/UHCReloaded/misc/PlayerListHeaderFooterManager.java:117 -#, java-format -msgid "{0} player" -msgid_plural "{0} players" -msgstr[0] "{0} joueur" -msgstr[1] "{0} joueurs" - -#. Teams in the player list ({teamsText} replacement). {0} = current alive teams count. -#: src/main/java/eu/carrade/amaury/UHCReloaded/misc/PlayerListHeaderFooterManager.java:119 -#, java-format -msgid "{0} team" -msgid_plural "{0} teams" -msgstr[0] "{0} équipe" -msgstr[1] "{0} équipes" - -#. MOTD when the game is not started. -#: src/main/java/eu/carrade/amaury/UHCReloaded/misc/MOTDManager.java:90 -msgid "Waiting for players..." -msgstr "En attente de joueurs..." - -#. MOTD when the game is starting (slow TP in progress). -#: src/main/java/eu/carrade/amaury/UHCReloaded/misc/MOTDManager.java:99 -msgid "Starting in progress..." -msgstr "Démarrage en cours..." - -#. Solo game running MOTD. {0} = players alive count. -#: src/main/java/eu/carrade/amaury/UHCReloaded/misc/MOTDManager.java:114 -#, java-format -msgid "Game running! {0} player alive." -msgid_plural "Game running! {0} players alive." -msgstr[0] "Partie en cours ! {0} joueur encore en vie." -msgstr[1] "Partie en cours ! {0} joueurs encore en vie." - -#. Teams game running MOTD. {0} = players alive count. {1} = teams alive count. Plural based on players count. -#: src/main/java/eu/carrade/amaury/UHCReloaded/misc/MOTDManager.java:119 -#, java-format -msgid "Game running! {0} player alive in {1} team." -msgid_plural "Game running! {0} players alive in {1} teams." -msgstr[0] "Partie en cours ! {0} joueur en vie dans {1} équipe." -msgstr[1] "Partie en cours ! {0} joueurs en vie dans {1} équipes." - -#. Game finished MOTD with solo winner ({0} = winner raw name). -#: src/main/java/eu/carrade/amaury/UHCReloaded/misc/MOTDManager.java:136 -#, java-format -msgid "Game finished; congratulation to {0} for his victory!" -msgstr "Partie terminée ; félicitation à {0} pour sa victoire !" - -#. Game finished MOTD with team winner ({0} = team display name). -#: src/main/java/eu/carrade/amaury/UHCReloaded/misc/MOTDManager.java:141 -#, java-format -msgid "Game finished; the team {0} wins this match!" -msgstr "Partie terminée ; l'équipe {0} remporte la victoire !" - -#. Timer. {0} = hours; {1} = minutes; {2} = seconds. -#: src/main/java/eu/carrade/amaury/UHCReloaded/timers/UHTimer.java:404 -msgid "{0}{gray}:{white}{1}{gray}:{white}{2}" -msgstr "{0}{gray}:{white}{1}{gray}:{white}{2}" - -#. Timer. {0} = minutes; {1} = seconds. -#: src/main/java/eu/carrade/amaury/UHCReloaded/timers/UHTimer.java:409 -msgid "{white}{0}{gray}:{white}{1}" -msgstr "{white}{0}{gray}:{white}{1}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/categories/Category.java:39 -msgid "{aqua}------ Game-related commands ------" -msgstr "{aqua}------ Commandes liées au jeu ------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/categories/Category.java:40 -msgid "{aqua}------ Bugs-related commands ------" -msgstr "{aqua}------ Commandes liées aux bugs ------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/categories/Category.java:41 -msgid "{aqua}------ Miscellaneous commands ------" -msgstr "{aqua}------ Commandes diverses ------" - -#. Usage of the /g and /t commands -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/GlobalMessageCommand.java:109 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/TeamMessageCommand.java:108 -msgid "{ce}Usage: /{0} <message>" -msgstr "{ce}Utilisation : /{0} <message>" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpawnsCommand.java:94 -msgid "{aqua}------ Spawns points commands ------" -msgstr "{aqua}------ Commandes de gestion des points de démarrage ------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpawnsCommand.java:100 -msgid "" -"{cc}/uh spawns {ci}: manages the spawn points. Execute /uh spawns for " -"details." -msgstr "" -"{cc}/uh spawns {ci}: gère les points de démarrage. Exécutez /uh spawns pour " -"plus de détails." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPCommand.java:144 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPCommand.java:188 -msgid "{ce}The coordinates must be three valid numbers." -msgstr "{ce}Les coordonnées doivent être trois nombres." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPCommand.java:148 -msgid "{ce}This team is not registered." -msgstr "{ce}Cette équipe n'est pas enregistrée." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPCommand.java:157 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPCommand.java:199 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:109 -msgid "{ce}{0} is offline!" -msgstr "{ce}{0} est hors-ligne !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPCommand.java:263 -msgid "{aqua}------ Teleportation commands ------" -msgstr "{aqua}------ Commandes de téléportation ------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPCommand.java:264 -msgid "" -"{cc}/uh tp team <x> <y> <z> | <target> <team ...> {ci}: teleports the team " -"to the given location/target." -msgstr "" -"{cc}/uh tp team <x> <y> <z> | <target> <team ...> {ci}: téléporte une équipe " -"au lieu ou au joueur indiqué." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPCommand.java:265 -msgid "" -"{cc}/uh tp spectators <x> <y> <z> | <target> {ci}: teleports the spectators " -"(aka non-alive players) to the given location/target." -msgstr "" -"{cc}/uh tp spectators <x> <y> <z> | <target> {ci}: téléporte les spectateurs " -"(i.e. les joueurs non-vivants) au lieu ou au joueur indiqué." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPCommand.java:272 -msgid "" -"{cc}/uh tp {ci}: teleports the spectators or an entire team. See /uh tp for " -"details." -msgstr "" -"{cc}/uh tp {ci}: téléporte les spectateurs ou une équipe. Consultez /uh tp " -"pour plus de détails." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java:79 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/AbstractCommandExecutor.java:208 -msgid "{yellow}{0} - version {1}" -msgstr "{yellow}{0} - version {1}" - -#. The "and" in the authors list (like "Amaury Carrade, azenet and João Roda") -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java:94 -msgctxt "authors_list" -msgid "and" -msgstr "et" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java:102 -#, java-format -msgid "Plugin made with love by {0}." -msgstr "Plugin réalisé avec amour par {0}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java:129 -#, java-format -msgid "Build number: {0}." -msgstr "Numéro de construction : {0}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java:133 -msgid "Build number not available." -msgstr "Numéro de construction indisponible." - -#. Translation -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java:138 -msgid "{aqua}------ Translations ------" -msgstr "{aqua}------ Traductions ------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java:139 -#, java-format -msgid "Current language: {0} (translated by {1})." -msgstr "Langue courante : {0} (traduit par {1})." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java:140 -#, java-format -msgid "Fallback language: {0} (translated by {1})." -msgstr "Langue par défaut : {0} (traduit par {1})." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java:141 -msgid "{aqua}------ License ------" -msgstr "{aqua}------ Licence ------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java:142 -msgid "Published under the CeCILL-B License." -msgstr "Publié sous la licence CeCILL-B." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHAboutCommand.java:170 -msgid "{cc}/uh about {ci}: informations about the plugin and the translation." -msgstr "" -"{cc}/uh about {ci}: informations à propos du plugin et des traductions." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderWarningCommand.java:73 -msgid "{cs}Warning canceled." -msgstr "{cs}Avertissement annulé." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderWarningCommand.java:88 -msgid "" -"{cs}Future size saved. All players outside this future border will be warned " -"every {0} second." -msgid_plural "" -"{cs}Future size saved. All players outside this future border will be warned " -"every {0} seconds." -msgstr[0] "" -"{cs}Future taille enregistrée. Les joueurs hors de la bordure vont être " -"avertis toutes les {0} seconde." -msgstr[1] "" -"{cs}Future taille enregistrée. Les joueurs hors de la bordure vont être " -"avertis toutes les {0} secondes." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderWarningCommand.java:93 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java:98 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java:122 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderCheckCommand.java:71 -msgid "{ce}“{0}” is not a number..." -msgstr "{ce}“{0}” n'est pas un nombre..." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderWarningCommand.java:118 -msgid "" -"{cc}/uh border warning <futureDiameter> [minutesBeforeReduction]{ci}: warns " -"all players outside the given future diameter. It's just a notice, nothing " -"else." -msgstr "" -"{cc}/uh border warning <futurDiamètre> [minutesAvantRéduction] {ci}: avertit " -"tous les joueurs hors de la future bordure donnée. Ce n'est qu'un " -"avertissement, rien de plus." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderWarningCommand.java:118 -msgid "{cc}/uh border warning cancel{ci}: cancels a previously-set warning." -msgstr "{cc}/uh border warning cancel {ci}: annule un précédent avertissement." - -#. Some players are outside -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java:74 -msgid "" -"{ce}Some players are outside the future border, so this operation was " -"cancelled." -msgstr "" -"{ce}Certains joueurs étant hors de cette nouvelle bordure, l'opération a été " -"annulée." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java:75 -msgid "" -"{ci}Use {cc}/uh border set {0} force{ci} to resize the border regardless to " -"this point." -msgstr "" -"{ci}Utilisez {cc}/uh border set {0} force{ci} pour changer la taille de la " -"carte malgré tout." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java:78 -msgid "" -"{ce}WARNING: {ci}because WorldBorder is not installed, players out of the " -"border will not be teleported!" -msgstr "" -"{ce}ATTENTION: {ci}WorldBorder n'étant pas installé, les joueurs hors de la " -"bordure ne seront pas téléportés !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java:88 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java:113 -msgid "{lightpurple}The diameter of the map is now {0} block." -msgid_plural "{lightpurple}The diameter of the map is now {0} blocks." -msgstr[0] "{lightpurple}La carte a désormais un diamètre de {0} bloc." -msgstr[1] "{lightpurple}La carte a désormais un diamètre de {0} blocs." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java:92 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java:117 -msgid "{lightpurple}The size of the map is now {0}×{0}." -msgstr "{lightpurple}La taille de la carte est désormais de {0}×{0}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderSetCommand.java:147 -msgid "" -"{cc}/uh border set <diameter> [force]{ci}: changes the size of the map. If " -"force is not given, the operation will be canceled if there is a player " -"outside the border." -msgstr "" -"{cc}/uh border set <diamètre> [force] {ci}: change la taille de la carte. Si " -"le paramètre “force” n'est pas donné, l'opération sera annulée s'il existe " -"des joueurs hors de la bordure." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderCheckCommand.java:91 -msgid "" -"{cc}/uh border check <diameter>{ci}: returns a list of the players outside " -"the given border size." -msgstr "" -"{cc}/uh border check <diamètre> {ci}: retourne la liste des joueurs hors de " -"la bordure." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderGetCommand.java:60 -msgid "{ci}The current diameter of the map is {0} block." -msgid_plural "{ci}The current diameter of the map is {0} blocks." -msgstr[0] "{ci}La carte a actuellement un diamètre de {0} bloc." -msgstr[1] "{ci}La carte a actuellement un diamètre de {0} blocs." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderGetCommand.java:64 -msgid "{ci}The current map size is {0}×{0}." -msgstr "{ci}La taille actuelle de la carte est {0}×{0}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/border/UHBorderGetCommand.java:83 -msgid "{cc}/uh border get{ci}: returns the current size of the map." -msgstr "{cc}/uh border get {ci}: retourne la taille actuelle de la carte." - -#. Header of the /uh infos command. Plural based on the players count. -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:69 -msgid "{ci}{0} player alive in {1} team." -msgid_plural "{ci}{0} players alive in {1} teams." -msgstr[0] "{ci}{0} joueur en vie, dans {1} équipe." -msgstr[1] "{ci}{0} joueurs en vie, répartis dans {1} équipes." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:73 -msgid "{ci}The game is not started." -msgstr "{ci}Le jeu n'est pas encore démarré." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:93 -msgid "Currently online" -msgstr "Actuellement connecté(e)" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:99 -msgid "Currently offline" -msgstr "Actuellement hors-ligne" - -#. Team name in tooltip in /uh infos -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:108 -#, java-format -msgid "Team: {0}" -msgstr "Équipe : {0}" - -#. Separator in /uh infos -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:115 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:160 -msgid "{gray} - " -msgstr "{gray} - " - -#. Alive state in /uh infos -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:122 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:164 -msgid "{green}alive" -msgstr "{green}vivant" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:125 -#, java-format -msgid "{0} half-hearts" -msgstr "{0} demi-cœurs" - -#. Alive state in /uh infos -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:131 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:168 -msgid "{red}dead" -msgstr "{red}mort" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHInfosCommand.java:196 -msgid "{cc}/uh infos {ci}: prints some infos about the current game." -msgstr "{cc}/uh infos {ci}: affiche des informations à propos du jeu en cours." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedAllCommand.java:75 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedAllCommand.java:88 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedCommand.java:87 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedCommand.java:100 -msgid "" -"{ce}Food points and saturation must be numbers (floats for the saturation)!" -msgstr "" -"{ce}Les valeurs de faim et de saturation doivent être des nombres " -"(possiblement à virgule pour la saturation) !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedAllCommand.java:116 -msgid "" -"{cc}/uh feedall [foodPoints=20] [saturation=max] {ci}: feeds all players." -msgstr "" -"{cc}/uh feedall [faim=20] [saturation=max] {ci}: nourrit tous les joueurs." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsAddCommand.java:97 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsAddCommand.java:118 -msgid "{cs}Spawn added in the world {0}: {1};{2}" -msgstr "{cs}Point de démarrage ajouté dans le monde {0} : {1};{2}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsAddCommand.java:101 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsAddCommand.java:126 -msgid "{ce}You cannot add a spawn point out of the borders." -msgstr "" -"{ce}Vous ne pouvez pas ajouter un point de démarrage hors des bordures." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsAddCommand.java:105 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsAddCommand.java:130 -msgid "{ce}Unable to add this spawn point: no safe spot found in the Nether." -msgstr "" -"{ce}Impossible d'ajouter ce point de démarrage : aucun endroit sûr trouvé " -"dans le Nether." - -#. /uh spawns add <x>: Two coordinates needed! -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsAddCommand.java:111 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsRemoveCommand.java:85 -msgid "{ce}You need to specify two coordinates." -msgstr "{ce}Vous devez spécifier deux coordonnées." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsAddCommand.java:122 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:186 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsRemoveCommand.java:106 -msgid "{ce}This is not a number!" -msgstr "{ce}Ceci n'est pas un nombre !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsAddCommand.java:152 -msgid "" -"{cc}/uh spawns add {ci}: adds a spawn point for a team or a player, at the " -"current location of the sender or at the provided coordinates." -msgstr "" -"{cc}/uh spawns add [<x> <z>]{ci}: ajoute un point de démarrage à la position " -"de l'exécutant ou aux coordonnées données." - -#. Solo mode? -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:119 -msgid "{ci}No team found: assuming the game is a solo game." -msgstr "{ci}Aucune équipe trouvée : le jeu est considéré comme solo." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:136 -msgid "" -"{ci}Some players are not in a team; their number was added to the spawn " -"count." -msgstr "" -"{ci}Certains joueurs ne sont pas dans une équipe ; leur nombre a été ajoutés " -"aux points de démarrage à générer." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:174 -msgid "{ce}The world {0} doesn't exists." -msgstr "{ce}Le monde {0} n'existe pas." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:193 -msgid "{ci}You asked for a void generation. Thus, the generation is empty." -msgstr "{ci}Vous avez demandé de ne rien générer. Rien ne sera généré." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:205 -msgid "{ce}The generation method “{0}” is not (yet?) supported." -msgstr "{ce}La méthode de génération « {0} » n'est actuellement pas supportée." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:211 -msgid "" -"{ce}You asked for the impossible: there are too many spawn points on a too " -"small surface. Decrease the spawn count or the minimal distance between two " -"points." -msgstr "" -"{ce}Vous avez demandé l'impossible : il y a trop de points sur une trop " -"petite surface. Diminuez le nombre de points à générer ou la distance " -"minimale entre deux points." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:215 -msgid "{cs}Successfully generated the asked spawn points." -msgstr "{cs}Génération des points de démarrage effectuée avec succès." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:277 -msgid "{aqua}Command" -msgstr "{aqua}Commande" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:278 -msgid "" -"{cc}/uh spawns generate <circular|grid|random> [size] [distanceMin] [count] " -"[xCenter] [zCenter] [world]" -msgstr "" -"{cc}/uh spawns generate <circular|grid|random> [taille] [distanceMin] " -"[nombre] [xCentre] [zCentre] [monde]" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:279 -msgid "{aqua}Shapes" -msgstr "{aqua}Formes" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:280 -msgid "" -" - {cc}random{ci}: generates random spawn points on the map, with a minimal " -"distance between them." -msgstr "" -" - {cc}random{ci} : génère des points aléatoirement sur la carte, avec une " -"distance minimale entre eux." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:281 -msgid "" -" - {cc}grid{ci}: generates the spawn points on concentric squares, with a " -"constant distance between two generated points." -msgstr "" -" - {cc}grid{ci} : génère les points sur des carrés concentriques, en " -"commençant par le plus grand. La distance entre deux points est constante." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:282 -msgid "" -" - {cc}circular{ci}: generates the spawn points on concentric circles, with " -"a minimal distance between two generated points. In each circle, the angle " -"(and the distance) between two spawn points is constant." -msgstr "" -" - {cc}circular{ci}: génère les points sur des cercles concentriques, avec " -"une distance minimale entre deux points. Sur chaque cercle, l'angle (et donc " -"la distance) entre deux points est constant." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:283 -msgid "{aqua}Arguments" -msgstr "{aqua}Arguments" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:284 -msgid "" -" - {cc}size{ci}: the size of the region where the spawn points will be " -"generated. Squared or circular, following the shape of the map. Default: " -"map' size." -msgstr "" -" - {cc}taille{ci} : la taille de la région dans laquelle les points vont " -"être générés. La région est carrée ou circulaire, selon la configuration. " -"Par défaut : la taille de la carte." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:285 -msgid "" -" - {cc}distanceMin{ci}: the minimal distance between two spawn points. " -"Default: 250 blocks." -msgstr "" -" - {cc}distanceMin{ci} : la distance minimale entre deux points. Par " -"défaut : 250 blocs." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:286 -msgid "" -" - {cc}count{ci}: the number of spawn points to generate. Default: the " -"number of players or teams." -msgstr "" -" - {cc}nombre{ci} : le nombre de points à générer. Par défaut : le nombre de " -"joueurs ou d'équipes." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:287 -msgid "" -" - {cc}xCenter{ci}, {cc}zCenter{ci}: the center of the region where the " -"points are generated. Default: world' spawn point." -msgstr "" -" - {cc}xCentre{ci}, {cc}zCentre{ci} : le centre de la région dans laquelle " -"les points sont générés. Par défaut : le point d'apparition du monde." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:288 -msgid " - {cc}world{ci}: the world where the spawn points will be generated." -msgstr " - {cc}monde{ci} : le monde dans lequel les points seront générés." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsGenerateCommand.java:295 -msgid "" -"{cc}/uh spawns generate {ci}: automagically generates spawn points. See /uh " -"spawns generate for details." -msgstr "" -"{cc}/uh spawns generate {ci}: génère automatiquement des points de " -"démarrage. Consultez /uh spawns generate pour plus de détails." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsDumpCommand.java:126 -msgid "" -"{cc}/uh spawns dump {ci}: displays the registered spawn points in an " -"exportable format. {gray}Use this to plot the spawn points, as example." -msgstr "" -"{cc}/uh spawns dump {ci}: affiche les points de démarrage dans un format " -"exportable. {gray}Utilisez ceci pour afficher les points sur un graph, par " -"exemple." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsListCommand.java:75 -msgid "{ce}There isn't any registered spawn point." -msgstr "{ce}Il n'y a pas de point de démarrage enregistré." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsListCommand.java:79 -msgid "{ci}There are {0} registered spawn points." -msgstr "{ci}Il y a {0} points de démarrage enregistrés." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsListCommand.java:100 -msgid "{lightpurple}World {0}" -msgstr "{lightpurple}Monde {0}" - -#. A spawn point in the /uh spawns list command (in the overworld) -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsListCommand.java:130 -msgid "{green}{0}{darkgreen};{green}{1}" -msgstr "{green}{0}{darkgreen};{green}{1}" - -#. A spawn point in the /uh spawns list command (in the Nether) -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsListCommand.java:134 -msgid "{red}{0}{darkred};{red}{1}" -msgstr "{red}{0}{darkred};{red}{1}" - -#. A spawn point in the /uh spawns list command (in the End) -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsListCommand.java:138 -msgid "{yellow}{0}{gold};{yellow}{1}" -msgstr "{yellow}{0}{gold};{yellow}{1}" - -#. A spawn point in the /uh spawns list command (in a custom world) -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsListCommand.java:142 -msgid "{gray}{0}{darkgray};{gray}{1}" -msgstr "{gray}{0}{darkgray};{gray}{1}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsListCommand.java:185 -msgid "{cc}/uh spawns list {ci}: lists the registered spawn points." -msgstr "{cc}/uh spawns list {ci}: liste les points de démarrage enregistrés." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsResetCommand.java:67 -msgid "{cs}All the spawn points were removed." -msgstr "{cs}Tous les points de démarrage ont été supprimés." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsResetCommand.java:93 -msgid "{cc}/uh spawns reset {ci}: removes all registered spawn points." -msgstr "" -"{cc}/uh spawns reset {ci}: supprime tous les points de démarrage enregistrés." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsRemoveCommand.java:80 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsRemoveCommand.java:102 -msgid "{cs}The spawn point {1};{2} in the world {0} was removed." -msgstr "{cs}Le point de démarrage {1};{2} du monde {0} a été supprimé." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/spawns/UHSpawnsRemoveCommand.java:134 -msgid "" -"{cc}/uh spawns remove [<x> <z>] {ci}: removes the spawn points at the " -"specified coordinates, or at the current location if the sender without " -"coordinates." -msgstr "" -"{cc}/uh spawns remove [<x> <z>] {ci}: supprime les points de démarrage aux " -"coordonnées spécifiées, ou à la position de l'envoyeur sans coordonnées." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPBackCommand.java:70 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPSpawnCommand.java:79 -msgid "{ce}The player {0} is not online." -msgstr "{ce}Le joueur {0} n'est pas connecté." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPBackCommand.java:75 -msgid "{ce}No death location available for the player {0}." -msgstr "{ce}Pas de localisation de mort enregistrée pour le joueur {0}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPBackCommand.java:85 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPBackCommand.java:90 -msgid "{cs}The player {0} was teleported back." -msgstr "{cs}Le joueur {0} a été téléporté là où il est mort." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPBackCommand.java:95 -msgid "" -"{ce}The player {0} was NOT teleported back because no safe spot was found." -msgstr "" -"{ce}Le joueur {0} n'a PAS été téléporté car aucun point de téléportation sûr " -"n'a été trouvé." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPBackCommand.java:96 -msgid "" -"{ci}Use {cc}/uh tpback {0} force{ci} to teleport the player regardless this " -"point." -msgstr "" -"{ci}Utilisez {cc}/uh tpback {0} force{ci} pour le téléporter malgré tout." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPBackCommand.java:135 -msgid "" -"{cc}/uh tpback <player> [force] {ci}: safely teleports back a player to his " -"death location." -msgstr "" -"{cc}/uh tpback <joueur> [force] {ci}: téléporte un joueur au lieu de sa mort " -"en toute sécurité." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFinishCommand.java:76 -msgid "{ce}The game is not started!" -msgstr "{ce}Le jeu n'est pas encore démarré !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFinishCommand.java:80 -msgid "{ce}There's not one team alive!" -msgstr "{ce}Il n'y a pas qu'une équipe encore en vie !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFinishCommand.java:104 -msgid "" -"{cc}/uh finish {ci}: displays the name of the winner(s) and launches some " -"fireworks." -msgstr "" -"{cc}/uh finish {ci}: affiche le nom du/des vainqueurs et lance des feux " -"d'artifices." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPSpawnCommand.java:66 -msgid "" -"{ce}The spawn points are not already assigned to the player, because the " -"game is not started." -msgstr "" -"{ce}Les points de démarrage n'ont pas encore été assignés aux joueurs, car " -"le jeu n'a pas encore démarré." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPSpawnCommand.java:87 -msgid "{ce}No spawn location available for the player {0}." -msgstr "{ce}Pas de localisation de démarrage enregistrée pour le joueur {0}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPSpawnCommand.java:95 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPSpawnCommand.java:99 -msgid "{cs}The player {0} was teleported to his spawn location." -msgstr "{cs}Le joueur {0} a été téléporté à son point de démarrage attribué." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPSpawnCommand.java:103 -msgid "" -"{ce}The player {0} was NOT teleported to his spawn because no safe spot was " -"found." -msgstr "" -"{ce}Le joueur {0} n'a PAS été téléporté car aucun point de téléportation sûr " -"n'a été trouvé." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPSpawnCommand.java:104 -msgid "" -"{ci}Use {cc}/uh tpspawn {0} force{ci} to teleport the player regardless this " -"point." -msgstr "" -"{ci}Utilisez {cc}/uh tpspawn {0} force{ci} pour le téléporter malgré tout." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTPSpawnCommand.java:148 -msgid "" -"{cc}/uh tpspawn <player> [force] {ci}: safely teleports back a player to his " -"spawn location." -msgstr "" -"{cc}/uh tpspawn <joueur> [force] {ci}: téléporte un joueur à son point de " -"démarrage attribué en toute sécurité." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHResurrectCommand.java:78 -msgid "{ce}This player is not playing or dead!" -msgstr "{ce}Ce joueur ne joue pas ou n'est pas mort !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHResurrectCommand.java:82 -msgid "" -"{cs}Because {0} is offline, he will be resurrected when he logins. If he " -"was, he is no longer banned." -msgstr "" -"{cs}Comme {0} est déconnecté, il sera ressuscité dés qu'il se connectera. " -"S'il l'était, il n'est plus banni." - -#. Trying to resurrect an alive player -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHResurrectCommand.java:90 -msgid "{ce}{0} is not dead!" -msgstr "{ce}{0} n'est pas mort !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHResurrectCommand.java:127 -msgid "{cc}/uh resurrect <player> {ci}: resurrects a player." -msgstr "{cc}/uh resurrect <joueur> {ci}: fait revivre un joueur." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamJoinCommand.java:117 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamRemoveCommand.java:76 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/ToggleChatCommand.java:100 -msgid "{ce}This team does not exists." -msgstr "{ce}Cette équipe n'existe pas." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamJoinCommand.java:131 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:100 -msgid "{ce}Unable to retrieve the player {0}." -msgstr "{ce]Impossible de trouver le joueur {0}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamJoinCommand.java:134 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:103 -msgid "" -"{ce}In offline mode, you cannot add players if they never came to this " -"server." -msgstr "" -"{ce}En mode hors-ligne, vous ne pouvez pas ajouter de joueurs qui ne se sont " -"jamais connectés." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamJoinCommand.java:143 -msgid "{cs}The player {0} was successfully added to the team {1}" -msgstr "{cs}Le joueur {0} a été ajouté à l'équipe {1}{cs} avec succès." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamJoinCommand.java:190 -msgid "" -"{cc}/uh team join <player> <teamName ...> {ci}: adds a player inside the " -"given team. The name of the team is it color, or the explicit name given." -msgstr "" -"{cc}/uh team join <joueur> <nomÉquipe ...> {ci}: ajoute un joueur dans " -"l'équipe donnée. Le nom de l'équipe est sa couleur, ou le nom explicite " -"donné." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamResetCommand.java:67 -msgid "{cs}All teams where removed." -msgstr "{cs}Toutes les équipes ont été supprimées." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamResetCommand.java:93 -msgid "{cc}/uh team reset {ci}: removes all teams." -msgstr "{cc}/uh team reset {ci}: supprime toutes les équipes." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamAddCommand.java:79 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamAddCommand.java:105 -msgid "" -"{ce}Unable to add the team, check the color name. Tip: use Tab to " -"autocomplete." -msgstr "" -"{ce}Impossible d'ajouter l'équipe ; vérifiez le nom de la couleur. Conseil : " -"utilisez l'autocomplétion." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamAddCommand.java:93 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamAddCommand.java:121 -msgid "{cs}Team {0}{cs} added." -msgstr "{cs}Équipe {0}{cs} ajoutée." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamAddCommand.java:163 -msgid "" -"{cc}/uh team add <color> [<name ...>] {ci}: adds a team with the provided " -"color." -msgstr "" -"{cc}/uh team add <couleur> [<nom ...>]{ci}: ajoute une équipe de la couleur " -"donnée." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamLeaveCommand.java:92 -msgid "{ce}The player {0} is disconnected and never logged in before!" -msgstr "" -"{ce}Le joueur {0} est déconnecté et ne s'est jamais connecté au serveur " -"auparavant !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamLeaveCommand.java:109 -msgid "{cs}The player {0} was successfully removed from his team." -msgstr "{cs}Le joueur {0} a été retiré de son équipe avec succès." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamLeaveCommand.java:143 -msgid "{cc}/uh team leave <player> {ci}: removes a player from his team." -msgstr "{cc}/uh team leave <joueur> {ci}: retire un joueur de son équipe." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamRemoveCommand.java:80 -msgid "{cs}Team {0} deleted." -msgstr "{cs}Équipe {0} supprimée." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamRemoveCommand.java:119 -msgid "{cc}/uh team remove <name ...> {ci}: removes a team" -msgstr "{cc}/uh team remove <nom ...> {ci}: supprime une équipe." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamListCommand.java:70 -msgid "{ce}There isn't any team to show." -msgstr "{ce}Il n'y a pas d'équipe à lister." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamListCommand.java:76 -#, java-format -msgid "{0} ({1} player)" -msgid_plural "{0} ({1} players)" -msgstr[0] "{0} ({1} joueur)" -msgstr[1] "{0} ({1} joueurs)" - -#. Player name after the online status dot in /uh teams list -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamListCommand.java:92 -#, java-format -msgctxt "teams_list" -msgid "{0}" -msgstr "{0}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamListCommand.java:120 -msgid "{cc}/uh team list {ci}: lists the teams and their players." -msgstr "{cc}/uh team list {ci}: liste toutes les équipes et leurs membres." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerCommand.java:74 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerResetCommand.java:77 -msgid "{ce}Either this team does not exists, or you are not in a team." -msgstr "{ce}Cette équipe n'existe pas, ou vous n'êtes pas dans une équipe." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerCommand.java:78 -msgid "{ce}You must run this command with a banner in your main hand." -msgstr "" -"{ce}Vous devez avoir une bannière dans votre main principale pour lancer " -"cette commande." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerCommand.java:83 -msgid "{cs}The banner of the team {0}{cs} was successfully updated." -msgstr "{cs}La bannière de l'équipe {0}{cs} a été mise à jour avec succès." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerCommand.java:109 -msgid "" -"{cc}/uh team banner [team name ...] {ci}: updates the team's banner using " -"the banner in the sender hand. If the team name is not provided, uses the " -"sender's team." -msgstr "" -"{cc}/uh team banner [nom de l'équipe ...] {ci}: change la bannière de " -"l'équipe en utilisant la bannière dans la main de l'exécuteur. Si le nom de " -"l'équipe n'est pas spécifié, celle de l'exécuteur est utilisée." - -#. Error message of /uh team bannerreset from the console without name -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerResetCommand.java:71 -msgid "{ce}From the console, you must provide a team name." -msgstr "{ce}Depuis la console, vous devez préciser le nom d'une équipe." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerResetCommand.java:82 -msgid "" -"{cs}The banner of the team {0}{cs} was successfully reset to the default one." -msgstr "{cs}La bannière de l'équipe {0}{cs} a été réinitialisée avec succès." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamBannerResetCommand.java:108 -msgid "" -"{cc}/uh team bannerreset [team name ...] {ci}: resets the banner of the team " -"to the default. If the team name is not provided, uses the sender's team." -msgstr "" -"{cc}/uh team bannerreset [nom de l'équipe ...] {ci}: réinitialise la " -"bannière de l'équipe à celle générée par défaut. Si le nom de l'équipe n'est " -"pas spécifié, celle de l'exécuteur est utilisée." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamGUICommand.java:80 -msgid "{cc}/uh team gui {ci}: opens a GUI to join and manage the teams." -msgstr "" -"{cc}/uh team gui {ci}: ouvre une interface graphique pour gérer et rejoindre " -"les équipes." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamSpyCommand.java:70 -msgid "{ce}Cannot toggle the spy mode of {0} because he/she is offline." -msgstr "" -"{ce}Impossible d'inverser le mode d'espoinnage de {0} car il (ou elle) n'est " -"pas connecté(e)." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamSpyCommand.java:95 -msgid "{cs}Spy mode {darkred}disabled{cs} for {0}." -msgstr "{cs}Espoinnage {darkred}désactivé{cs} pour {0}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamSpyCommand.java:100 -msgid "{cs}Spy mode {darkgreen}enabled{cs} for {0}." -msgstr "{cs}Espionnage {darkgreen}activé{cs} pour {0}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/team/UHTeamSpyCommand.java:123 -msgid "" -"{cc}/uh team spy [player] {ci}: allows yourself (or the target player) to " -"receive all the team chats (read-only). Execute again to stop." -msgstr "" -"{cc}/uh team spy [joueur] {ci}: permet de recevoir (soit-même ou le joueur " -"ciblé) tous les chats d'équipe (en lecture seule). Exécutez une autre fois " -"pour interrompre." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTimersCommand.java:92 -msgid "{aqua}------ Timers commands ------" -msgstr "{aqua}------ Commandes liées aux comptes à rebours ------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTimersCommand.java:98 -msgid "{cc}/uh timers {ci}: manages the timers. See /uh timers for details." -msgstr "" -"{cc}/uh timers {ci}: gère les comptes à rebours. Consultez /uh timers pour " -"plus de détails." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTeamCommand.java:110 -msgid "{aqua}------ Team commands ------" -msgstr "{aqua}------ Commandes liées aux équipes ------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTeamCommand.java:111 -msgid "" -"{cc}/join [player] <team ...> {ci}: adds “player” (or the sender) inside the " -"given team. Without arguments, displays the chat-based team selector." -msgstr "" -"{cc}/join [joueur] <équipe ...> {ci}: ajoute “joueur” (ou l'envoyeur) dans " -"l'équipe donnée. Sans argument, affiche le sélecteur d'équipe." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTeamCommand.java:112 -msgid "" -"{cc}/leave [player] {ci}: removes “player” (or the sender) from his team." -msgstr "" -"{cc}/leave [joueur] {ci}: retire “joueur” (ou l'envoyeur) de son équipe." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHTeamCommand.java:119 -msgid "{cc}/uh team {ci}: manages the teams. Execute /uh team for details." -msgstr "" -"{cc}/uh team {ci}: gère les équipes. Exécutez /uh team pour plus de détails." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHBorderCommand.java:83 -msgid "{aqua}------ Border commands ------" -msgstr "{aqua}------ Commandes liées aux bordures ------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHBorderCommand.java:89 -msgid "{cc}/uh border {ci}: manages borders. Execute /uh border for details." -msgstr "" -"{cc}/uh border {ci}: gère la bordure. Exécutez /uh border pour plus de " -"détails." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealAllCommand.java:94 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealCommand.java:107 -msgid "{ce}Hey, this is not a number of half-hearts. It's a text. Pfff." -msgstr "" -"{ce}Hey, ce n'est pas un nombre de demi-coeurs... C'est un texte... Pfff." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealAllCommand.java:101 -msgid "{ce}Serial killer!" -msgstr "{ce}S'pèce de tueur en série !" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealAllCommand.java:112 -msgid "{ce}The health of {0} was not updated to avoid a kill." -msgstr "{ce}La vie de {0} n'a pas été changée, pour ne pas le/la tuer." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealAllCommand.java:140 -msgid "" -"{cc}/uh healall [half-hearts=20|±diff] {ci}: heals all players instead of " -"only one." -msgstr "" -"{cc}/uh healall [demi-coeurs=20|±diff] {ci}: change la vie de tous les " -"joueurs, et non d'un seul." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHShiftCommand.java:67 -msgid "the console" -msgstr "la console" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHShiftCommand.java:72 -msgid "" -"{ce}You can't shift the current episode because the game is not started." -msgstr "" -"{ce}Vous ne pouvez pas passer l'épisode actuel car le jeu n'a pas démarré." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHShiftCommand.java:91 -msgid "{cc}/uh shift {ci}: shifts an episode." -msgstr "{cc}/uh shift {ci}: passe un épisode." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHGenerateWallsCommand.java:75 -msgid "{cst}Generating the walls..." -msgstr "{cst}Génération des murs en cours..." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHGenerateWallsCommand.java:90 -msgid "{ci}From the console, generating the walls of the default world, {0}" -msgstr "{ci}Depuis la console, génération du mur du monde par défaut, {0}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHGenerateWallsCommand.java:100 -msgid "" -"{ce}Unable to generate the wall: see logs for details. The blocks set in the " -"config are probably invalid." -msgstr "" -"{ce}Impossible de générer le mur: voir logs pour plus de détails. Les blocs " -"configurés sont probablement invalide." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHGenerateWallsCommand.java:106 -msgid "{ce}An error occurred, see console for details." -msgstr "" -"{ce}Une erreur s'est produite, consultez la console pour plus de détails." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHGenerateWallsCommand.java:111 -msgid "{cst}Generation done." -msgstr "{cst}Génération terminée." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHGenerateWallsCommand.java:137 -msgid "" -"{cc}/uh generatewalls {ci}: generates the walls according to the " -"configuration." -msgstr "{cc}/uh generatewalls {ci}: génère les murs suivant la configuration." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersStopCommand.java:72 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersStartCommand.java:72 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersHideCommand.java:72 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersDisplayCommand.java:72 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersRemoveCommand.java:72 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersResumeCommand.java:72 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersSetCommand.java:81 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersPauseCommand.java:72 -msgid "{ce}This timer is not registered." -msgstr "{ce}Ce compteur n'est pas enregistré." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersStopCommand.java:77 -msgid "{cs}The timer {0}{cs} was stopped." -msgstr "{cs}Le compteur {0}{cs} a été arrêté." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersStopCommand.java:102 -msgid "" -"{cc}/uh timers stop <title ...> {ci}: stops a timer. The timer will be " -"removed from the scoreboard." -msgstr "" -"{cc}/uh timers stop <title ...> {ci}: force l'arrêt d'un compteur. Il est " -"retiré du scoraboard." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersStartCommand.java:82 -msgid "{cs}The timer {0}{cs} was started." -msgstr "{cs}Le compteur {0}{cs} a démarré." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersStartCommand.java:107 -msgid "{cc}/uh timers start <title ...> {ci}: starts a timer." -msgstr "{cc}/uh timers start <titre ...> {ci}: démarre un compte à rebours." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersHideCommand.java:76 -msgid "{cs}The timer {0}{cs} is now hidden." -msgstr "{cs}Le compteur {0}{cs} est désormais masqué." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersHideCommand.java:101 -msgid "" -"{cc}/uh timers hide <title ...> {ci}: removes a timer from the scoreboard. " -"Don't stops the timer." -msgstr "" -"{cc}/uh timers hide <titre ...> {ci}: retire un compteur du scoreboard. " -"N'arrête pas le compteur." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersListCommand.java:65 -msgid "{ci}{0} timer is registered." -msgid_plural "{ci}{0} timers are registered." -msgstr[0] "{ci}Il y a {0} compteur enregistré." -msgstr[1] "{ci}Il y a {0} compteurs enregistrés." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersListCommand.java:73 -msgid "{yellow} • {{ci}{0}{ci} - total {1} second - {2}" -msgid_plural "{yellow} • {{ci}{0}{ci} - total {1} seconds - {2}" -msgstr[0] "{yellow} • {ci}{0}{ci} - {1} seconde au total - {2}" -msgstr[1] "{yellow} • {ci}{0}{ci} - {1} secondes au total - {2}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersListCommand.java:82 -msgid "{green} • {ci}{0}{ci} - total {1} second - {2}" -msgid_plural "{green} • {ci}{0}{ci} - total {1} seconds - {2}" -msgstr[0] "{green} • {ci}{0}{ci} - {1} seconde au total - {2}" -msgstr[1] "{green} • {ci}{0}{ci} - {1} secondes au total - {2}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersListCommand.java:92 -msgid "{red} • {ci}{0}{ci} - total {1} second" -msgid_plural "{red} • {ci}{0}{ci} - total {1} seconds" -msgstr[0] "{red} • {ci}{0}{ci} - {1} seconde au total" -msgstr[1] "{red} • {ci}{0}{ci} - {1} secondes au total" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersListCommand.java:123 -msgid "{cc}/uh timers list {ci}: lists the registered timers." -msgstr "{cc}/uh timers list {ci}: liste les compteurs enregistrés." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersDisplayCommand.java:76 -msgid "{cs}The timer {0}{cs} is now displayed." -msgstr "{cs}Le compteur {0}{cs} est désormais affiché." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersDisplayCommand.java:101 -msgid "" -"{cc}/uh timers display <title ...> {ci}: displays a timer in the scoreboard. " -"Automatic when a timer is started." -msgstr "" -"{cc}/uh timers display <titre ...> {ci}: affiche un compteur dans le " -"scoreboard. Automatique au démarrage du compteur." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersRemoveCommand.java:79 -msgid "{cs}The timer {0}{cs} has been deleted." -msgstr "{cs}Le compteur {0}{cs} a été supprimé." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersRemoveCommand.java:104 -msgid "{cc}/uh timers remove <title ...> {ci}: deletes a timer." -msgstr "{cc}/uh timers remove <title ...> {ci}: supprime un compteur." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersResumeCommand.java:77 -msgid "{cs}The timer {0}{cs} was resumed." -msgstr "{cs}Le compteur {0}{cs} n'est plus en pause." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersResumeCommand.java:102 -msgid "{cc}/uh timers resume <title ...> {ci}: resumes a timer." -msgstr "" -"{cc}/uh timers resume <title ...> {ci}: redémarre un compteur après une " -"pause." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersSetCommand.java:86 -msgid "{cs}The duration of the timer {0}{cs} is now {1}." -msgstr "{cs}La durée du compteur {0}{cs} est désormais {1}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersSetCommand.java:91 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersAddCommand.java:91 -msgid "" -"{ce}The duration' syntax is invalid; accepted formats are mm, mm:ss or hh:mm:" -"ss." -msgstr "" -"{ce}La syntaxe de la durée entrée est invalide, les formats acceptés sont " -"mm, mm:ss ou hh:mm:ss." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersSetCommand.java:124 -msgid "" -"{cc}/uh timers set <duration> <title ...> {ci}: sets the duration of a timer." -msgstr "" -"{cc}/uh timers set <durée> <titre ...> {ci}: modifie la durée d'un compte à " -"rebours." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersAddCommand.java:78 -msgid "{ce}A timer called {0}{ce} already exists; please choose another name." -msgstr "{ce}Un compteur nommé {0}{ce} existe déjà, choisissez un autre nom." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersAddCommand.java:86 -msgid "{cs}The timer {0}{cs} (duration {1}) has been registered." -msgstr "{cs}Le compteur {0}{cs}, de durée {1}, a bien été enregistré." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersAddCommand.java:111 -msgid "{cc}/uh timers add <duration> <title ...> {ci}: adds a timer." -msgstr "" -"{cc}/uh timers add <durée> <titre ...> {ci}: ajoute un compte à rebours." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersPauseCommand.java:77 -msgid "{cs}The timer {0}{cs} is now paused." -msgstr "{cs}Le compteur {0}{cs} est désormais en pause." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/timers/UHTimersPauseCommand.java:102 -msgid "{cc}/uh timers pause <title ...> {ci}: pauses a timer." -msgstr "{cc}/uh timers pause <titre ...> {ci}: met en pause un comparateur." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHLoadPlayersCommand.java:61 -msgid "{ce}You cannot load unknown players in offline mode, sorry." -msgstr "" -"{ce}Vous ne pouvez pas charger des joueurs inconnus en mode hors-ligne, " -"désolé." - -#. Error returned if one calls /uh loadplayers without arguments. -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHLoadPlayersCommand.java:68 -msgid "{ce}You need to provide at least one player name." -msgstr "{ce}Vous devez spécifier au moins un nom de joueur." - -#. Message displayed when the /uh loadplayers command is used, as the execution may take some time. -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHLoadPlayersCommand.java:73 -msgid "{cst}Loading players..." -msgstr "{cst}Chargement des joueurs..." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHLoadPlayersCommand.java:80 -msgid "{cs}Loaded {0} player successfully." -msgid_plural "{cs}Loaded {0} players successfully." -msgstr[0] "{cs}{0} joueur a été chargé." -msgstr[1] "{cs}{0} joueurs ont été chargés." - -#. Message sent if some players cannot be loaded while /uh loadplayers is used. 0 = amount of players missing; 1 = list of nicknames (format "nick1, nick2, nick3"). -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHLoadPlayersCommand.java:88 -msgid "{ce}{0} player is missing: {1}." -msgid_plural "{ce}{0} players are missing: {1}." -msgstr[0] "{ce}Il manque {0} joueur : {1}." -msgstr[1] "{ce}Il manque {0} joueurs : {1}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHLoadPlayersCommand.java:108 -msgid "" -"{cc}/uh loadplayers <pseudo> [pseudo] ... {ci}: loads the given players in " -"the server so they can be added to teams even if they never logged in." -msgstr "" -"{cc}/uh loadplayers <pseudo> [pseudo] ... {ci}: charges les joueurs " -"spécifiés afin qu'il puissent être ajoutés dans une équipe même s'ils ne se " -"sont jamais connectés au serveur." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:92 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:116 -msgid "{cst}You where frozen by {0}." -msgstr "{cst}Vous avez été immobilisé(e) par {0}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:96 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:121 -msgid "{cst}You where unfrozen by {0}." -msgstr "{cst}Vous avez été libéré(e) par {0}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:117 -msgid "{cs}{0} is now frozen." -msgstr "{cs}{0} est désormais immobilisé(e)." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:122 -msgid "{cs}{0} is now unfrozen." -msgstr "{cs}{0} est désormais libéré(e)." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:137 -msgid "{darkaqua}The entire game is now frozen." -msgstr "{darkaqua}Le jeu est désormais en pause." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:141 -msgid "{darkaqua}The game is now unfrozen." -msgstr "{darkaqua}Le jeu n'est plus en pause." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:181 -msgid "{aqua}------ Freeze commands ------" -msgstr "{aqua}------ Commandes liées à l'immobilisation ------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:182 -msgid "" -"{cc}/uh freeze on [player]{ci}: freezes a player, or the sender without a " -"specified player." -msgstr "" -"{cc}/uh freeze on [joueur] {ci}: immobilise un joueur, ou l'exécuteur sans " -"joueur spécifié." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:183 -msgid "" -"{cc}/uh freeze off [player]{ci}: unfreezes a player (or the sender), even if " -"the entire game is frozen." -msgstr "" -"{cc}/uh freeze off [player] {ci}: libère un joueur (ou l'envoyeur), même si " -"le jeu est en pause." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:184 -msgid "{cc}/uh freeze all{ci}: freezes the entire game (players, mobs, timer)." -msgstr "" -"{cc}/uh freeze all {ci}: met le jeu en pause (immobilise les joueurs, mobs, " -"et le compteur)." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:185 -msgid "" -"{cc}/uh freeze none{ci}: unfreezes the entire game. You NEED to execute this " -"in order to relaunch the timer." -msgstr "" -"{cc}/uh freeze none {ci}: relance le jeu. Vous DEVEZ exécuter ceci pour " -"relancer le compteur." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFreezeCommand.java:192 -msgid "" -"{cc}/uh freeze {ci}: (un)freezes the entire game, or a player. See /uh " -"freeze for details." -msgstr "" -"{cc}/uh freeze {ci}: (dés)immobilise l'ensemble du jeu, ou un joueur. " -"Consultez /uh freeze pour plus de détails." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealCommand.java:73 -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedCommand.java:72 -msgid "{ce}This player is offline." -msgstr "{ce}Ce joueur n'est pas connecté." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealCommand.java:115 -msgid "{ce}You can't kill a player with this command, to avoid typo fails." -msgstr "" -"{ce}Vous ne pouvez pas tuer un joueur avec cette commande, pour éviter toute " -"faute de frappe." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHHealCommand.java:143 -msgid "" -"{cc}/uh heal <player> [half-hearts=20|±diff] {ci}: heals a player to the " -"number of half-hearts provided (default 20)." -msgstr "" -"{cc}/uh heal <joueur> [demi-coeurs=20|±diff] {ci}: change la vie d'un joueur " -"avec le nombre de demi-coeurs donné (par défaut, 20)." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHFeedCommand.java:125 -msgid "" -"{cc}/uh feed <player> [foodPoints=20] [saturation=max] {ci}: feeds a player." -msgstr "" -"{cc}/uh feed <joueur> [faim=20] [saturation=max] {ci}: nourrit un joueur." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHKillCommand.java:77 -msgid "{ce}This player was never seen on this server." -msgstr "{ce}Cette personne n'a jamais été vue sur le serveur." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHKillCommand.java:92 -msgid "{cs}The player {0} is now marked as dead." -msgstr "{cs}Le joueur {0} est désormais marqué comme mort." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHKillCommand.java:96 -msgid "{ce}{0} is not an alive player." -msgstr "{ce}{0} n'est pas un joueur vivant." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHKillCommand.java:127 -msgid "" -"{cc}/uh kill <player> {ci}: mark a player as dead, even if he is offline." -msgstr "" -"{cc}/uh kill <joueur> {ci}: marque un joueur comme mort, même s'il est hors-" -"ligne." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHStartCommand.java:99 -msgid "" -"{ce}The game is already started! Reload or restart the server to restart the " -"game." -msgstr "" -"{ce}Le jeu est déjà démarré ! Rechargez ou redémarrez le serveur pour " -"redémarrer." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHStartCommand.java:133 -msgid "{aqua}------ Beginning of the game ------" -msgstr "{aqua}------ Démarrage du jeu ------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHStartCommand.java:134 -msgid "{cc}/uh start {ci}: starts the game. Period." -msgstr "{cc}/uh start {ci}: démarre le jeu, tout simplement." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHStartCommand.java:135 -msgid "{aqua}Startup options" -msgstr "{aqua}Options de démarrage" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHStartCommand.java:136 -msgid "" -"{ci}You can add some tags to change the way the game is started, just append " -"them to the command with spaces." -msgstr "" -"{ci}Vous pouvez ajouter des options pour changer la manière dont le jeu est " -"démarré. Pour ce faire, ajoutez les tags suivant après la commande (séparés " -"par des espaces)." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHStartCommand.java:137 -msgid "" -"{cc}slow:true {ci}: launches the game slowly, in two steps (teleportation " -"then beginning of the game), for smaller servers." -msgstr "" -"{cc}slow:true {ci}: lance le jeu doucement, en deux étapes (téléportation " -"puis commencement), pour les plus petits serveurs." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHStartCommand.java:138 -msgid "" -"{cc}ignoreTeams:true {ci}: even with teams, teleports the players like in a " -"solo game (only one player per spawn point, not a spawn point per team)." -msgstr "" -"{cc}ignoreTeams:true {ci}: même avec des équipes, téléporte les joueurs " -"comme pour un jeu solo (uniquement un joueur par point de démarrage, et non " -"un point par équipe)." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHStartCommand.java:145 -msgid "" -"{cc}/uh start {ci}: launches the game. See /uh start help for options (slow " -"and ignoreTeams)." -msgstr "" -"{cc}/uh start {ci}: lance le jeu. Consultez /uh start help pour les options " -"de démarrage (lent, en ignorant les équipes)." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:109 -msgid "{cs}The player {0} is now a spectator." -msgstr "{cs}Le joueur {0} est désormais un spectateur." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:129 -msgid "{ce}The player {0} was not found." -msgstr "{ce}Le joueur {0} n'a pas été trouvé." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:134 -msgid "{cs}The player {0} is now a player." -msgstr "{cs}Le joueur {0} est désormais un joueur." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:144 -msgid "{ce}There isn't any spectator to list." -msgstr "{ce}Il n'y a pas de spectateur à lister." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:148 -msgid "{ci}{0} registered spectator." -msgid_plural "{ci}{0} registered spectators." -msgstr[0] "{ci}{0} spectateur enregistré." -msgstr[1] "{ci}{0} spectateurs enregistrés." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:149 -msgid "{ci}This count includes only the initial spectators." -msgstr "{ci}Ce compte inclue uniquement les spectateurs initiaux." - -#. A list item in the startup spectators list -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:154 -msgctxt "startup_specs" -msgid "{lightpurple} - {0}" -msgstr "{lightpurple} - {0}" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:191 -msgid "{aqua}------ Startup spectators commands ------" -msgstr "{aqua}------ Commandes liées aux spectateurs initiaux ------" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:193 -msgid "{cc}/uh spec add <player>{ci}: adds a startup spectator." -msgstr "{cc}/uh spec add <joueur> {ci}: ajoute un spectateur initial." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:194 -msgid "{cc}/uh spec remove <player>{ci}: removes a startup spectator." -msgstr "{cc}/uh spec remove <joueur> {ci}: supprime un spectateur initial." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:195 -msgid "{cc}/uh spec list{ci}: lists the startup spectators." -msgstr "{cc}/uh spec list {ci}: liste les spectateurs initiaux." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHSpectatorsCommand.java:203 -msgid "" -"{cc}/uh spec {ci}: manages the spectators. Execute /uh spec for details." -msgstr "" -"{cc}/uh spec {ci}: gère les spectateurs. Exécutez /uh spec pour plus de " -"détails." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHRulesCommand.java:63 -msgid "{ce}No rules are set in the config file." -msgstr "{ce}Aucune règle n'est enregistrée dans le fichier de configuration." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHRulesCommand.java:75 -msgid "{cs}Rules sent to {0}." -msgstr "{cs}Les règles ont été envoyées à {0}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHRulesCommand.java:79 -msgid "{ce}Cannot display the rules to {0} because he (or she) is offline." -msgstr "" -"{ce}Impossible d'afficher les règles à {0} car il ou elle est hors-ligne." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/uh/UHRulesCommand.java:103 -msgid "" -"{cc}/uh rules [player] {ci}: sends the server rules to the server or the " -"given player." -msgstr "" -"{cc}/uh rules [joueur] {ci}: envoie les règles du jeu au serveur ou au " -"joueur spécifié." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/ToggleChatCommand.java:77 -msgid "{cs}You are now chatting with your team only." -msgstr "{cs}Vous discutez désormais avec votre équipe." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/ToggleChatCommand.java:81 -msgid "{cs}You are now chatting with everyone." -msgstr "{cs}Vous discutez désormais avec tous le monde." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/commands/ToggleChatCommand.java:95 -msgid "{cs}You are now chatting with the team {0}{cs}." -msgstr "{cs}Vous discutez désormais avec l'équipe {0}{cs}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/AbstractCommandExecutor.java:209 -msgid "" -"{ci}Legend: {cc}/uh command <required> [optional=default] <spaces allowed ..." -">{ci}." -msgstr "" -"{ci}Légende: {cc}/uh command <requis> [optionnel=valeur par défaut] <espaces " -"autorisées ...>{ci}." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/AbstractCommandExecutor.java:225 -msgid "{ce}{bold}You cannot execute this command this way." -msgstr "{ce}{bold}Vous ne pouvez exécuter cette commande ainsi." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/AbstractCommandExecutor.java:226 -msgid "{ce}The help is displayed above." -msgstr "{ce}L'aide est rappelée ci-dessus." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/AbstractCommandExecutor.java:257 -msgid "{ce}You are not allowed to execute this command." -msgstr "{ce}Vous n'avez pas le droit d'exécuter cette commande." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/commands/core/AbstractCommandExecutor.java:261 -msgid "{ce}This can only be executed as a player." -msgstr "{ce}Vous ne pouvez exécuter cela qu'en étant un joueur." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/task/BorderWarningTask.java:65 -msgid "{ce}You are currently out of the future border (diameter of {0} block)." -msgid_plural "" -"{ce}You are currently out of the future border (diameter of {0} blocks)." -msgstr[0] "{ce}Vous êtes hors de la future bordure de {0} bloc de diamètre." -msgstr[1] "{ce}Vous êtes hors de la future bordure de {0} blocs de diamètre." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/task/BorderWarningTask.java:69 -msgid "{ce}You are currently out of the future border of {0}×{0} blocks." -msgstr "{ce}Vous êtes hors de la future bordure de {0}×{0} blocs." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/task/BorderWarningTask.java:72 -msgid "{ci}You have {0} block to go before being inside." -msgid_plural "{ci}You have {0} blocks to go before being inside." -msgstr[0] "{ci}Il vous reste {0} blocs à parcourir avant d'y être." -msgstr[1] "{ci}Il vous reste {0} bloc à parcourir avant d'y être." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:334 -msgid "{ce}Unable to start the game: not enough teleportation spots." -msgstr "{ce}Impossible de démarrer : pas assez de points de téléportation." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:335 -msgid "" -"{ci}You can use {cc}/uh spawns generate <random|circular|grid>{ci} to " -"generate the missing spawns automatically." -msgstr "" -"{ci}Vous pouvez utiliser {cc}/uh spawns generate <random|circular|grid>{ci} " -"pour automatiquement générer les points de téléportation manquant." - -#. In the sentence: "Or click here to generate the spawns randomly." -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:338 -msgid "Or" -msgstr "Ou" - -#. In the sentence: "Or click here to generate the spawns randomly." -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:341 -msgid "click here" -msgstr "cliquez ici" - -#. In the sentence: "Or click here to generate the spawns randomly." -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:347 -msgid "to generate the spawns randomly." -msgstr "afin de générer les points de démarrage aléatoirement." - -#. A simple information, because this start is slower (yeah, Captain Obvious here) -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:479 -msgid "{lightpurple}Teleportation in progress... Please wait." -msgstr "{lightpurple}Téléportation en cours... Merci de patienter." - -#. Displayed in the action bar while the slow teleportation occurs. -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:494 -msgid "{lightpurple}Teleporting... {gray}({0}/{1})" -msgstr "{lightpurple}Téléportation... {gray}({0}/{1})" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:514 -msgid "{gray}Player {0}{gray} teleported." -msgstr "{gray}Joueur {0}{gray} téléporté." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:573 -msgid "{cs}All teams are teleported." -msgstr "{cs}Toutes les équipes ont été téléportées." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:574 -msgid "{gray}Use {cc}/uh start{gray} or click here to start the game." -msgstr "" -"{gray}Utilisez {cc}/uh start{gray} ou cliquez ici pour démarrer le jeu." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:575 -msgid "Click here to start the game" -msgstr "Cliquez ici pour démarrer la partie" - -#. Displayed in the action bar when the slow teleportation is finished but the game not started. -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:584 -msgid "{lightpurple}Teleportation complete. {gray}The game will start soon..." -msgstr "{lightpurple}Téléportation terminée. {gray}Ça ne devrait pas tarder..." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:615 -msgid "{ce}Please execute {cc}/uh start slow:true{ce} before." -msgstr "{ce}Veuillez exécuter {cc}/uh start slow:true{ce} avant." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:621 -msgid "{ce}Please wait while the players are teleported." -msgstr "{ce}Veuillez patienter, les équipes sont en train d'être téléportées." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:717 -msgid "" -"{red}{bold}Warning!{white} The grace period ended, you are now vulnerable." -msgstr "" -"{red}{bold}Attention !{white} La période de grâce est terminée ; vous êtes " -"désormais vulnérable." - -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:736 -msgid "{red}{bold}Warning!{white} PvP is now enabled." -msgstr "{red}{bold}Attention !{white} Le PvP est désormais actif." - -#. Spectators list item if the nick cannot be found -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:1073 -#, java-format -msgid "Unknown player with UUID {0}" -msgstr "Joueur inconnu ayant l'UUID {0}" - -#. The "and" in the winners players list (like "player1, player2 and player3"). -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:1219 -msgctxt "winners_list" -msgid "and" -msgstr "et" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:1231 -msgid "" -"{darkgreen}{obfuscated}--{green} Congratulations to {0} (team {1}{green}) " -"for their victory! {darkgreen}{obfuscated}--" -msgstr "" -"{darkgreen}{obfuscated}--{green} Félicitations à {0} (équipe {1}{green}) " -"pour leur victoire ! {darkgreen}{obfuscated}--" - -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:1235 -msgid "" -"{darkgreen}{obfuscated}--{green} Congratulations to {0} for his victory! " -"{darkgreen}{obfuscated}--" -msgstr "" -"{darkgreen}{obfuscated}--{green} Félicitation à {0} pour sa victoire ! " -"{darkgreen}{obfuscated}--" - -#. The main title of the /title displayed when a team wins the game. {0} becomes the team display name (with colors). -#. The main title of the /title displayed when a player wins the game (in solo). {0} becomes the player display name (with colors). -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:1247 -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:1254 -msgid "{darkgreen}{0}" -msgstr "{darkgreen}{0}" - -#. The subtitle of the /title displayed when a team wins the game. {0} becomes the team display name (with colors). -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:1249 -msgid "{green}This team wins the game!" -msgstr "{green}Cette équipe remporte la victoire !" - -#. The subtitle of the /title displayed when a player wins the game (in solo). {0} becomes the player display name (with colors). -#: src/main/java/eu/carrade/amaury/UHCReloaded/game/UHGameManager.java:1256 -msgid "{green}wins the game!" -msgstr "{green}remporte la partie !" - -#~ msgid "" -#~ "{ce}Unable to add the player {0} to the team {1}. This player is unknown " -#~ "in the server." -#~ msgstr "" -#~ "{ce}Impossible d'ajouter le joueur {0} dans l'équipe {1}. Ce joueur n'est " -#~ "jamais venu sur ce serveur." - -#~ msgid "Spawn point {0},{1} added from the config file" -#~ msgstr "" -#~ "Point de démarrage {0},{1} ajouté depuis le fichier de configuration." - -#~ msgid "Invalid spawn point set in config: {0}" -#~ msgstr "Point de démarrage invalide dans la configuration : {0}" - -#~ msgid "Invalid team set in config: {0}" -#~ msgstr "Équipe invalide dans la configuration : {0}" - -#~ msgid "Team {0} ({1}) added from the config file" -#~ msgstr "Équipe {0} ({1}) ajoutée depuis le fichier de configuration." - -#~ msgid "Team {0} added from the config file" -#~ msgstr "Équipe {0} ajoutée depuis le fichier de configuration." diff --git a/src/main/resources/i18n/pt_BR.po b/src/main/resources/i18n/pt-BR.po similarity index 99% rename from src/main/resources/i18n/pt_BR.po rename to src/main/resources/i18n/pt-BR.po index 6ae3798..5ab5fe2 100644 --- a/src/main/resources/i18n/pt_BR.po +++ b/src/main/resources/i18n/pt-BR.po @@ -713,13 +713,13 @@ msgstr "{gray}{italic}Para a bússola é necessária carne podre." #. Error message if a player tries to use his pointing compass without a #. player nearby. #: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:335 -msgid "{gray}{italic}Only silence answers your request." -msgstr "{gray}{italic}Nenhum jogador encontrado nas proximidades." +msgid "Only silence answers your request." +msgstr "Nenhum jogador encontrado nas proximidades." #. Success message when a player uses his pointing compass. #: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:342 -msgid "{gray}The compass now points to the closest player." -msgstr "{gray}A bússola está apotando para o jogador mais próximo de você." +msgid "The compass now points to the closest player." +msgstr "A bússola está apotando para o jogador mais próximo de você." #. Dynmap marker label of a death point #: src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHDynmapIntegration.java:152 @@ -755,27 +755,8 @@ msgstr "Feita da cabeça de {0}" #. Item name of a golden head (from a player) #: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:393 -msgctxt "player_head" -msgid "{aqua}Golden head" -msgstr "{aqua}Maçã Dourada" - -#. Item name of an enchanted golden head (from a player) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:399 -msgctxt "player_head" -msgid "{lightpurple}Golden head" -msgstr "{lightpurple}Maçã Dourada" - -#. Item name of a golden head (from a monster) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:426 -msgctxt "monster_head" -msgid "{aqua}Golden head" -msgstr "{aqua}Maçã Dourada" - -#. Item name of an enchanted golden head (from a monster) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:432 -msgctxt "monster_head" -msgid "{lightpurple}Golden head" -msgstr "{lightpurple}Maçã Dourada" +msgid "Golden head" +msgstr "Maçã Dourada" #. Current episode in the sidebar #: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:141 diff --git a/src/main/resources/i18n/pt_PT.po b/src/main/resources/i18n/pt-PT.po similarity index 99% rename from src/main/resources/i18n/pt_PT.po rename to src/main/resources/i18n/pt-PT.po index 699ef0e..b814f50 100644 --- a/src/main/resources/i18n/pt_PT.po +++ b/src/main/resources/i18n/pt-PT.po @@ -708,13 +708,13 @@ msgstr "{gray}{italic}Precisas de Carne Podre para utilizares a Bussola." #. Error message if a player tries to use his pointing compass without a #. player nearby. #: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:335 -msgid "{gray}{italic}Only silence answers your request." -msgstr "{gray}{italic}Nao foram encontrados jogadores por perto." +msgid "Only silence answers your request." +msgstr "Nao foram encontrados jogadores por perto." #. Success message when a player uses his pointing compass. #: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:342 -msgid "{gray}The compass now points to the closest player." -msgstr "{gray}A Bussola aponta agora para o jogador mais proximo." +msgid "The compass now points to the closest player." +msgstr "A Bussola aponta agora para o jogador mais proximo." #. Dynmap marker label of a death point #: src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHDynmapIntegration.java:152 @@ -750,27 +750,8 @@ msgstr "Feita da cabeca de {0}" #. Item name of a golden head (from a player) #: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:393 -msgctxt "player_head" -msgid "{aqua}Golden head" -msgstr "{aqua}Maca Dourada" - -#. Item name of an enchanted golden head (from a player) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:399 -msgctxt "player_head" -msgid "{lightpurple}Golden head" -msgstr "{lightpurple}Maca Dourada" - -#. Item name of a golden head (from a monster) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:426 -msgctxt "monster_head" -msgid "{aqua}Golden head" -msgstr "{aqua}Maca Dourada" - -#. Item name of an enchanted golden head (from a monster) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:432 -msgctxt "monster_head" -msgid "{lightpurple}Golden head" -msgstr "{lightpurple}Maca Dourada" +msgid "Golden head" +msgstr "Maca Dourada" #. Current episode in the sidebar #: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:141 diff --git a/src/main/resources/i18n/zh_CN.po b/src/main/resources/i18n/zh-CN.po similarity index 98% rename from src/main/resources/i18n/zh_CN.po rename to src/main/resources/i18n/zh-CN.po index 6a9ba23..f81ce1c 100644 --- a/src/main/resources/i18n/zh_CN.po +++ b/src/main/resources/i18n/zh-CN.po @@ -684,13 +684,13 @@ msgstr "{gray}{italic}你没有腐肉." #. Error message if a player tries to use his pointing compass without a #. player nearby. #: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:335 -msgid "{gray}{italic}Only silence answers your request." -msgstr "{gray}{italic}指南针没找到任何特殊事物." +msgid "Only silence answers your request." +msgstr "指南针没找到任何特殊事物." #. Success message when a player uses his pointing compass. #: src/main/java/eu/carrade/amaury/UHCReloaded/listeners/GameplayListener.java:342 -msgid "{gray}The compass now points to the closest player." -msgstr "{gray}指南针正指向离你最近的玩家." +msgid "The compass now points to the closest player." +msgstr "指南针正指向离你最近的玩家." #. Dynmap marker label of a death point #: src/main/java/eu/carrade/amaury/UHCReloaded/integration/UHDynmapIntegration.java:152 @@ -726,27 +726,8 @@ msgstr "用玩家 {0} 掉落的头颅制作" #. Item name of a golden head (from a player) #: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:393 -msgctxt "player_head" -msgid "{aqua}Golden head" -msgstr "{aqua}金苹果(金头颅)" - -#. Item name of an enchanted golden head (from a player) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:399 -msgctxt "player_head" -msgid "{lightpurple}Golden head" -msgstr "{lightpurple}金苹果(金头颅)" - -#. Item name of a golden head (from a monster) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:426 -msgctxt "monster_head" -msgid "{aqua}Golden head" -msgstr "{aqua}金苹果(金头颅)" - -#. Item name of an enchanted golden head (from a monster) -#: src/main/java/eu/carrade/amaury/UHCReloaded/recipes/RecipesManager.java:432 -msgctxt "monster_head" -msgid "{lightpurple}Golden head" -msgstr "{lightpurple}金苹果(金头颅)" +msgid "Golden head" +msgstr "金苹果(金头颅)" #. Current episode in the sidebar #: src/main/java/eu/carrade/amaury/UHCReloaded/scoreboard/GameSidebar.java:141 diff --git a/src/main/resources/i18n/zh_CN.yml b/src/main/resources/i18n/zh-CN.yml similarity index 100% rename from src/main/resources/i18n/zh_CN.yml rename to src/main/resources/i18n/zh-CN.yml diff --git a/src/main/resources/modules/core-border.yml b/src/main/resources/modules/core-border.yml new file mode 100644 index 0000000..12516b2 --- /dev/null +++ b/src/main/resources/modules/core-border.yml @@ -0,0 +1,52 @@ +# The diameter of the map (not the radius!), in blocks +size: 2000 + +# "squared" or "circular". Affects the WorldBorder pre-configuration, and the +# wall generator used. +shape: "squared" + +# The world border manager. Can be: +# - "vanilla", to use the vanilla world border; or +# - "brettflan", to use the WorldBorder Bukkit plugin by Brettflan +# (http://dev.bukkit.org/bukkit-plugins/worldborder/). +# +# If the shape is "circular", fallbacks to "brettflan" as the vanilla world border don't +# support circular borders. And if the WorldBorder plugin is not installed, fallbacks to +# no border. +motor: "vanilla" + +# The amount of blocks a player may safely be outside the border before taking damage. +# Only for the vanilla world border. Ignored else. +damages-buffer: 5 + +# The amount of damage a player takes when outside the border plus the border buffer. +# The damages delt is calculated by multiplying this amount by the number of blocks behind the buffer. +# Only for the vanilla world border. Ignored else. +damages-amount: 0.2 + +# The warning distance that causes the screen to be tinted red when the player is within the specified +# number of blocks from the border. +# Only for the vanilla world border. Ignored else. +warning-distance: 5 + + +# Automatic and progressive border shrinking. +# Notice: if the border is circular, the WorldBorder Bukkit plugin by Brettflan (see above) +# is REQUIRED. Without, the border shrinking will not work. +shrinking: + enabled: false + + # Formats: "mm", "mm:ss" or "hh:mm:ss". + # With the default values, the border eats one block every 8 seconds on each side. + starts-after: "1:30:00" + shrinks-during: "2:00:00" + diameter-after-shrink: 200 + + +# Do you want the border current size to be displayed into the sidebar? +sidebar: + displayed: true + + # If true, displays the border diameter (ex. "2000 blocks wide"). Else, the min/max + # coordinates (ex. "-1000 +1000"). Ignored if the border is circular. + display-diameter: false diff --git a/src/main/resources/modules/core-game.yml b/src/main/resources/modules/core-game.yml new file mode 100644 index 0000000..7929592 --- /dev/null +++ b/src/main/resources/modules/core-game.yml @@ -0,0 +1,44 @@ +# The duration of the countdown before the game (seconds). +countdown: 7 + +# Displays a title when the game starts. +startup-title: true + +# If true, in solo games, all players will be colored randomly. +# Else everyone will be white. +random-colors-in-solo-games: true + +# If true, the initial teleportation progress will be broadcasted +# in the players' action bars, so they don't wait in the dark. +broadcast-progress: true + + +# The slow start allow the game to teleports the players slowly, for +# smaller servers, to avoid too many chunks loaded at once. You can +# enable the slow mode by using /uh start --slow, or using the GUI: +# as an operator, right-click the redstone comparator, then “Start the +# game”, then “Slow Start”. +slow: + # The delay, in seconds, between two teleportations in slow mode. + delay-between-teleportations: 3 + + +beginning: + # During this period, all damages will be disabled. + grace-period: "00:01:00" + + # Broadcast the end of the grace period + broadcast-grace-end: true + + # During this period, the PVP will be disabled. + peace-period: "00:15:00" + + # During this period, there will not be any hostile creature at the surface. + # They will still be there in caves. + surface-mobs-free-period: "00:20:00" + + +# Displays the players' count and teams' count in the sidebar. +sidebar: + players: true + teams: true diff --git a/src/main/resources/modules/core-spawns.yml b/src/main/resources/modules/core-spawns.yml new file mode 100644 index 0000000..a64b748 --- /dev/null +++ b/src/main/resources/modules/core-spawns.yml @@ -0,0 +1,15 @@ +# Don't generate the spawn points (with /uh spawns generate) above the water? +avoid-water: true + +# Use this to set the spawn points of the teams (or the players) +# You can also use the command `/uh spawns add` to add temporary spawn points, +# and `/uh spawns generate` to automatically generate them. (See `/uh spawns` for documentation.) +# (The spawn points added through `/uh spawns` are deleted when the server is stopped.) +# +# Format: +# - x,z +# - x,z +# - etc. + +spawn-points: + - diff --git a/src/main/resources/modules/core-spectators.yml b/src/main/resources/modules/core-spectators.yml new file mode 100644 index 0000000..8f4302b --- /dev/null +++ b/src/main/resources/modules/core-spectators.yml @@ -0,0 +1,11 @@ +# Allows registered spectators to re-join the game. +# This includes dead players and spectators manually registered with /uh spectators add. +spectators-can-join: true + +# Allows unregistered spectators to join the game (as spectator only). +unknown-spectators-can-join: true + +# If the previous option is set to false and this one to true, the first time +# an unknown spectator try to join the server, all administrators will be notified +# with a link to allow the spectator to join. The notification will only be sent once. +notify-on-unknown-spectators-trying-to-join: true diff --git a/src/main/resources/modules/core-teams.yml b/src/main/resources/modules/core-teams.yml new file mode 100644 index 0000000..ecd1463 --- /dev/null +++ b/src/main/resources/modules/core-teams.yml @@ -0,0 +1,82 @@ +can-see-friendly-invisibles: true +allow-friendly-fire: true + +# 0 = unlimited. +max-players-per-team: 0 + +# True to have players name in the team's color in the chat. +# No cat will be altered if this option is enabled. +colorize-chat: true + + +# These options are related to the auto-generated banner of each team. +# This banner is used on the teams selector (if set to "banner"), and can be given to the +# players when the game starts. +banner: + shape: + write-letter: true + add-border: true + + give: + place-on-spawn: true # Places the team banner on the spawn point. + give-in-hotbar: false # Gives a banner to each player. + give-on-head: false # Places the banner on the head of each player. + + shields: + add-on-shields: true # Crafted shields will have the team banner on them. MC 1.9+ only. + + +# Chest-based GUI to choose a team and manage the teams +gui: + display: + team-item: "banner" # Values: "banner", "glass", "glass_pane", "clay", "wool", "dye" + glow-on-selected-team: true # Set to true to display an enchantment glow on the player team. + # Note that the glow effect will not be applied with banners. + +team-chat: + # Forces disable the team-chat when the player die. + # If you use SpectatorPlus with the block-commands option enabled, this will prevent spectators + # from using the team chat. + disable-lock-on-death: true + + # Log the private team-chat in the console? + log: false + + +# The sidebar can display the player's team. +sidebar: + # Displays the player's team in the scoreboard + enabled: true + + title: + # The color of the title. If empty, the team color is used. + color: "" + + # If true, the title is the team's name. Else, a generic title (« Your team »). + use-team-name: false + + content: + # Displays hearts colored following the player's life (low = red, high = green) + display-hearts: true + + # Color the whole name, not only the heart, following the life. If disabled, + # the name is white (alive) or gray (dead). + color-name: false + + # Strike the dead players lines. + strike-dead-players: false + + login-state: + # Logged-out players are displayed in italic + italic: true + + # This string is displayed after the name of logged-out players + suffix: "\u27A5" + + display-met-players-only: + # If enabled, the sidebar will only contains players met at some time. + enabled: false + + # If enabled, a teammate will be displayed to the reference player if he/she + # is closer that this amount of blocks to the player. + displayed-when-closer-than: 10 diff --git a/src/main/resources/modules/cosmetics-episodes.yml b/src/main/resources/modules/cosmetics-episodes.yml new file mode 100644 index 0000000..8affd18 --- /dev/null +++ b/src/main/resources/modules/cosmetics-episodes.yml @@ -0,0 +1,9 @@ +# Format: "mm", "mm:ss" or "hh:mm:ss". If invalid, 20 minutes. +# Don't remove the "quotes" (because of the commas)! +length: "20:00" + +# A title is displayed when the episode changes. +display-title: true + +# The current episode is displayed into the sidebar. +display-in-sidebar: true diff --git a/src/main/resources/modules/cosmetics-hardcore-hearts.yml b/src/main/resources/modules/cosmetics-hardcore-hearts.yml new file mode 100644 index 0000000..7f6763f --- /dev/null +++ b/src/main/resources/modules/cosmetics-hardcore-hearts.yml @@ -0,0 +1,12 @@ +# Display hardcore hearts instead of normal ones? +hardcore-hearts: true + +# If a player die, with old Minecraft versions, his client will display an hardcore Game Over screen, +# without a « Respawn » button. But the player CAN respawn, by clicking « Leave server » and then, +# on the confirmation screen, « Respawn ». +# This option can automatically respawn the player after its death. +# Recent versions of Minecraft do have a « Spectate » button in the Game Over screen, but you can still +# enable the auto-respawn for them. +auto-respawn: + do: true + delay: 6 # seconds diff --git a/src/main/resources/modules/cosmetics-player-list-header-footer.yml b/src/main/resources/modules/cosmetics-player-list-header-footer.yml new file mode 100644 index 0000000..d1d7410 --- /dev/null +++ b/src/main/resources/modules/cosmetics-player-list-header-footer.yml @@ -0,0 +1,33 @@ +# You can here fill the header and footer of the player's list (opened with TAB by default) +# with custom strings. You can include chat color codes (with either § or &) and special +# placeholders that will be replaced by special values. +# +# You can use `\n` to split the text over multiple lines. +# +# By default, the following placeholders are available: +# +# {title} -> title of the game +# {playersText} -> the string « x players », where x is the number of players alive +# {playersCount} -> the number of alive players +# {teamsText} -> the string « x teams », where x is the number of teams alive +# {teamsCount} -> the number of alive teams +# +# If the episodes module is loaded, the following are also available: +# +# {episodeText} -> the string « Episode x », where x is the current episode number +# {episodeNumber} -> The current episode's number. +# +# Any module can add their own placeholders (including you owns). Use /uh list-hf-placeholders +# to get a list of all available placeholders for your modules. + +headers: + WAIT: "{title}" + STARTING: "{title}" + IN_GAME: "{title}" + END: "{title}" + +footers: + WAIT: "§2Be patient, the game will start soon..." + STARTING: "§2The game is starting!" + IN_GAME: "§2{playersText} §7- §2{teamsText}" + END: "§2§lGame Over!" diff --git a/src/main/resources/modules/end-death-announcement.yml b/src/main/resources/modules/end-death-announcement.yml new file mode 100644 index 0000000..186bbcd --- /dev/null +++ b/src/main/resources/modules/end-death-announcement.yml @@ -0,0 +1,20 @@ +# Broadcasts a message if a team has fallen. +notify-if-team-has-fallen: true + +# Use this to increase visibility of death messages. +eath-messages-format: "§6" +team-death-messages-format: "§6" + +# Sends a lightning strike effect on the death point +lightning-strike: false + +# Broadcasts a sound to the whole server. +play-sound: true + +# The sound to broadcast. +sound: + name: + - ENTITY_WITHER_SPAWN + - WITHER_SPAWN + volume: 1 + pitch: 1 diff --git a/src/main/resources/modules/end-kick.yml b/src/main/resources/modules/end-kick.yml new file mode 100644 index 0000000..a8f8dc6 --- /dev/null +++ b/src/main/resources/modules/end-kick.yml @@ -0,0 +1,5 @@ +# Kick the player after this delay. +delay: "00:30" + +# Kick the player with this message. +message: "jayjay" diff --git a/src/main/resources/modules/end-xp-to-killers.yml b/src/main/resources/modules/end-xp-to-killers.yml new file mode 100644 index 0000000..21bb1dd --- /dev/null +++ b/src/main/resources/modules/end-xp-to-killers.yml @@ -0,0 +1,5 @@ +# Give this amount of XP levels when a player kills another player. +levels: 2 + +# Only when a player kills a player from another team. +only-other-team: true diff --git a/src/main/resources/modules/external-dynmap.yml b/src/main/resources/modules/external-dynmap.yml new file mode 100644 index 0000000..58bed31 --- /dev/null +++ b/src/main/resources/modules/external-dynmap.yml @@ -0,0 +1,5 @@ +# Displays the players' spawns in the dynmap. +show-spawn-locations: true + +# Displays the players' death locations in the dynmap. +show-death-locations: true diff --git a/src/main/resources/modules/external-motd.yml b/src/main/resources/modules/external-motd.yml new file mode 100644 index 0000000..d085bf8 --- /dev/null +++ b/src/main/resources/modules/external-motd.yml @@ -0,0 +1,5 @@ +# Display the match name in the MOTD +display-match-name: true + +# This will be displayed before the match name (formatting...) +match-name-prefix: "" diff --git a/src/main/resources/modules/external-reports.yml b/src/main/resources/modules/external-reports.yml new file mode 100644 index 0000000..aec07e6 --- /dev/null +++ b/src/main/resources/modules/external-reports.yml @@ -0,0 +1,102 @@ + +# The Hawk reports API base website URL. If empty, defaults +# to the Hawk instance managed by DamagesLogger's authors. +# Change this if you want to use your own instance. +reports-api-base-url: "" + +# If false, the report will not be published at the end of the game. +# It will still be saved in the plugin directory (under plugins/UHPlugin/reports). +publish-report: true + +# If published, the URL can be automatically broadcasted to: +# - ALL: all players in the server (plus the console); +# - ADMINISTRATORS: only administrators (currently operators) +# - CONSOLE: only the console (absolutely nothing in-game). +broadcast-report-to: ALL + + +# The settings below configure the Hawk reports web page. +# TODO add documentation for each. + +date: true +players-count: true +winners: true + +summary: + enabled: true + history: true + players: true + teams: true + +damages: + enabled: true + damages-per-players: true + damages-per-teams: true + damages-from-environment: true + display-killer: true + +players: + enabled: true + play-time: true + + global-statistics: true + statistics-whitelist: [] + statistics-highlight: + - DAMAGE_DEALT + - CRAFT_ITEM + - ITEM_ENCHANTED + - BREWINGSTAND_INTERACTION + - SPRINT_ONE_CM + + used: false + used-whitelist: [] + used-highlight: + - DIAMOND_SWORD + - DIAMOND_AXE + - DIAMOND_PICKAXE + - DIAMOND_HOE + - IRON_SWORD + - IRON_AXE + - IRON_PICKAXE + - IRON_HOE + - CAKE + - SADDLE + - GOLDEN_APPLE + - POTION + - GOLD_RECORD + - GREEN_RECORD + - RECORD_3 + - RECORD_4 + - RECORD_5 + - RECORD_6 + - RECORD_7 + - RECORD_8 + - RECORD_9 + - RECORD_10 + - RECORD_11 + - RECORD_12 + + mined: true + mined-whitelist: [] + mined-highlight: + - DIAMOND + - DIAMOND_ORE + - GOLD_INGOT + - GOLD_ORE + - IRON_INGOT + - IRON_ORE + - EMERALD + - EMERALD_ORE + - OBSIDIAN + - NETHER_WARTS + - MOB_SPAWNER + - STONE + + picked-up: true + picked-up-whitelist: [] + picked-up-highlight: + - APPLE + - BOW + - ENDER_PEARL + - GOLD_INGOT + - SKULL_ITEM diff --git a/src/main/resources/modules/gameplay-compass.yml b/src/main/resources/modules/gameplay-compass.yml new file mode 100644 index 0000000..6ab6897 --- /dev/null +++ b/src/main/resources/modules/gameplay-compass.yml @@ -0,0 +1,29 @@ +# The recipe can either be the default Minecraft recipe, or a custom special, harder, recipe. +# +# The special recipe is with an ingredient in the center, and then, +# from the top, clockwise: iron, spider eye, iron, rotten flesh, iron, bone, iron, gunpowder. +# This field change the central ingredient. +# +# DEFAULT: The vanilla compass recipe, without all these extra things. +# EASY: The center is redstone (like the normal compass). +# MEDIUM: The center is an ender pearl. +# HARD: The center is an eye of ender. +recipe: DEFAULT + +# This item will be required to be able to use the compass, and for each use +# of it. +compass-fee-item: ROTTEN_FLESH + +# This amount of the previous item will be required and consumed for each +# use of the compass. +compass-fee-amount: 1 + +# If true, the compass will only target players from other teams. +never-target-teammates: true + +# The behavior of the compass. +# GIVE_DIRECTION: Gives the target's direction by updating the compass. +# GIVE_DISTANCE: Gives the target's distance from the player. +# GIVE_BOTH: Gives both the direction and the distance. +# GIVE_EITHER_RANDOMLY: Gives either the direction or the distance, randomly, with a small chance of getting both. +compass-behavior: GIVE_DIRECTION diff --git a/src/main/resources/modules/gameplay-daylight-cycle.yml b/src/main/resources/modules/gameplay-daylight-cycle.yml new file mode 100644 index 0000000..f8b0ba2 --- /dev/null +++ b/src/main/resources/modules/gameplay-daylight-cycle.yml @@ -0,0 +1,15 @@ +# If false, the time will be frozen. +enable-daylight-cycle: true + +# The duration of one Minecraft day, in real life minutes. The default duration is +# 20 minutes, but you can change this to any value longer or shorter, down to the +# second if you like to see the sun navigating the sky reaaaallly fast. +daylight-cycle-duration: "00:20:00" + +# The hour of the waiting phase, in ticks. +# For the record, 0 = sun rise, 6000 = midday, 12 000 = sun set, 18 000 = midnight. +waiting-phase-hour: 6000 + +# The hour when the game starts. If the daylight cycle is disabled, this will be the +# hour of the whole game. +initial-game-hour: 0 diff --git a/src/main/resources/modules/gameplay-golden-heads.yml b/src/main/resources/modules/gameplay-golden-heads.yml new file mode 100644 index 0000000..fd20b1c --- /dev/null +++ b/src/main/resources/modules/gameplay-golden-heads.yml @@ -0,0 +1,73 @@ +# Will players drop their head on death? +drop-head-on-death: true + +# Maybe ony in PvP? +drop-head-on-death-pvp-only: false + +# Below, you'll be able to tweak the amount of half-hearts +# apples regenerate. Should we display this amount, if +# different from vanilla, in the apples' tooltips? +display-regen-amount-on-apples: true + + +# Golden apple settings. +# If disabled, the craft will be impossible. +# The regeneration is in half-hearts. +golden-apple: + enable: true + regeneration: 4 + +# Enchanted golden apple settings (a.k.a. “Notch Apple”). +# If disabled, the craft will be impossible. +# If enabled, the old craft with gold blocks will be registered. +# The regeneration is in half-hearts. +enchanted-golden-apple: + enable: false + regeneration: 180 + + +# Player “golden head”, made with a player head and eight gold ingots. +# You can change the amount of golden heads crafted from one head +# and eight ingots, and add or not a RP lore to the item. +# The regeneration is in half-hearts. +player-golden-apple: + enable: true + regeneration: 4 + amount-crafted: 1 + add-lore: true + + +# Wither “golden head”, made with a Wither Skeleton head and eight +# gold ingots. +# You can change the amount of golden heads crafted from one head +# and eight ingots, and add or not a RP lore to the item. +# The regeneration is in half-hearts. +wither-golden-apple: + enable: true + regeneration: 4 + amount-crafted: 1 + add-lore: true + + +# Player “enchanted golden head”, made with a player head and eight +# gold blocks. +# You can change the amount of golden heads crafted from one head +# and eight blocks, and add or not a RP lore to the item. +# The regeneration is in half-hearts. +player-enchanted-golden-apple: + enable: false + regeneration: 180 + amount-crafted: 1 + add-lore: true + + +# Player “enchanted golden head”, made with a Wither Skeleton head +# and eight gold blocks. +# You can change the amount of golden heads crafted from one head +# and eight blocks, and add or not a RP lore to the item. +# The regeneration is in half-hearts. +wither-enchanted-golden-apple: + enable: false + regeneration: 180 + amount-crafted: 1 + add-lore: true diff --git a/src/main/resources/modules/gameplay-hardcore.yml b/src/main/resources/modules/gameplay-hardcore.yml new file mode 100644 index 0000000..b951834 --- /dev/null +++ b/src/main/resources/modules/gameplay-hardcore.yml @@ -0,0 +1,6 @@ +# If false, the natural regeneration will be disabled in playing worlds. +natural-regeneration: false + +# The difficulty of the game worlds. +# Either PEACEFUL, EASY, NORMAL or HARD. +difficulty: HARD diff --git a/src/main/resources/modules/gameplay-killer-rabbit.yml b/src/main/resources/modules/gameplay-killer-rabbit.yml new file mode 100644 index 0000000..b092617 --- /dev/null +++ b/src/main/resources/modules/gameplay-killer-rabbit.yml @@ -0,0 +1,8 @@ +# When a rabbit spawn, it'll have this probability of becoming a Killer Rabbit. +# If 0, no killer rabbit will spawn (but you can also disable the module for the same +# effect). +spawn-probability: 0.05 + +# The Killer Rabbit's name. You can use color codes with § in this. +# If empty, the rabbit won't have any special name (we'll rely on Minecraft default). +name: "The Killer Rabbit of Cærbannog" diff --git a/src/main/resources/modules/gameplay-no-witches.yml b/src/main/resources/modules/gameplay-no-witches.yml new file mode 100644 index 0000000..6e8e67e --- /dev/null +++ b/src/main/resources/modules/gameplay-no-witches.yml @@ -0,0 +1,5 @@ +# Disables Witches' natural spawn (e.g. in caves/dark, or in their huts). +disable-natural-spawn: true + +# Disables Witches' lightning spawn (villagers hit by a lightning bolt will not turn into a witch). +disable-lightning-spawn: true diff --git a/src/main/resources/modules/gameplay-potions.yml b/src/main/resources/modules/gameplay-potions.yml new file mode 100644 index 0000000..e2685af --- /dev/null +++ b/src/main/resources/modules/gameplay-potions.yml @@ -0,0 +1,11 @@ +# Potions won't be able to be increased to the second level. +disable-level-II: true + +# Potions won't be able to be extended in time. +disable-extended: false + +# Players won't be able to make splashes potions. +disable-splash: false + +# Players won't be able to make lingering potions. +disable-lingering: false diff --git a/src/main/resources/modules/gameplay-weather.yml b/src/main/resources/modules/gameplay-weather.yml new file mode 100644 index 0000000..be87507 --- /dev/null +++ b/src/main/resources/modules/gameplay-weather.yml @@ -0,0 +1,11 @@ +# If true, the weather will randomly change during the game. +enable-weather-cycle: true + +# The weather when the game starts. If the weather cycle is disabled, +# this will also be the weather during the whole game. +# Can be CLEAR or DOWNFALL. +initial-weather: CLEAR + +# The weather during the initial waiting phase. +# Can be CLEAR or DOWNFALL. +waiting-phase-weather: CLEAR diff --git a/src/main/resources/modules/scenarii-alliances.yml b/src/main/resources/modules/scenarii-alliances.yml new file mode 100644 index 0000000..27bd3dd --- /dev/null +++ b/src/main/resources/modules/scenarii-alliances.yml @@ -0,0 +1,12 @@ +# The number of alliances each player is allowed to enter. +# To be allowed to enter an alliance, a player must have its +# alliance counter strictly positive. If he/she enters the alliance, +# the amount of players minus one will be subtracted from its counter. +alliances-per-player: 2 + +# The maximal size of an alliance. Similar to teams' max size. +max-players-per-alliance: 3 + +# Players will only be allowed to send an alliance request (using /a) if they +# are at less than this amount of blocks from each other. +max-distance-to-create-an-alliance: 60 diff --git a/src/main/resources/modules/starting-cages.yml b/src/main/resources/modules/starting-cages.yml new file mode 100644 index 0000000..4447a8b --- /dev/null +++ b/src/main/resources/modules/starting-cages.yml @@ -0,0 +1,25 @@ +# The cage type. Can be: +# - team_color_transparent (stained glass using the team color, or white without color/for solo); +# - team_color_solid (the same with stained hardened clay); +# - custom (a custom block, configure the one to use after). +type: TEAM_COLOR_TRANSPARENT + +# If you selected “custom” before, write here the block you want to use. It can be any valid Material. +# You can use safely any falling block here, they will never fall. +custom-block: + +# If true, the cages will be built completely, including the ceiling. Else, they will be open to the sky. +build-ceiling: false + +# If true, the walls will be built using the block above. Else, using barrier blocks. +visible-walls: true + +# The internal square radius of the cage. +# With 0, you'll have a cage with one block to walk. +# With 1, you'll have a 3×3 cage. +# With 2, a 5×5 cage. Etc. +radius: 2 + +# The internal height of the cages, i.e. the height of the space available to the players inside the cage. +# It is kinda useless to set a too high height here, as players won't be able to fly. +height: 3 diff --git a/src/main/resources/modules/utilities-rules.yml b/src/main/resources/modules/utilities-rules.yml new file mode 100644 index 0000000..6237703 --- /dev/null +++ b/src/main/resources/modules/utilities-rules.yml @@ -0,0 +1,17 @@ +# You can send the rules automatically. +# Remainder: you can also send the rules manually using /uh rules [player]. +display: + # Automatically displays the rules to players when they join the game (and it is not started). + on-join: false + + # Automatically broadcasts the rules when the game starts. + on-start: true + +# Rules are a way to display rules & other infos to the players. +# The content is completely up to you, formatting included (using standard +# formatting codes with either § or &). It will be displayed as a list to +# the players (one bullet per line in the following list). +# Empty entries (« - "" ») are replaced by a completely blank line, if you +# need a separator. +rules: + - diff --git a/src/main/resources/modules/utilities-runtime-commands-executor.yml b/src/main/resources/modules/utilities-runtime-commands-executor.yml new file mode 100644 index 0000000..e06e74b --- /dev/null +++ b/src/main/resources/modules/utilities-runtime-commands-executor.yml @@ -0,0 +1,35 @@ +# This module allows you to schedule commands at any moment during the game. They will be executed by the console +# automatically. +# For each game phase, you'll be able to configure a list of commands to run, with a delay for each of them. The +# commands will be executed when the phase is reached, after the given delay. As example, a command configured into +# the `in-game` list with a 3-minutes delay will be executed three minutes after the game's start. +# The delay's formats are "mm" (minutes), "mm:ss" or "hh:mm:ss". +# Empty commands are ignored. + + +# Commands executed from the server startup. +wait: + - exec: "" + delay: "00:12:00" + + +# Commands executed from the moment the game is launched (when the /uh start is first executed, or the corresponding +# GUI button). Beware that this phase can be cancelled, e.g. if the game cannot be started. If so, all non-executed +# commands will not be executed, but some (especially with a zero delay) may have been executed and could be executed +# twice. +starting: + - exec: "" + delay: "00:24:00" + + +# Commands executed from the moment the game starts for real, when players falls from their spawn point into the world. +in-game: + - exec: "" + delay: "00:48:00" + + +# Commands executed from the game's end. Beware that this phase can be cancelled, e.g. if someone is resurrected. If so, +# all non-executed commands will not be executed, but some ay have been executed and could be executed twice. +end: + - exec: "" + delay: "01:36:00" diff --git a/src/main/resources/modules/utilities-walls.yml b/src/main/resources/modules/utilities-walls.yml new file mode 100644 index 0000000..192fc7b --- /dev/null +++ b/src/main/resources/modules/utilities-walls.yml @@ -0,0 +1,8 @@ +# The height of the wall generated using /uh build-wall, in blocks, counted from the bottom of the world. +height: 128 + +block: + # The replace-air block will be placed where there where some transparent blocks or trees before. + # The replace-solid one, where there was another kind of block. + replace-air: GLASS + replace-solid: BEDROCK diff --git a/src/main/resources/modules/utilities-warning.yml b/src/main/resources/modules/utilities-warning.yml new file mode 100644 index 0000000..c727791 --- /dev/null +++ b/src/main/resources/modules/utilities-warning.yml @@ -0,0 +1,3 @@ +# The delay between two warning messages sent to the players out of a future border +# (this warning is set using /uh border-warning <futureDiameter>). +warning-interval: "00:01:30" diff --git a/src/main/resources/modules/waiting-phase-wait.yml b/src/main/resources/modules/waiting-phase-wait.yml new file mode 100644 index 0000000..ce458b2 --- /dev/null +++ b/src/main/resources/modules/waiting-phase-wait.yml @@ -0,0 +1,39 @@ +# Teleport the players to the spawn point on login if the game is not started? +# Avoids the random spawn point of Minecraft, and teleports them back to +# there if they log out then in. +teleport-to-spawn-if-not-started: true + +inventory: + # True to clear the inventory of the players before the beginning of the game. + clear: true + + # True to prevent users from using their inventory when the game is not started. + prevent-usage: true + + # True to disable all the inventory points above for players with the uh.build permission. + allow-for-builders: true + + +teams-selector: + # True to give to the players a team selector, opening the teams inventory GUI (same as /teams). + enabled: true + + # The item to use as the team selector. Right-clicking it will open the GUI. + item: NETHER_STAR + + +config-accessor: + # True to give to the players with enough permissions a config accessor, opening the + # /config GUI. + enabled: true + + # The item to use as the config accessor. Right-clicking it will open the GUI. + item: REDSTONE_COMPARATOR + +# Displays the current team in the action bar before the game. Nothing is displayed if the player is +# not in a team. +team-in-action-bar: true + +# If set to true, players will be able to PVP while waiting. They will respawn in the world's +# spawn point every time. +enable-pvp: false diff --git a/src/main/resources/modules/world-generation-creatures.yml b/src/main/resources/modules/world-generation-creatures.yml new file mode 100644 index 0000000..01dc701 --- /dev/null +++ b/src/main/resources/modules/world-generation-creatures.yml @@ -0,0 +1,115 @@ +# +# This module tweaks the creatures spawn in the worlds (any creature; any biome). +# You can increase, decrease or even remove completely an entity to/from a specific or all biomes. +# +# This mainly act on **chunk generation** (it is also effective for natural spawns to refill the world +# with new creatures, but way less). It works by patching the Minecraft Biomes registry to update the +# spawning rules. So, you should generate (using WorldBorder and its fill command, for example) the world with this +# plugin running and this module enabled, for best results. +# +# To enable ths module at startup, add it into the main `config.yml` file, like so: +# +# modules: +# "worldgen.creatures": true +# +# +# +# Each spawning rule have these properties. Except if specified, unset properties will be left as-is. +# +# - The entity, obviously. +# The list is available here: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/EntityType.html +# +# - The weight of the entity in the biome. +# The higher the weight is, the likelier the mob is to be selected when the server looks for a mob to spawn (in all +# cases). If set to 0, the entity will not spawn at all from natural spawning. +# +# - The minimal pack size. +# While generating the chunks (and only while generating the chunks), the server will spawn entities in groups; this +# is the minimal size of such groups. +# +# - The maximal pack size. +# Same, but it's the max. +# +# - The biomes where this rule is active. +# If you precise nothing at all about the biomes (only the previous properties), the rule will be updated for +# all biomes already having a rule for the given entity (so the entity will not spawn in *new* biomes). +# +# If you want the rule to be applied to *all* biomes, add `biomes: ALL`. This will tell Minecraft to spawn the +# entity in all biomes, including these where the entity does not spawn in vanilla. This includes the Nether and the +# End. In this example, Mushroom Cows will rarely spawn in all biomes (not only Mushroom Islands). +# +# spawn_rules: +# - entity: MUSHROOM_COW +# weight: 1 +# biomes: ALL +# +# If you want to apply this rule to some specific biomes (leaving rules for this entity in other biomes untouched, +# list the biomes in a `biomes` key, like in the following example. This example will tell Minecraft to spawn +# blazes with a very, very high weight in deserts & savannas (including plateaux). +# +# spawn_rules: +# - entity: BLAZE +# weight: 250 # This would basically mean “blazes everywhere” (in the biomes below, at least) +# biomes: +# - DESERT +# - SAVANNA +# - SAVANNA_PLATEAU +# +# The biomes' list is available here: https://gist.github.com/AmauryCarrade/667ada6cbba41b3c3475217247ab9715 +# +# +# +# The default spawn rules below are a bit heavier for passive useful creature in typical survival games. Feel free to +# alter them to your preferences, of course. +# +# This module alters the spawning rules when enabled **for the whole server lifetime**. Even if disabled, the rules will +# still be there. If the server is rebooted without this module, the rules will be reset to Minecraft default. +# +# If you remove all spawn rules, the behavior will be vanilla. +# +# In case of conflicts (i.e. multiples rules for the same entity and the same biome), the last rule in the list wins. +# +# As a finale note, please remember that entities will still spawn according to their environmental rules. As example, +# cows spawn on grass. This imply that some rules may not work as you intended. As example, if you configure rabbits +# to spawn in the Nether, the rule will be saved into the Minecraft server, but you'll never see any rabbit in there, +# because there is no grass or sand in the Nether. +# + +spawn_rules: + - entity: SHEEP + weight: 15 + minimal_pack_size: 3 + maximal_pack_size: 8 + + - entity: RABBIT + weight: 4 + minimal_pack_size: 2 + maximal_pack_size: 5 + + - entity: PIG + weight: 15 + minimal_pack_size: 6 + maximal_pack_size: 14 + + - entity: CHICKEN + weight: 18 + minimal_pack_size: 8 + maximal_pack_size: 16 + + - entity: COW + weight: 18 + minimal_pack_size: 5 + maximal_pack_size: 12 + + - entity: WOLF + weight: 5 + minimal_pack_size: 1 + maximal_pack_size: 6 + + - entity: HORSE + weight: 5 + minimal_pack_size: 2 + maximal_pack_size: 8 + + - entity: OCELOT + weight: 5 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5f65b60..732301b 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,46 +1,46 @@ -name: UHPlugin -description: UltraHardcore Reloaded -main: eu.carrade.amaury.UHCReloaded.UHCReloaded -version: 1.5 +name: QuartzSurvivalGames +description: Survival games plugin, able to handle most Minecraft survival games (like UHC) through combined modules +main: eu.carrade.amaury.quartzsurvivalgames.QuartzSurvivalGames +load: STARTUP +version: 2.0-beta author: "Amaury Carrade" -authors: [azenet, "João Roda"] - -awareness: - - !@UTF8 +authors: ["azenet", "João Roda"] +api-version: "1.13" softdepend: - WorldBorder - SpectatorPlus - dynmap - ProtocolLib + - DamagesLogger commands: uh: description: UltraHardcore Reloaded base command usage: /<command> <subcommand> - see /<command> for available subcommands. - t: - description: Allows an user to send a message to his team. - usage: /<command> <message> - - g: - description: Allows an user to send a message to everyone. - usage: /<command> <message> - - togglechat: - description: Allows an user to toggle the chat between the global chat and a team chat. - usage: /<command> - - join: - description: Use this to join an UltraHardcore team. - usage: /<command> [player] <team> - - leave: - description: Use this to quit your current UltraHardcore team. - usage: /<command> [player] - - teams: - description: Displays a GUI to manage the UHCReloaded teams - usage: /<command> +# t: +# description: Allows an user to send a message to his team. +# usage: /<command> <message> +# +# g: +# description: Allows an user to send a message to everyone. +# usage: /<command> <message> +# +# togglechat: +# description: Allows an user to toggle the chat between the global chat and a team chat. +# usage: /<command> +# +# join: +# description: Use this to join an UltraHardcore team. +# usage: /<command> [player] <team> +# +# leave: +# description: Use this to quit your current UltraHardcore team. +# usage: /<command> [player] +# +# teams: +# description: Displays a GUI to manage the UHCReloaded teams +# usage: /<command> permissions: @@ -209,11 +209,10 @@ permissions: uh.player.renameTeam: - default: Allows a player to rename his own team. + description: Allows a player to rename his own team. default: op uh.team.gui: description: Allows a player to use the teams GUI (/uh team gui) default: true - diff --git a/src/test/java/eu/carrade/amaury/quartzsurvivalgames/SidebarInjectorTest.java b/src/test/java/eu/carrade/amaury/quartzsurvivalgames/SidebarInjectorTest.java new file mode 100644 index 0000000..9ac55bb --- /dev/null +++ b/src/test/java/eu/carrade/amaury/quartzsurvivalgames/SidebarInjectorTest.java @@ -0,0 +1,229 @@ +/* + * 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.quartzsurvivalgames; + +import eu.carrade.amaury.quartzsurvivalgames.modules.core.sidebar.SidebarInjector; +import org.junit.Assert; +import org.junit.ComparisonFailure; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + + +public class SidebarInjectorTest +{ + private static<T> void assertListsEquals(final String message, final List<T> expected, final List<T> actual) + { + if (expected == actual) return; + + if (expected.size() != actual.size()) + Assert.fail(message + " - Lists size differ (expected <" + expected.size() + "> but got <" + actual.size() + ">)"); + + for (int i = 0; i < expected.size(); i++) + { + final T expectedValue = expected.get(i); + final T actualValue = actual.get(i); + + if (!expectedValue.equals(actualValue)) + { + if (expectedValue instanceof String && actualValue instanceof String) + { + final String completeMessage = (message == null ? "" : message + " - ") + "Lists first differ at index " + i + ":"; + throw new ComparisonFailure(completeMessage, (String) expectedValue, (String) actualValue); + } + else + { + Assert.fail((message == null ? "" : message + " - ") + "Lists first differ at index " + i + ": expected <" + expected.toString() + "> but got <" + actual.toString() + ">"); + } + } + } + } + + @Test + public void testBasicInjector() + { + assertListsEquals( + "Items added without priority or spacing should be left as is and in order", + Arrays.asList("Line 1", "Line 2", "Line 3", "Line 4", "Line 5", "Line 6"), + new SidebarInjector() + .injectLines("Line 1", "Line 2", "Line 3") + .injectLines("Line 4") + .injectLines("Line 5", "Line 6") + .buildLines() + ); + } + + @Test + public void testPriorityInInjector() + { + assertListsEquals( + "Items added with priority should be ordered according to theses, regardless of the inclusion order", + Arrays.asList("Line 4", "Line 1", "Line 2", "Line 3", "Line 5", "Line 6"), + new SidebarInjector() + .injectLines("Line 1", "Line 2", "Line 3") + .injectLines(SidebarInjector.SidebarPriority.TOP,"Line 4") + .injectLines("Line 5", "Line 6") + .buildLines() + ); + + assertListsEquals( + "Items added with multiple priorities should be ordered according to theses, regardless of the inclusion order", + Arrays.asList("Line 5", "Line 6", "Line 4", "Line 1", "Line 2", "Line 3"), + new SidebarInjector() + .injectLines(SidebarInjector.SidebarPriority.BOTTOM, "Line 1", "Line 2", "Line 3") + .injectLines(SidebarInjector.SidebarPriority.TOP,"Line 4") + .injectLines(SidebarInjector.SidebarPriority.VERY_TOP, "Line 5", "Line 6") + .buildLines() + ); + + assertListsEquals( + "Items added without priority or spacing should be left as is and in order", + Arrays.asList("Line 1", "Line 2", "Line 4", "Line 3", "Line 5", "Line 6"), + new SidebarInjector() + .injectLines(SidebarInjector.SidebarPriority.VERY_BOTTOM, "Line 6") + .injectLines(SidebarInjector.SidebarPriority.BOTTOM, "Line 5") + .injectLines(SidebarInjector.SidebarPriority.MIDDLE, "Line 4") + .injectLines("Line 3") + .injectLines(SidebarInjector.SidebarPriority.TOP, "Line 2") + .injectLines(SidebarInjector.SidebarPriority.VERY_TOP, "Line 1") + .buildLines() + ); + } + + @Test + public void testSpacesInInjector() + { + assertListsEquals( + "If spaces are required around the only element, they are not added", + Collections.singletonList("Line 1"), + new SidebarInjector() + .injectLines(true, "Line 1") + .buildLines() + ); + + assertListsEquals( + "If spaces are required above the first element, it is not added", + Arrays.asList("Line 1", "Line 2", "Line 3"), + new SidebarInjector() + .injectLines(true, false, "Line 1") + .injectLines("Line 2", "Line 3") + .buildLines() + ); + + assertListsEquals( + "If spaces are required around the first element, it is added after but not before", + Arrays.asList("Line 1", "", "Line 2", "Line 3"), + new SidebarInjector() + .injectLines(true, "Line 1") + .injectLines("Line 2", "Line 3") + .buildLines() + ); + + assertListsEquals( + "If spaces are required below the last element, it is not added", + Arrays.asList("Line 1", "Line 2", "Line 3"), + new SidebarInjector() + .injectLines("Line 1") + .injectLines(false, true, "Line 2", "Line 3") + .buildLines() + ); + + assertListsEquals( + "If spaces are required around the last element, it is added before but not after", + Arrays.asList("Line 1", "Line 2", "", "Line 3", "Line 4"), + new SidebarInjector() + .injectLines("Line 1", "Line 2") + .injectLines(true, "Line 3", "Line 4") + .buildLines() + ); + + assertListsEquals( + "If spaces are required after an element and before the next, it is added only once", + Arrays.asList("Line 1", "Line 2", "", "Line 3", "Line 4"), + new SidebarInjector() + .injectLines(true, "Line 1", "Line 2") + .injectLines(true, "Line 3", "Line 4") + .buildLines() + ); + } + + @Test + public void testSpacesAndPrioritiesInInjector() + { + assertListsEquals( + "If spaces are required above the first element, it is not added (with priorities)", + Arrays.asList("Line 1", "Line 2", "Line 3"), + new SidebarInjector() + .injectLines("Line 2", "Line 3") + .injectLines(SidebarInjector.SidebarPriority.TOP, true, false, "Line 1") + .buildLines() + ); + + assertListsEquals( + "If spaces are required around the first element, it is added after but not before", + Arrays.asList("Line 1", "", "Line 2", "Line 3"), + new SidebarInjector() + .injectLines("Line 2", "Line 3") + .injectLines(SidebarInjector.SidebarPriority.VERY_TOP, true, "Line 1") + .buildLines() + ); + + assertListsEquals( + "If spaces are required below the last element, it is not added", + Arrays.asList("Line 1", "Line 2", "Line 3"), + new SidebarInjector() + .injectLines(SidebarInjector.SidebarPriority.BOTTOM, false, true, "Line 2", "Line 3") + .injectLines("Line 1") + .buildLines() + ); + + assertListsEquals( + "If spaces are required around the last element, it is added before but not after", + Arrays.asList("Line 1", "Line 2", "", "Line 3", "Line 4"), + new SidebarInjector() + .injectLines(SidebarInjector.SidebarPriority.VERY_BOTTOM, true, "Line 3", "Line 4") + .injectLines("Line 1", "Line 2") + .buildLines() + ); + + assertListsEquals( + "If spaces are required after an element and before the next, it is added only once", + Arrays.asList("Line 1", "Line 2", "", "Line 3", "Line 4"), + new SidebarInjector() + .injectLines(true, "Line 1", "Line 2") + .injectLines(SidebarInjector.SidebarPriority.MIDDLE,true, "Line 3", "Line 4") + .buildLines() + ); + } +}