diff --git a/.travis.yml b/.travis.yml index 8c197c0b..90a3db0d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ script: - ./gradlew build jdk: - - oraclejdk8 + - openjdk8 before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index c3d7ea02..3d7a556a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,71 @@ # Change Log -# Upcoming/Unreleased Features, Changes & Bugfixes -**REQUIRED: SF build 2764+ & GP build 4.3.0.505+ OPTIONAL: Nucleus version 1.2.0+** -- Added Void World Generation capabilities -- Added Nether portal fix - - -# Beta 27.2 +# Beta 28 +### NOTE: Sponge Forge `1.12.2-2825-7.1.6-RC3697` adds entity and biome support for schematics +**REQUIRED: Sponge API 7.1 (SF 3682+); GP 1.12.2-4.3.0.622+; Permissions Plugin (ie. LuckPerms)** +**OPTIONAL: Nucleus 1.9.0-S7.1+** +- Added new schematic features: + - `/is create` & `/is reset` now feature a chest UI when more than 1 schematic is available + - `/is schematic` - schematic parent & list command + - `/is schematic create ` - replaces `/isa createschematic ` + - `/is schematic delete ` - deletes a schematic + - `/is schematic command ` - manages schematic commands + - `/is schematic info ` - displays detailed information about a schematic + - `/is schematic setbiome ` - set a default biome for a schematic that overrides the permission option + - `/is schematic setheight ` - set the generation height of a schematic + - `/is schematic setname ` - set an in-game name for a schematic that supports formatting code + - `/is schematic seticon ` - set an icon for a schematic to be used by the chest GUI + - `/is schematic setpreset ` - set a flat world preset for a schematic *_see flat world preset support_ + - `skyclaims.default-schematic` now defaults to empty which will list valid schematics + - Removed `Misc-List-Schematics` config + - Added `Misc > Text-Schematic-List` config to disable new chest UI +- Removed `/isa` &`/is admin` + - `/is transfer` replaces `/isa transfer` + - `/is reload` replaces `/isa reload` + - `Admin-Command-Alias` config removed +- Added `skyclaims.max-teammates` option to limit the number of players per island +- Added fine-grained keep/clear inventory control: + - Player inventory keep inventory permissions: + - `skyclaims.keepinv.player.create` + - `skyclaims.keepinv.player.delete` + - `skyclaims.keepinv.player.kick` + - `skyclaims.keepinv.player.leave` + - `skyclaims.keepinv.player.reset` + - EnderChest inventory keep inventory permissions: + - `skyclaims.keepinv.enderchest.create` + - `skyclaims.keepinv.enderchest.delete` + - `skyclaims.keepinv.enderchest.kick` + - `skyclaims.keepinv.enderchest.leave` + - `skyclaims.keepinv.enderchest.reset` +- Added `/is entity` command for detailed entity information +- Added `/is setname [name]` command +- Added `/scplayerinfo` command for debugging permission options +- Added support for flat world preset codes (_block ID portion only_) for region generation + - See https://minecraft.gamepedia.com/Superflat#Preset_code_format for more details +- Added new schematics: + - Stoneblock 2 + - SkyFactory 4 +- Added `World > Regen-On-Create` config option +- Reworked `/is list [island] [sort type] [sort order]` + - Sort order has been separated from sort type + - **Sort Types**: NAME, CREATED, ONLINE, ACTIVE, MEMBERS, SIZE, ENTITIES + - **Sort Orders**: ASC, DESC + - Added `Misc > Primary-List-Sort` config option - sets a sort type that gets applied before the one provided from the command argument +- Added `Misc > Island-Commands` config option + - Commands trigger on island creation, join, and reset + - Removed `Misc > Create-Commands` & `Misc > Reset-Commands` +- Removed outdated schematics: + - Garden of Glass + - SkyExchange +- Added island `min-size` check when an island owner logs in and if necessary, the island will be expanded +- Fixed schematics sometimes not generating at the intended height. The height set will be the height the player is at when standing on the lowest block of a schematic. +- Fixed Nucleus Integration commands not registering after a reload +- Fixed admin island expansion (`/is info`) bug where old clickable text can be used to expand outside the region +- Fixed a bug where `/is lock` would not prevent entry to a locked island +- Fixed a bug when removing overlapping claims during `/is create` +- Updated bStats to 1.4 + +# Beta 27.2 HOTFIX **REQUIRED: SF build 2800+ & GP build 4.3.0.509+ OPTIONAL: Nucleus version 1.2.0+** - **BREAKING CHANGES:** - Biome argument permissions have changed to `skyclaims.arguments.biomes.modid.biomeid` diff --git a/README.md b/README.md index 8604ee6d..914a2f54 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# SkyClaims [![Build Status](https://img.shields.io/teamcity/https/ci.devonthe.rocks/s/SkyClaims_Build.svg)](https://ci.devonthe.rocks/viewType.html?buildTypeId=SkyClaims_Build&guest=1) [![Releases](https://img.shields.io/github/downloads/DevOnTheRocks/SkyClaims/total.svg)](https://github.com/DevOnTheRocks/SkyClaims/releases) ![Discord](https://img.shields.io/discord/265190931072942080.svg) +# SkyClaims [![Releases](https://img.shields.io/github/downloads/DevOnTheRocks/SkyClaims/total.svg)](https://github.com/DevOnTheRocks/SkyClaims/releases) ![Discord](https://img.shields.io/discord/265190931072942080.svg) English | Chinese @@ -27,19 +27,19 @@ This plugin is in Beta. Live support is available for the latest builds through - [X] Change the biome of a block, chunk or entire island - [X] Limit entity spawning per island - [X] Automatic removal of inactive islands +- [X] Island messaging via GP's `/townchat`/`/tc` for chatting within your island +- [X] Economy support for schematics & island expansion - [ ] Configurable island layouts (linear & spiral planned) -- [ ] Island messaging channel for chatting within your island -- [ ] Economy support for schematics & island expansion ## Dependencies - **Required:** - [Sponge](https://www.spongepowered.org/downloads) - 1.12.2-2555-7.0.0-BETA-2800+ - - [Grief Prevention](https://forums.spongepowered.org/t/griefprevention-official-thread/1123) - 1.12.2-4.3.0.473+ + - [Grief Prevention](https://forums.spongepowered.org/t/griefprevention-official-thread/1123) - 1.12.2-4.3.0.622+ - Permission Plugin - [LuckPerms](https://forums.spongepowered.org/t/luckperms-an-advanced-permissions-plugin/14274) is highly recommended - **Optional:** - - [Nucleus](https://nucleuspowered.org) - 1.2.0+ - + - [Nucleus](https://nucleuspowered.org) - 1.9.0-S7.1+ + - Economy Plugin - [Economy Lite](https://ore.spongepowered.org/Flibio/EconomyLite), [Total Economy](https://ore.spongepowered.org/Erigitic/Total-Economy), or any other Sponge Economy plugin of your choosing. ## Additional Information diff --git a/build.gradle b/build.gradle index 6c5cf237..f1c9cbc2 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,11 @@ plugins { id "idea" id "signing" id "ninja.miserable.blossom" version "1.0.1" - id "com.github.johnrengelman.shadow" version "2.0.1" - id "org.spongepowered.plugin" version "0.8.1" - id 'com.qixalite.spongestart2' version '3.0.1' + id "com.github.johnrengelman.shadow" version "5.0.0" + id "org.spongepowered.plugin" version "0.9.0" + id "com.qixalite.spongestart2" version "4.0.0" + id "io.franzbecker.gradle-lombok" version "3.1.0" + id "org.sonarqube" version "2.6" } group = "net.mohron.skyclaims" @@ -39,8 +41,12 @@ repositories { url = "http://repo.drnaylor.co.uk/artifactory/list/minecraft" } maven { - name "LuckPerms" - url "https://repo.lucko.me/" + name = "LuckPerms" + url = "https://repo.lucko.me/" + } + maven { + name = "bStats" + url = "http://repo.bstats.org/content/repositories/releases/" } } @@ -48,15 +54,22 @@ dependencies { compile("org.spongepowered:spongeapi:${spongeapi}") compile("me.ryanhamshire:griefprevention:${griefprevention}:api") compile("io.github.nucleuspowered:nucleus-api:${nucleus}") + compile("org.bstats:bstats-sponge:${bstats}") runtimeOnly("me.ryanhamshire:griefprevention:${griefprevention}") //compile fileTree(dir: "libs", include: "*.jar") } +lombok { + version = "1.18.8" + sha256 = "" +} + shadowJar { + classifier = "plugin" dependencies { - include(dependency("me.ryanhamshire:griefprevention:${griefprevention}:api")) - include(dependency("io.github.nucleuspowered:nucleus-api:${nucleus}")) + include(dependency("org.bstats:bstats-sponge:${bstats}")) } + minimize() } blossom { @@ -68,12 +81,8 @@ blossom { } spongestart { - online "false" - minecraft "1.12.2" - type "bleeding" - spongeForge "${spongeforge}" - forge "${forge}" - forgeServerFolder "run/API7/" + online = "false" + minecraft = "1.12.2" } signing { diff --git a/gradle.properties b/gradle.properties index f361efa0..cf6ea00e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,13 +1,13 @@ ## Version major=0 -minor=27 -patch=2 -api=S7.0 +minor=28 +patch=0 +api=S7.1 suffix=BETA ## Dependencies -spongeapi=7.0.0 -spongeforge=1.12.2-2611-7.1.0-BETA-2953 -forge=14.23.0.2528 -nucleus=1.2.0-PR5-S7.0 -griefprevention=1.12.2-4.3.0.509 -luckperms=4.0.0 \ No newline at end of file +spongeapi=7.1.0 +spongeforge=1.12.2-2768-7.1.4 +forge=14.23.5.2768 +griefprevention=1.12.2-4.3.0.662 +nucleus=1.9.0-S7.1 +bstats=1.4 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 933b6473..41a9c7e1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Sun May 12 10:08:07 EDT 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/src/main/java/net/mohron/skyclaims/SkyClaims.java b/src/main/java/net/mohron/skyclaims/SkyClaims.java index a17f8ecd..dbc215b7 100644 --- a/src/main/java/net/mohron/skyclaims/SkyClaims.java +++ b/src/main/java/net/mohron/skyclaims/SkyClaims.java @@ -29,19 +29,18 @@ import static net.mohron.skyclaims.PluginInfo.VERSION; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import com.google.inject.Inject; import java.nio.file.Path; +import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.Set; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; import me.ryanhamshire.griefprevention.GriefPrevention; import me.ryanhamshire.griefprevention.api.GriefPreventionApi; -import net.mohron.skyclaims.command.CommandAdmin; import net.mohron.skyclaims.command.CommandIsland; -import net.mohron.skyclaims.command.argument.SchematicArgument; +import net.mohron.skyclaims.command.debug.CommandPlayerInfo; import net.mohron.skyclaims.command.debug.CommandVersion; import net.mohron.skyclaims.config.ConfigManager; import net.mohron.skyclaims.config.type.GlobalConfig; @@ -56,20 +55,28 @@ import net.mohron.skyclaims.listener.RespawnHandler; import net.mohron.skyclaims.listener.SchematicHandler; import net.mohron.skyclaims.listener.WorldLoadHandler; -import net.mohron.skyclaims.metrics.Metrics; +import net.mohron.skyclaims.schematic.SchematicManager; import net.mohron.skyclaims.team.InviteService; import net.mohron.skyclaims.world.Island; import net.mohron.skyclaims.world.IslandCleanupTask; +import net.mohron.skyclaims.world.IslandManager; +import net.mohron.skyclaims.world.gen.VoidWorldGeneratorModifier; +import net.mohron.skyclaims.world.region.Region; import ninja.leaping.configurate.commented.CommentedConfigurationNode; import ninja.leaping.configurate.loader.ConfigurationLoader; +import org.bstats.sponge.Metrics2; import org.slf4j.Logger; import org.spongepowered.api.Game; import org.spongepowered.api.Platform; import org.spongepowered.api.Sponge; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockTypes; import org.spongepowered.api.config.ConfigDir; import org.spongepowered.api.config.DefaultConfig; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.Order; +import org.spongepowered.api.event.filter.Getter; +import org.spongepowered.api.event.game.GameRegistryEvent; import org.spongepowered.api.event.game.GameReloadEvent; import org.spongepowered.api.event.game.state.GameAboutToStartServerEvent; import org.spongepowered.api.event.game.state.GameConstructionEvent; @@ -77,11 +84,17 @@ import org.spongepowered.api.event.game.state.GamePreInitializationEvent; import org.spongepowered.api.event.game.state.GameStartedServerEvent; import org.spongepowered.api.event.game.state.GameStoppingServerEvent; +import org.spongepowered.api.event.world.ConstructWorldPropertiesEvent; +import org.spongepowered.api.event.world.LoadWorldEvent; import org.spongepowered.api.plugin.Dependency; import org.spongepowered.api.plugin.Plugin; import org.spongepowered.api.plugin.PluginContainer; import org.spongepowered.api.scheduler.Task; import org.spongepowered.api.service.permission.PermissionService; +import org.spongepowered.api.world.Location; +import org.spongepowered.api.world.World; +import org.spongepowered.api.world.gen.WorldGeneratorModifier; +import org.spongepowered.api.world.storage.WorldProperties; @Plugin( id = ID, @@ -96,8 +109,6 @@ }) public class SkyClaims { - public static Map islands = Maps.newHashMap(); - private static Set saveQueue = Sets.newHashSet(); private static SkyClaims instance; private GriefPreventionApi griefPrevention; private PermissionService permissionService; @@ -112,7 +123,7 @@ public class SkyClaims { private Game game; @Inject - private Metrics metrics; + private Metrics2 metrics; @Inject @ConfigDir(sharedRoot = false) @@ -125,11 +136,15 @@ public class SkyClaims { private IDatabase database; + private Map islandManagers = Maps.newHashMap(); private InviteService inviteService; + private SchematicManager schematicManager; + private WorldGeneratorModifier voidGenModifier = new VoidWorldGeneratorModifier(); private boolean enabled = true; + private boolean setupSpawn = false; - private static final String cleanup = "skyclaims.island.cleanup"; + private static final String ISLAND_CLEANUP = "skyclaims.island.cleanup"; public static SkyClaims getInstance() { return instance; @@ -192,19 +207,63 @@ public void onAboutToStart(GameAboutToStartServerEvent event) { } permissionService = Sponge.getServiceManager().provideUnchecked(PermissionService.class); - if (Sponge.getServiceManager().getRegistration(PermissionService.class).get().getPlugin().getId().equalsIgnoreCase("sponge")) { + if (!Sponge.getServiceManager().getRegistration(PermissionService.class).isPresent() + || Sponge.getServiceManager().getRegistration(PermissionService.class).get().getPlugin().getId().equalsIgnoreCase("sponge")) { logger.error("Unable to initialize plugin. SkyClaims requires a permissions plugin. Disabling SkyClaims."); enabled = false; return; } inviteService = new InviteService(); + schematicManager = new SchematicManager(this); registerListeners(); registerTasks(); registerCommands(); } + @Listener + public void onGameRegistry(GameRegistryEvent.Register event) { + event.register(voidGenModifier); + } + + @Listener + public void onConstructWorldProperties(ConstructWorldPropertiesEvent event, @Getter(value = "getWorldProperties") WorldProperties properties) { + if (!properties.isInitialized() && config.getWorldConfig().getVoidDimensions().contains(properties.getWorldName())) { + Collection modifiers = properties.getGeneratorModifiers(); + modifiers.add(voidGenModifier); + properties.setGeneratorModifiers(modifiers); + logger.info("{} set to use SkyClaims' Enhanced Void World Generation Modifier.", properties.getWorldName()); + } + if (!properties.isInitialized() && properties.getWorldName() + .equalsIgnoreCase(config.getWorldConfig().getWorldName())) { + setupSpawn = true; + } + } + + @Listener(order = Order.LATE) + public void onWorldLoad(LoadWorldEvent event, @Getter(value = "getTargetWorld") World world) { + if (!enabled || !griefPrevention.isEnabled(world) || !world.equals(config.getWorldConfig().getWorld())) { + return; + } + + if (setupSpawn && !config.getWorldConfig().isSeparateSpawn()) { + Location spawn = new Region(0, 0).getCenter(); + int size = 4; + for (int x = -size; x <= size; x++) { + for (int z = -size; z <= size; z++) { + spawn.add(x, -1, z).setBlock(BlockState.builder().blockType(BlockTypes.BEDROCK).build()); + if (Math.abs(x) == size || Math.abs(z) == size) { + spawn.add(x, 1, z).setBlock(BlockState.builder().blockType(BlockTypes.FENCE).build()); + } + world.getProperties().setSpawnPosition(spawn.getPosition().toInt()); + world.getProperties().setGameRule("spawnRadius", "0"); + } + } + logger.info("Spawn area created."); + } + } + @Listener public void onServerStarted(GameStartedServerEvent event) { if (!enabled) { @@ -212,12 +271,13 @@ public void onServerStarted(GameStartedServerEvent event) { } database = initializeDatabase(); + schematicManager.load(); - islands = database.loadData(); - logger.info("{} islands loaded.", islands.size()); - if (!saveQueue.isEmpty()) { - logger.info("Saving {} claims that were malformed.", saveQueue.size()); - database.saveData(saveQueue); + IslandManager.ISLANDS = database.loadData(); + logger.info("{} islands loaded.", IslandManager.ISLANDS.size()); + if (!IslandManager.saveQueue.isEmpty()) { + logger.info("Saving {} claims that were malformed.", IslandManager.saveQueue.size()); + database.saveData(IslandManager.saveQueue); } addCustomMetrics(); @@ -241,15 +301,15 @@ public void onReload(GameReloadEvent event) { public void reload() { // Load Plugin Config configManager.load(); - // Load Schematics Directory - SchematicArgument.load(); + // Load Schematics + schematicManager.load(); // Load Database - islands = database.loadData(); + IslandManager.ISLANDS = database.loadData(); // Reload Listeners Sponge.getEventManager().unregisterPluginListeners(this); registerListeners(); // Reload Tasks - Sponge.getScheduler().getTasksByName(cleanup).forEach(Task::cancel); + Sponge.getScheduler().getTasksByName(ISLAND_CLEANUP).forEach(Task::cancel); registerTasks(); // Reload Commands Sponge.getCommandManager().getOwnedBy(this).forEach(Sponge.getCommandManager()::removeMapping); @@ -272,8 +332,8 @@ private void registerListeners() { private void registerTasks() { if (getConfig().getExpirationConfig().isEnabled()) { Sponge.getScheduler().createTaskBuilder() - .name(cleanup) - .execute(new IslandCleanupTask(islands.values())) + .name(ISLAND_CLEANUP) + .execute(new IslandCleanupTask(IslandManager.ISLANDS.values())) .interval(getConfig().getExpirationConfig().getInterval(), TimeUnit.MINUTES) .async() .submit(this); @@ -282,11 +342,11 @@ private void registerTasks() { private void registerDebugCommands() { CommandVersion.register(); + CommandPlayerInfo.register(); } private void registerCommands() { CommandIsland.register(); - CommandAdmin.register(); } private IDatabase initializeDatabase() { @@ -301,8 +361,8 @@ private IDatabase initializeDatabase() { } private void addCustomMetrics() { - metrics.addCustomChart(new Metrics.SingleLineChart("islands", () -> islands.size())); - metrics.addCustomChart(new Metrics.DrilldownPie("sponge_version", () -> { + metrics.addCustomChart(new Metrics2.SingleLineChart("islands", () -> IslandManager.ISLANDS.size())); + metrics.addCustomChart(new Metrics2.DrilldownPie("sponge_version", () -> { Map> map = new HashMap<>(); String api = Sponge.getPlatform().getContainer(Platform.Component.API).getVersion().orElse("?").split("-")[0]; Map entry = new HashMap<>(); @@ -310,7 +370,7 @@ private void addCustomMetrics() { map.put(api, entry); return map; })); - metrics.addCustomChart(new Metrics.SimplePie("allocated_ram", () -> + metrics.addCustomChart(new Metrics2.SimplePie("allocated_ram", () -> String.format("%s GB", Math.round((Runtime.getRuntime().maxMemory() / 1024.0 / 1024.0 / 1024.0) * 2.0) / 2.0)) ); } @@ -331,6 +391,10 @@ public InviteService getInviteService() { return inviteService; } + public SchematicManager getSchematicManager() { + return schematicManager; + } + public Logger getLogger() { return logger; } @@ -355,7 +419,15 @@ public IDatabase getDatabase() { return database; } + public Optional getIslandManager(World world) { + return getIslandManager(world.getProperties()); + } + + public Optional getIslandManager(WorldProperties world) { + return Optional.ofNullable(islandManagers.get(world.getUniqueId())); + } + public void queueForSaving(Island island) { - saveQueue.add(island); + IslandManager.saveQueue.add(island); } } diff --git a/src/main/java/net/mohron/skyclaims/SkyClaimsTimings.java b/src/main/java/net/mohron/skyclaims/SkyClaimsTimings.java index 625791ed..34b3c56b 100644 --- a/src/main/java/net/mohron/skyclaims/SkyClaimsTimings.java +++ b/src/main/java/net/mohron/skyclaims/SkyClaimsTimings.java @@ -21,7 +21,10 @@ import co.aikar.timings.Timing; import co.aikar.timings.Timings; -public class SkyClaimsTimings { +public final class SkyClaimsTimings { + + private SkyClaimsTimings(){ + } // TASKS public static final Timing GENERATE_ISLAND = Timings.of(SkyClaims.getInstance().getPluginContainer(), "onGenerateIsland"); diff --git a/src/main/java/net/mohron/skyclaims/command/CommandAdmin.java b/src/main/java/net/mohron/skyclaims/command/CommandAdmin.java deleted file mode 100644 index 6b0e42ff..00000000 --- a/src/main/java/net/mohron/skyclaims/command/CommandAdmin.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SkyClaims - A Skyblock plugin made for Sponge - * Copyright (C) 2017 Mohron - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * SkyClaims is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with SkyClaims. If not, see . - */ - -package net.mohron.skyclaims.command; - -import static net.mohron.skyclaims.PluginInfo.NAME; -import static net.mohron.skyclaims.PluginInfo.VERSION; - -import com.google.common.collect.Lists; -import java.util.List; -import net.mohron.skyclaims.PluginInfo; -import net.mohron.skyclaims.command.admin.CommandCreateSchematic; -import net.mohron.skyclaims.command.admin.CommandReload; -import net.mohron.skyclaims.command.admin.CommandTransfer; -import net.mohron.skyclaims.permissions.Permissions; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.CommandException; -import org.spongepowered.api.command.CommandResult; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.args.CommandContext; -import org.spongepowered.api.command.args.GenericArguments; -import org.spongepowered.api.command.spec.CommandSpec; -import org.spongepowered.api.service.pagination.PaginationList; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.action.TextActions; -import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.text.format.TextStyles; -import org.spongepowered.api.util.annotation.NonnullByDefault; - -@NonnullByDefault -public class CommandAdmin extends CommandBase { - - public static final String HELP_TEXT = String - .format("use to run %s's admin commands or display help info", PluginInfo.NAME); - private static final Text HELP = Text.of("help"); - - public static void register() { - CommandSpec commandSpec = CommandSpec.builder() - .permission(Permissions.COMMAND_ADMIN) - .description(Text.of(HELP_TEXT)) - .child(CommandReload.commandSpec, "reload") - .child(CommandCreateSchematic.commandSpec, "createschematic", "cs") - .child(CommandTransfer.commandSpec, "transfer") - .childArgumentParseExceptionFallback(false) - .arguments(GenericArguments.optionalWeak(GenericArguments.onlyOne(GenericArguments.literal(HELP, "help")))) - .executor(new CommandAdmin()) - .build(); - - try { - registerSubCommands(); - CommandIsland.addSubCommand(commandSpec, "admin"); - Sponge.getCommandManager().register(PLUGIN, commandSpec, PLUGIN.getConfig().getCommandConfig().getAdminAlias()); - PLUGIN.getLogger().debug("Registered command: CommandAdmin"); - } catch (UnsupportedOperationException e) { - PLUGIN.getLogger().error("Failed to register command: CommandAdmin", e); - } - } - - private static void registerSubCommands() { - CommandCreateSchematic.register(); - CommandReload.register(); - CommandTransfer.register(); - } - - public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { - net.mohron.skyclaims.config.type.CommandConfig config = PLUGIN.getConfig().getCommandConfig(); - List helpText = Lists.newArrayList(); - String alias = config.getAdminAlias().isEmpty() - ? config.getBaseAlias() + " admin " - : config.getAdminAlias().get(0) + " "; - boolean hasPerms = false; - - if (src.hasPermission(Permissions.COMMAND_CREATE_SCHEMATIC)) { - helpText.add(Text.of( - TextColors.AQUA, alias, "cs", - TextColors.GOLD, " ", - TextColors.DARK_GRAY, " - ", - TextColors.DARK_GREEN, CommandCreateSchematic.HELP_TEXT)); - hasPerms = true; - } - - if (src.hasPermission(Permissions.COMMAND_RELOAD)) { - helpText.add(Text.of( - TextColors.AQUA, Text.of(TextActions.runCommand("/" + alias + "reload"), alias, "reload"), - TextColors.DARK_GRAY, " - ", - TextColors.DARK_GREEN, CommandReload.HELP_TEXT)); - hasPerms = true; - } - - if (src.hasPermission(Permissions.COMMAND_TRANSFER)) { - helpText.add(Text.of( - TextColors.AQUA, alias, "transfer", - TextColors.GRAY, " [owner]", - TextColors.GOLD, " ", - TextColors.DARK_GRAY, " - ", - TextColors.DARK_GREEN, CommandTransfer.HELP_TEXT)); - hasPerms = true; - } - - if (hasPerms) { - PaginationList.builder() - .title(Text.of(TextColors.AQUA, NAME, " Admin Help")) - .padding(Text.of(TextColors.AQUA, TextStyles.STRIKETHROUGH, "-")) - .contents(helpText) - .sendTo(src); - } else { - src.sendMessage(Text.of(NAME + " " + VERSION)); - } - - return CommandResult.success(); - } -} diff --git a/src/main/java/net/mohron/skyclaims/command/CommandBase.java b/src/main/java/net/mohron/skyclaims/command/CommandBase.java index b261cfaa..d2707773 100644 --- a/src/main/java/net/mohron/skyclaims/command/CommandBase.java +++ b/src/main/java/net/mohron/skyclaims/command/CommandBase.java @@ -23,9 +23,15 @@ import java.util.Collection; import java.util.List; import java.util.UUID; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; +import net.mohron.skyclaims.schematic.SchematicUI; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandPermissionException; import org.spongepowered.api.command.CommandResult; @@ -33,62 +39,58 @@ import org.spongepowered.api.command.args.CommandContext; import org.spongepowered.api.command.spec.CommandExecutor; import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.entity.living.player.User; +import org.spongepowered.api.service.pagination.PaginationList; +import org.spongepowered.api.service.user.UserStorageService; import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; +import org.spongepowered.api.text.format.TextStyles; -@NonnullByDefault public abstract class CommandBase implements CommandExecutor { protected static final SkyClaims PLUGIN = SkyClaims.getInstance(); - public static abstract class IslandCommand extends CommandBase implements - CommandRequirement.RequiresPlayerIsland { + public abstract static class IslandCommand extends CommandBase implements CommandRequirement.RequiresPlayerIsland { protected static final Text ISLAND = Text.of("island"); @Override public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { if (!(src instanceof Player)) { - throw new CommandException( - Text.of(TextColors.RED, "This command can only be used by a player!")); + throw new CommandException(Text.of(TextColors.RED, "This command can only be used by a player!")); } if (!args.hasAny(ISLAND)) { return execute( (Player) src, - Island.get(((Player) src).getLocation()) - .orElseThrow(() -> new CommandException( - Text.of(TextColors.RED, "You must be on an island to use this command!"))), + IslandManager.get(((Player) src).getLocation()).orElseThrow(() -> new CommandException(Text.of( + TextColors.RED, "You must be on an island to use this command!") + )), args); } else { List islands = Lists.newArrayList(); - args.getAll(ISLAND).forEach(i -> Island.get(i).ifPresent(islands::add)); + args.getAll(ISLAND).forEach(i -> IslandManager.get(i).ifPresent(islands::add)); if (islands.size() == 1) { return execute((Player) src, islands.get(0), args); } else { - throw new CommandException( - Text.of(TextColors.RED, "Multiple island support not yet implemented!") - ); + throw new CommandException(Text.of(TextColors.RED, "Multiple island support not yet implemented!")); } } } } - public static abstract class PlayerCommand extends CommandBase implements - CommandRequirement.RequiresPlayer { + public abstract static class PlayerCommand extends CommandBase implements CommandRequirement.RequiresPlayer { @Override public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { if (src instanceof Player) { return execute((Player) src, args); } - throw new CommandException( - Text.of(TextColors.RED, "This command can only be used by a player!")); + throw new CommandException(Text.of(TextColors.RED, "This command can only be used by a player!")); } } - public static abstract class LockCommand extends CommandBase implements - CommandRequirement.RequiresIsland { + public abstract static class LockCommand extends CommandBase implements CommandRequirement.RequiresIsland { private boolean lock; @@ -106,20 +108,17 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm } if (!args.hasAny(ISLAND)) { if (src instanceof Player) { - Island island = Island.get(((Player) src).getLocation()) - .orElseThrow(() -> new CommandException(Text.of( - TextColors.RED, - "You must either provide an island argument or be on an island to use this command!" - ))); + Island island = IslandManager.get(((Player) src).getLocation()).orElseThrow(() -> new CommandException( + Text.of(TextColors.RED, "You must provide an island argument or be on an island to use this command!") + )); checkPerms(src, island); return execute(src, island, args); } else { - throw new CommandException(Text.of(TextColors.RED, - "An island argument is required when executed by a non-player!")); + throw new CommandException(Text.of(TextColors.RED, "An island argument is required when executed by a non-player!")); } } else { List islands = Lists.newArrayList(); - args.getAll(ISLAND).forEach(i -> Island.get(i).ifPresent(islands::add)); + args.getAll(ISLAND).forEach(i -> IslandManager.get(i).ifPresent(islands::add)); if (islands.size() == 1) { checkPerms(src, islands.get(0)); return execute(src, islands.get(0), args); @@ -142,7 +141,7 @@ private void checkPerms(CommandSource src, Island island) throws CommandPermissi private CommandResult lockIslands(CommandSource src, Collection islandsIds) { ArrayList islands = Lists.newArrayList(); - islandsIds.forEach(i -> Island.get(i).ifPresent(islands::add)); + islandsIds.forEach(i -> IslandManager.get(i).ifPresent(islands::add)); islands.forEach(island -> { island.setLocked(lock); src.sendMessage(Text.of( @@ -155,13 +154,74 @@ private CommandResult lockIslands(CommandSource src, Collection islandsIds } private CommandResult lockAll(CommandSource src) { - SkyClaims.islands.values().forEach(i -> i.setLocked(lock)); + IslandManager.ISLANDS.values().forEach(i -> i.setLocked(lock)); src.sendMessage(Text.of( - TextColors.DARK_PURPLE, SkyClaims.islands.size(), + TextColors.DARK_PURPLE, IslandManager.ISLANDS.size(), TextColors.GREEN, " islands have been ", lock ? "locked" : "unlocked", "!" )); return CommandResult.success(); } } + + public abstract static class ListSchematicCommand extends PlayerCommand implements CommandRequirement.RequiresPlayer { + + protected static final Text SCHEMATIC = Text.of("schematic"); + + protected CommandResult listSchematics(Player player, Function> mapper) throws CommandException { + boolean checkPerms = PLUGIN.getConfig().getPermissionConfig().isSeparateSchematicPerms(); + + List schematics = PLUGIN.getSchematicManager().getSchematics().stream() + .filter(s -> !checkPerms || player.hasPermission(Permissions.COMMAND_ARGUMENTS_SCHEMATICS + "." + s.getName())) + .collect(Collectors.toList()); + + if (schematics.isEmpty()) { + throw new CommandException(Text.of(TextColors.RED, "You have no schematics available!")); + } + if (schematics.size() == 1) { + mapper.apply(schematics.get(0)); + return CommandResult.empty(); + } + + if (PLUGIN.getConfig().getMiscConfig().isTextSchematicList()) { + List schematicText = schematics.stream() + .map(s -> s.getText().toBuilder().onClick(TextActions.executeCallback(mapper.apply(s))).build()) + .collect(Collectors.toList()); + + PaginationList.builder() + .title(Text.of(TextColors.AQUA, "Schematics")) + .padding(Text.of(TextColors.AQUA, TextStyles.STRIKETHROUGH, "-")) + .contents(schematicText) + .sendTo(player); + + return CommandResult.empty(); + } + + player.openInventory(SchematicUI.of(schematics, mapper)); + return CommandResult.empty(); + } + } + + protected void clearIslandMemberInventories(Island island, String keepPlayerInv, String keepEnderChestInv) { + UserStorageService uss = PLUGIN.getGame().getServiceManager().provideUnchecked(UserStorageService.class); + + // Clear the owner's inventory, if enabled + uss.get(island.getOwnerUniqueId()).ifPresent(o -> clearMemberInventory(o, keepPlayerInv, keepEnderChestInv)); + // Clear each member's inventory, if enabled + for (User user : island.getMembers()) { + clearMemberInventory(user, keepPlayerInv, keepEnderChestInv); + } + } + + protected void clearMemberInventory(User member, String keepPlayerInv, String keepEnderChestInv) { + // Check if the player is exempt from having their inventory cleared + if (!member.hasPermission(keepPlayerInv)) { + PLUGIN.getLogger().debug("Clearing {}'s player inventory.", member.getName()); + member.getInventory().clear(); + } + if (!member.hasPermission(keepEnderChestInv)) { + PLUGIN.getLogger().debug("Clearing {}'s ender chest inventory.", member.getName()); + member.getEnderChestInventory().clear(); + } + } } diff --git a/src/main/java/net/mohron/skyclaims/command/CommandIsland.java b/src/main/java/net/mohron/skyclaims/command/CommandIsland.java index 9929c4b3..a4e230d7 100644 --- a/src/main/java/net/mohron/skyclaims/command/CommandIsland.java +++ b/src/main/java/net/mohron/skyclaims/command/CommandIsland.java @@ -22,13 +22,18 @@ import static net.mohron.skyclaims.PluginInfo.VERSION; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import java.net.MalformedURLException; import java.net.URL; +import java.util.Iterator; import java.util.List; import java.util.Map; -import net.mohron.skyclaims.PluginInfo; +import net.mohron.skyclaims.command.admin.CommandReload; +import net.mohron.skyclaims.command.admin.CommandTransfer; +import net.mohron.skyclaims.command.argument.IslandSortType; +import net.mohron.skyclaims.command.schematic.CommandSchematic; import net.mohron.skyclaims.command.team.CommandDemote; import net.mohron.skyclaims.command.team.CommandInvite; import net.mohron.skyclaims.command.team.CommandKick; @@ -36,18 +41,21 @@ import net.mohron.skyclaims.command.team.CommandPromote; import net.mohron.skyclaims.command.user.CommandCreate; import net.mohron.skyclaims.command.user.CommandDelete; +import net.mohron.skyclaims.command.user.CommandEntityInfo; import net.mohron.skyclaims.command.user.CommandExpand; import net.mohron.skyclaims.command.user.CommandInfo; import net.mohron.skyclaims.command.user.CommandList; import net.mohron.skyclaims.command.user.CommandLock; import net.mohron.skyclaims.command.user.CommandReset; import net.mohron.skyclaims.command.user.CommandSetBiome; +import net.mohron.skyclaims.command.user.CommandSetName; import net.mohron.skyclaims.command.user.CommandSetSpawn; import net.mohron.skyclaims.command.user.CommandSpawn; import net.mohron.skyclaims.command.user.CommandUnlock; import net.mohron.skyclaims.integration.nucleus.CommandHome; import net.mohron.skyclaims.integration.nucleus.CommandSetHome; import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.team.PrivilegeType; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandCallable; import org.spongepowered.api.command.CommandException; @@ -62,13 +70,10 @@ import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.text.format.TextStyles; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandIsland extends CommandBase { - private static final String HELP_TEXT = String - .format("use to run %s's subcommands or display command help info.", PluginInfo.NAME); + private static final String HELP_TEXT = "use to run SkyClaim's subcommands or display command help info."; private static final Text HELP = Text.of("help"); private static final Map, CommandCallable> children = Maps.newHashMap(); @@ -103,6 +108,7 @@ public static void clearSubCommands() { private static void registerSubCommands() { CommandCreate.register(); CommandDelete.register(); + CommandEntityInfo.register(); CommandDemote.register(); CommandExpand.register(); CommandInfo.register(); @@ -112,10 +118,14 @@ private static void registerSubCommands() { CommandList.register(); CommandLock.register(); CommandPromote.register(); + CommandReload.register(); CommandReset.register(); + CommandSchematic.register(); CommandSetBiome.register(); + CommandSetName.register(); CommandSetSpawn.register(); CommandSpawn.register(); + CommandTransfer.register(); CommandUnlock.register(); } @@ -148,12 +158,21 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm )); } + if (src.hasPermission(Permissions.COMMAND_ENTITY_INFO)) { + helpText.add(Text.of( + TextColors.AQUA, Text.builder(alias + "entity").onClick(TextActions.runCommand("/" + alias + "entity")), + TextColors.GRAY, " [island]", + TextColors.DARK_GRAY, " - ", + TextColors.DARK_GREEN, CommandEntityInfo.HELP_TEXT + )); + } + if (src.hasPermission(Permissions.COMMAND_EXPAND)) { helpText.add(Text.of( TextColors.AQUA, Text.builder(alias + "expand") .onClick(TextActions.suggestCommand("/" + alias + "expand ")), TextColors.GRAY, " [island]", - TextColors.GRAY, " ", + TextColors.GOLD, " ", TextColors.DARK_GRAY, " - ", TextColors.DARK_GREEN, CommandExpand.HELP_TEXT )); @@ -205,7 +224,8 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm TextColors.AQUA, Text.builder(alias + "invite").onClick(TextActions.runCommand("/" + alias + "invite")), TextColors.GRAY, " [user]", - TextColors.GRAY, " [privilege]", + TextColors.GRAY, Text.builder(" [privilege]") + .onHover(TextActions.showText(getTextFromEnum(PrivilegeType.class))), TextColors.DARK_GRAY, " - ", TextColors.DARK_GREEN, CommandInvite.HELP_TEXT )); @@ -235,7 +255,10 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm TextColors.AQUA, Text.builder(alias + "list").onClick(TextActions.runCommand("/" + alias + "list")), TextColors.GRAY, " [island]", - TextColors.GRAY, Text.builder(" [sort]").onHover(TextActions.showText(getSortOptions())), + TextColors.GRAY, Text.builder(" [sort type]") + .onHover(TextActions.showText(getTextFromEnum(IslandSortType.class))), + TextColors.GRAY, Text.builder(" [sort order]") + .onHover(TextActions.showText(getTextFromEnum(IslandSortType.Order.class))), TextColors.DARK_GRAY, " - ", TextColors.DARK_GREEN, CommandList.HELP_TEXT )); @@ -262,6 +285,13 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm )); } + if (src.hasPermission(Permissions.COMMAND_RELOAD)) { + helpText.add(Text.of( + TextColors.AQUA, Text.of(TextActions.runCommand("/" + alias + "reload"), alias, "reload"), + TextColors.DARK_GRAY, " - ", + TextColors.DARK_GREEN, CommandReload.HELP_TEXT)); + } + if (src.hasPermission(Permissions.COMMAND_RESET)) { helpText.add(Text.of( TextColors.AQUA, @@ -274,6 +304,15 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm )); } + if (src.hasPermission(Permissions.COMMAND_SCHEMATIC)) { + helpText.add(Text.of( + TextColors.AQUA, alias, "schematic", + TextColors.GRAY, Text.builder(" [sub command]") + .onHover(TextActions.showText(Text.of("list, command, create, delete, info, setbiome, sethieght, seticon, setname, setpreset"))), + TextColors.DARK_GRAY, " - ", + TextColors.DARK_GREEN, CommandSchematic.HELP_TEXT)); + } + if (src.hasPermission(Permissions.COMMAND_SET_BIOME)) { helpText.add(Text.of( TextColors.AQUA, Text.builder(alias + "setbiome") @@ -285,6 +324,16 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm )); } + if (src.hasPermission(Permissions.COMMAND_SET_NAME)) { + helpText.add(Text.of( + TextColors.AQUA, Text.builder(alias + "setname") + .onClick(TextActions.suggestCommand("/" + alias + "setname ")), + TextColors.GRAY, " [name]", + TextColors.DARK_GRAY, " - ", + TextColors.DARK_GREEN, CommandSetName.HELP_TEXT + )); + } + if (src.hasPermission(Permissions.COMMAND_SET_HOME)) { helpText.add(Text.of( TextColors.AQUA, @@ -313,6 +362,15 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm )); } + if (src.hasPermission(Permissions.COMMAND_TRANSFER)) { + helpText.add(Text.of( + TextColors.AQUA, alias, "transfer", + TextColors.GRAY, " [owner]", + TextColors.GOLD, " ", + TextColors.DARK_GRAY, " - ", + TextColors.DARK_GREEN, CommandTransfer.HELP_TEXT)); + } + if (src.hasPermission(Permissions.COMMAND_LOCK)) { helpText.add(Text.of( TextColors.AQUA, @@ -342,15 +400,16 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm return CommandResult.success(); } - private Text getSortOptions() { - return Text.of( - TextColors.GREEN, "ascending ", TextColors.RED, "descending", Text.NEW_LINE, - TextColors.GREEN, "newest ", TextColors.RED, "oldest", Text.NEW_LINE, - TextColors.GREEN, "active ", TextColors.RED, "inactive", Text.NEW_LINE, - TextColors.GREEN, "team+ ", TextColors.RED, "team-", Text.NEW_LINE, - TextColors.GREEN, "largest ", TextColors.RED, "smallest", Text.NEW_LINE, - TextColors.GREEN, "entities+ ", TextColors.RED, "entities-", Text.NEW_LINE, - TextColors.GREEN, "tile+ ", TextColors.RED, "tile-", Text.NEW_LINE - ); + private Text getTextFromEnum(Class e) { + Text.Builder builder = Text.builder(); + Iterator it = Iterators.forArray(e.getEnumConstants()); + while (it.hasNext()) { + builder.append(Text.of(it.next())); + if (it.hasNext()) { + builder.append(Text.of(", ")); + } + } + + return builder.build(); } } diff --git a/src/main/java/net/mohron/skyclaims/command/CommandRequirement.java b/src/main/java/net/mohron/skyclaims/command/CommandRequirement.java index 00666fa8..ff497b38 100644 --- a/src/main/java/net/mohron/skyclaims/command/CommandRequirement.java +++ b/src/main/java/net/mohron/skyclaims/command/CommandRequirement.java @@ -32,8 +32,7 @@ public interface CommandRequirement extends CommandExecutor { interface RequiresIsland { - CommandResult execute(CommandSource src, Island island, CommandContext args) - throws CommandException; + CommandResult execute(CommandSource src, Island island, CommandContext args) throws CommandException; } interface RequiresPlayer { @@ -43,8 +42,7 @@ interface RequiresPlayer { interface RequiresPlayerIsland { - CommandResult execute(Player player, Island island, CommandContext args) - throws CommandException; + CommandResult execute(Player player, Island island, CommandContext args) throws CommandException; } } diff --git a/src/main/java/net/mohron/skyclaims/command/admin/CommandReload.java b/src/main/java/net/mohron/skyclaims/command/admin/CommandReload.java index f5fcd009..ba1d14b8 100644 --- a/src/main/java/net/mohron/skyclaims/command/admin/CommandReload.java +++ b/src/main/java/net/mohron/skyclaims/command/admin/CommandReload.java @@ -19,6 +19,7 @@ package net.mohron.skyclaims.command.admin; import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.CommandIsland; import net.mohron.skyclaims.permissions.Permissions; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; @@ -27,9 +28,7 @@ import org.spongepowered.api.command.spec.CommandSpec; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandReload extends CommandBase { public static final String HELP_TEXT = "used to reload SkyClaims's config, schematics, & database."; @@ -42,6 +41,7 @@ public class CommandReload extends CommandBase { public static void register() { try { + CommandIsland.addSubCommand(commandSpec, "reload"); PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); PLUGIN.getLogger().debug("Registered command: CommandReload"); } catch (UnsupportedOperationException e) { diff --git a/src/main/java/net/mohron/skyclaims/command/admin/CommandTransfer.java b/src/main/java/net/mohron/skyclaims/command/admin/CommandTransfer.java index e9cb8678..887c7678 100644 --- a/src/main/java/net/mohron/skyclaims/command/admin/CommandTransfer.java +++ b/src/main/java/net/mohron/skyclaims/command/admin/CommandTransfer.java @@ -19,9 +19,11 @@ package net.mohron.skyclaims.command.admin; import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.CommandIsland; import net.mohron.skyclaims.command.argument.Arguments; import net.mohron.skyclaims.permissions.Permissions; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; @@ -31,9 +33,7 @@ import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandTransfer extends CommandBase { public static final String HELP_TEXT = "used to transfer island ownership to another player."; @@ -49,6 +49,7 @@ public class CommandTransfer extends CommandBase { public static void register() { try { + CommandIsland.addSubCommand(commandSpec, "transfer"); PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); PLUGIN.getLogger().debug("Registered command: CommandTransfer"); } catch (UnsupportedOperationException e) { @@ -63,7 +64,7 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm User user = args.getOne(USER) .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "Invalid user!"))); - if (owner != null && Island.getTotalIslandsOwned(owner.getUniqueId()) > 1) { + if (owner != null && IslandManager.getTotalIslandsOwned(owner.getUniqueId()) > 1) { throw new CommandException(Text.of( TextColors.RED, "The owner supplied has multiple islands. Please go to the island you want to transfer." @@ -75,14 +76,14 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm throw new CommandException( Text.of(TextColors.RED, "You must supply a owner & user to use this command.")); } - island = Island.getByOwner(owner.getUniqueId()) + island = IslandManager.getByOwner(owner.getUniqueId()) .orElseThrow(() -> new CommandException( Text.of(TextColors.RED, "The owner supplied must have an island!"))); } else { - island = (owner != null) ? Island.getByOwner(owner.getUniqueId()) + island = (owner != null) ? IslandManager.getByOwner(owner.getUniqueId()) .orElseThrow(() -> new CommandException( Text.of(TextColors.RED, "The owner supplied must have an island!"))) - : Island.get(((Player) src).getLocation()) + : IslandManager.get(((Player) src).getLocation()) .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "This command must be run on the island you wish to transfer!"))); } diff --git a/src/main/java/net/mohron/skyclaims/command/admin/package-info.java b/src/main/java/net/mohron/skyclaims/command/admin/package-info.java new file mode 100644 index 00000000..fb00ad3c --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/admin/package-info.java @@ -0,0 +1,21 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ +@NonnullByDefault +package net.mohron.skyclaims.command.admin; + +import org.spongepowered.api.util.annotation.NonnullByDefault; \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/command/argument/Arguments.java b/src/main/java/net/mohron/skyclaims/command/argument/Arguments.java index e7fef4ca..8c52ad12 100644 --- a/src/main/java/net/mohron/skyclaims/command/argument/Arguments.java +++ b/src/main/java/net/mohron/skyclaims/command/argument/Arguments.java @@ -21,7 +21,10 @@ import net.mohron.skyclaims.team.PrivilegeType; import org.spongepowered.api.text.Text; -public class Arguments { +public final class Arguments { + + private Arguments() { + } public static BiomeArgument biome(Text key) { return new BiomeArgument(key); @@ -43,10 +46,6 @@ public static SchematicArgument schematic(Text key) { return new SchematicArgument(key); } - public static SortArgument sort(Text key) { - return new SortArgument(key); - } - public static TargetArgument target(Text key) { return new TargetArgument(key); } diff --git a/src/main/java/net/mohron/skyclaims/command/argument/BiomeArgument.java b/src/main/java/net/mohron/skyclaims/command/argument/BiomeArgument.java index 5212f30c..8597c8a2 100644 --- a/src/main/java/net/mohron/skyclaims/command/argument/BiomeArgument.java +++ b/src/main/java/net/mohron/skyclaims/command/argument/BiomeArgument.java @@ -34,10 +34,8 @@ import org.spongepowered.api.command.args.CommandElement; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; import org.spongepowered.api.world.biome.BiomeType; -@NonnullByDefault public class BiomeArgument extends CommandElement { public static final List BIOMES; @@ -62,12 +60,24 @@ public BiomeArgument(@Nullable Text key) { @Override protected Object parseValue(CommandSource src, CommandArgs args) throws ArgumentParseException { String arg = args.next().toLowerCase(); - BiomeType biomeType = BIOMES.stream().filter(b -> b.getId().contains(arg)).findAny().orElse(null); - if (biomeType != null) { - if (PLUGIN.getConfig().getPermissionConfig().isSeparateBiomePerms() && !src.hasPermission(getPermission(biomeType))) { - throw args.createError(Text.of(TextColors.RED, "You do not have permission to use the supplied biome type.")); + boolean checkPerms = PLUGIN.getConfig().getPermissionConfig().isSeparateBiomePerms(); + List biomeList = BIOMES.stream() + .filter(b -> b.getId().startsWith(arg) || b.getId().startsWith("minecraft:" + arg)) + .collect(Collectors.toList()); + + if (!biomeList.isEmpty()) { + if (biomeList.size() == 1) { + if (checkPerms && !src.hasPermission(getPermission(biomeList.get(0)))) { + throw args.createError(Text.of(TextColors.RED, "You do not have permission to use the supplied biome type.")); + } + return biomeList.get(0); + } else { + return biomeList.stream() + .filter(b -> (b.getId().equalsIgnoreCase(arg) || b.getId().equalsIgnoreCase("minecraft:" + arg)) + && (!checkPerms || src.hasPermission(getPermission(b)))) + .findAny() + .orElseThrow(() -> args.createError(Text.of(TextColors.RED, "More that one biome found for ", arg, "."))); } - return biomeType; } throw args.createError(Text.of(TextColors.RED, "Invalid biome type.")); } diff --git a/src/main/java/net/mohron/skyclaims/command/argument/IslandArgument.java b/src/main/java/net/mohron/skyclaims/command/argument/IslandArgument.java index 7e370810..3b27da66 100644 --- a/src/main/java/net/mohron/skyclaims/command/argument/IslandArgument.java +++ b/src/main/java/net/mohron/skyclaims/command/argument/IslandArgument.java @@ -26,10 +26,10 @@ import java.util.UUID; import java.util.stream.Collectors; import javax.annotation.Nullable; -import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.permissions.Permissions; import net.mohron.skyclaims.team.PrivilegeType; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.command.args.ArgumentParseException; import org.spongepowered.api.command.args.CommandArgs; @@ -38,9 +38,7 @@ import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class IslandArgument extends CommandElement { private PrivilegeType requirement; @@ -58,17 +56,17 @@ public IslandArgument(@Nullable Text key, PrivilegeType requiredPrivilege) { protected Object parseValue(CommandSource source, CommandArgs args) throws ArgumentParseException { String arg = args.next().toLowerCase(); - if (SkyClaims.islands.isEmpty()) { + if (IslandManager.ISLANDS.isEmpty()) { throw args.createError(Text.of(TextColors.RED, "There are no valid islands!")); } try { UUID uuid = UUID.fromString(arg); - if (SkyClaims.islands.containsKey(uuid)) { + if (IslandManager.ISLANDS.containsKey(uuid)) { return Sets.newHashSet(uuid); } } catch (IllegalArgumentException ignored) { } - Set islands = SkyClaims.islands.entrySet().stream() + Set islands = IslandManager.ISLANDS.entrySet().stream() .filter(i -> i.getValue().getOwnerName().equalsIgnoreCase(arg)) .map(Map.Entry::getKey) .collect(Collectors.toSet()); @@ -83,7 +81,7 @@ public List complete(CommandSource src, CommandArgs args, CommandContext try { String arg = args.peek().toLowerCase(); boolean admin = src.hasPermission(Permissions.COMMAND_LIST_ALL); - return SkyClaims.islands.values().stream() + return IslandManager.ISLANDS.values().stream() .filter(i -> admin || src instanceof Player && i.getPrivilegeType((Player) src) == requirement) .filter(i -> i.getOwnerName().toLowerCase().startsWith(arg)) diff --git a/src/main/java/net/mohron/skyclaims/command/argument/IslandSortType.java b/src/main/java/net/mohron/skyclaims/command/argument/IslandSortType.java new file mode 100644 index 00000000..e33333ce --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/argument/IslandSortType.java @@ -0,0 +1,103 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.argument; + +import java.util.Comparator; +import java.util.function.Function; +import net.mohron.skyclaims.world.Island; +import org.spongepowered.api.data.key.Keys; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.action.TextActions; +import org.spongepowered.api.text.format.TextColors; + +public enum IslandSortType { + NONE(Order.ASC), + NAME(Order.ASC), + CREATED(Order.ASC), + ONLINE(Order.DESC), + ACTIVE(Order.DESC), + MEMBERS(Order.DESC), + SIZE(Order.DESC), + ENTITIES(Order.DESC), + TILES(Order.DESC); + + private final Order order; + + IslandSortType(Order order) { + this.order = order; + } + + public enum Order { + ASC, DESC; + + public Comparator getComparator() { + switch (this) { + case DESC: + return Comparator.reverseOrder(); + case ASC: + default: + return Comparator.naturalOrder(); + } + } + + public Text toText() { + switch (this) { + case DESC: + return Text.builder("▼") + .color(TextColors.GRAY) + .onHover(TextActions.showText(Text.of("Descending"))) + .build(); + case ASC: + default: + return Text.builder("▲") + .color(TextColors.GRAY) + .onHover(TextActions.showText(Text.of("Ascending"))) + .build(); + } + } + } + + public Order getOrder() { + return order; + } + + public Function getSortFunction() { + switch (this) { + case CREATED: + return Island::getDateCreated; + case ONLINE: + return i -> i.getMembers().stream() + .anyMatch(user -> user.isOnline() && !user.get(Keys.VANISH).orElse(false)); + case ACTIVE: + return Island::getDateLastActive; + case MEMBERS: + return Island::getTotalMembers; + case SIZE: + return Island::getWidth; + case ENTITIES: + return Island::getTotalEntities; + case TILES: + return Island::getTotalTileEntities; + case NAME: + case NONE: + default: + return Island::getSortableName; + } + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/argument/SchematicArgument.java b/src/main/java/net/mohron/skyclaims/command/argument/SchematicArgument.java index 4e8b22ca..3e3febd5 100644 --- a/src/main/java/net/mohron/skyclaims/command/argument/SchematicArgument.java +++ b/src/main/java/net/mohron/skyclaims/command/argument/SchematicArgument.java @@ -19,14 +19,13 @@ package net.mohron.skyclaims.command.argument; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import java.io.File; import java.util.List; -import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import javax.annotation.Nullable; import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.command.args.ArgumentParseException; import org.spongepowered.api.command.args.CommandArgs; @@ -34,69 +33,41 @@ import org.spongepowered.api.command.args.CommandElement; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class SchematicArgument extends CommandElement { - public static final Map SCHEMATICS = Maps.newHashMap(); private static final SkyClaims PLUGIN = SkyClaims.getInstance(); - static { - load(); - } - public SchematicArgument(@Nullable Text key) { super(key); } - @SuppressWarnings("ConstantConditions") - public static void load() { - SchematicArgument.SCHEMATICS.clear(); - File schemDir = new File(PLUGIN.getConfigDir() + File.separator + "schematics"); - try { - PLUGIN.getLogger().debug("Attempting to retrieve all schematics!"); - for (File file : schemDir.listFiles()) { - PLUGIN.getLogger().debug("Found File: " + file); - String schem = file.getName(); - if (schem.endsWith(".schematic")) { - SchematicArgument.SCHEMATICS - .put(schem.replace(".schematic", "").toLowerCase(), schem.replace(".schematic", "")); - PLUGIN.getLogger().debug("Added Schematic: " + schem); - } - } - } catch (NullPointerException e) { - PLUGIN.getLogger().error("Failed to read schematics directory!"); - } - } - @Nullable @Override - protected Object parseValue(CommandSource source, CommandArgs args) - throws ArgumentParseException { + protected IslandSchematic parseValue(CommandSource source, CommandArgs args) throws ArgumentParseException { String schem = args.next().toLowerCase(); - if (SCHEMATICS.isEmpty()) { - throw new ArgumentParseException( - Text.of(TextColors.RED, "There are no valid schematics available!"), schem, 0); + if (PLUGIN.getSchematicManager().getSchematics().isEmpty()) { + throw args.createError(Text.of(TextColors.RED, "There are no valid schematics available!")); } - if (SCHEMATICS.containsKey(schem)) { - if (!hasPermission(source, schem)) { - throw new ArgumentParseException( - Text.of(TextColors.RED, "You do not have permission to use the supplied schematic!"), - schem, 0); + Optional schematic = PLUGIN.getSchematicManager().getSchematics().stream().filter(s -> s.getName().equalsIgnoreCase(schem)).findAny(); + if (schematic.isPresent()) { + if (PLUGIN.getConfig().getPermissionConfig().isSeparateSchematicPerms() && !hasPermission(source, schem)) { + throw args.createError(Text.of(TextColors.RED, "You do not have permission to use the supplied schematic!")); } - return SCHEMATICS.get(schem); + return schematic.get(); } - throw new ArgumentParseException(Text.of(TextColors.RED, "Invalid Schematic!"), schem, 0); + throw args.createError(Text.of(TextColors.RED, "Invalid Schematic!")); } @Override public List complete(CommandSource src, CommandArgs args, CommandContext context) { try { String name = args.peek().toLowerCase(); - return SCHEMATICS.keySet().stream() - .filter(s -> s.startsWith(name)) - .filter(s -> hasPermission(src, s)) + boolean checkPerms = PLUGIN.getConfig().getPermissionConfig().isSeparateSchematicPerms(); + return PLUGIN.getSchematicManager().getSchematics().stream() + .filter(s -> s.getName().startsWith(name)) + .filter(s -> !checkPerms || hasPermission(src, s.getName())) + .map(IslandSchematic::getName) .collect(Collectors.toList()); } catch (ArgumentParseException e) { return Lists.newArrayList(); @@ -104,8 +75,6 @@ public List complete(CommandSource src, CommandArgs args, CommandContext } private boolean hasPermission(CommandSource src, String name) { - boolean checkPerms = PLUGIN.getConfig().getPermissionConfig().isSeparateSchematicPerms(); - return !checkPerms || src - .hasPermission(Permissions.COMMAND_ARGUMENTS_SCHEMATICS + "." + name.toLowerCase()); + return src.hasPermission(Permissions.COMMAND_ARGUMENTS_SCHEMATICS + "." + name.toLowerCase()); } } \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/command/argument/SortArgument.java b/src/main/java/net/mohron/skyclaims/command/argument/SortArgument.java deleted file mode 100644 index bac1d134..00000000 --- a/src/main/java/net/mohron/skyclaims/command/argument/SortArgument.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SkyClaims - A Skyblock plugin made for Sponge - * Copyright (C) 2017 Mohron - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * SkyClaims is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with SkyClaims. If not, see . - */ - -package net.mohron.skyclaims.command.argument; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import net.mohron.skyclaims.world.Island; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.args.ArgumentParseException; -import org.spongepowered.api.command.args.CommandArgs; -import org.spongepowered.api.command.args.CommandContext; -import org.spongepowered.api.command.args.CommandElement; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; - -@NonnullByDefault -public class SortArgument extends CommandElement { - - public static final Map> SORT_TYPES = Maps.newHashMap(); - - static { - SORT_TYPES.put("ascending", Comparator.comparing(Island::getSortableName)); - SORT_TYPES.put("descending", Comparator.comparing(Island::getSortableName).reversed()); - SORT_TYPES.put("oldest", Comparator.comparing(Island::getDateCreated)); - SORT_TYPES.put("newest", Comparator.comparing(Island::getDateCreated).reversed()); - SORT_TYPES.put("inactive", Comparator.comparing(Island::getDateLastActive)); - SORT_TYPES.put("active", Comparator.comparing(Island::getDateLastActive).reversed()); - SORT_TYPES.put("team-", Comparator.comparing(Island::getTotalMembers)); - SORT_TYPES.put("team+", Comparator.comparing(Island::getTotalMembers).reversed()); - SORT_TYPES.put("smallest", Comparator.comparing(Island::getWidth)); - SORT_TYPES.put("largest", Comparator.comparing(Island::getWidth).reversed()); - SORT_TYPES.put("entities-", Comparator.comparing(Island::getTotalEntities)); - SORT_TYPES.put("entities+", Comparator.comparing(Island::getTotalEntities).reversed()); - SORT_TYPES.put("tile-", Comparator.comparing(Island::getTotalTileEntities)); - SORT_TYPES.put("tile+", Comparator.comparing(Island::getTotalTileEntities).reversed()); - } - - public SortArgument(@Nullable Text key) { - super(key); - } - - @Nullable - @Override - protected Object parseValue(CommandSource source, CommandArgs args) - throws ArgumentParseException { - String arg = args.next().toLowerCase(); - if (SORT_TYPES.containsKey(arg)) { - return SORT_TYPES.get(arg); - } - throw new ArgumentParseException(Text.of(TextColors.RED, "Invalid sort type."), arg, 0); - } - - @Override - public List complete(CommandSource src, CommandArgs args, CommandContext context) { - try { - String name = args.peek().toLowerCase(); - return SORT_TYPES.keySet().stream() - .filter(s -> s.startsWith(name)) - .collect(Collectors.toList()); - } catch (ArgumentParseException e) { - return Lists.newArrayList(); - } - } -} diff --git a/src/main/java/net/mohron/skyclaims/command/argument/TargetArgument.java b/src/main/java/net/mohron/skyclaims/command/argument/TargetArgument.java index 567a654d..faa1c6dd 100644 --- a/src/main/java/net/mohron/skyclaims/command/argument/TargetArgument.java +++ b/src/main/java/net/mohron/skyclaims/command/argument/TargetArgument.java @@ -33,9 +33,7 @@ import org.spongepowered.api.command.args.CommandElement; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class TargetArgument extends CommandElement { private static final SkyClaims PLUGIN = SkyClaims.getInstance(); diff --git a/src/main/java/net/mohron/skyclaims/command/argument/TwoUserArgument.java b/src/main/java/net/mohron/skyclaims/command/argument/TwoUserArgument.java index a2bfed15..bcc09ec3 100644 --- a/src/main/java/net/mohron/skyclaims/command/argument/TwoUserArgument.java +++ b/src/main/java/net/mohron/skyclaims/command/argument/TwoUserArgument.java @@ -33,9 +33,7 @@ import org.spongepowered.api.profile.GameProfile; import org.spongepowered.api.service.user.UserStorageService; import org.spongepowered.api.text.Text; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class TwoUserArgument extends CommandElement { private final Text key; diff --git a/src/main/java/net/mohron/skyclaims/command/argument/package-info.java b/src/main/java/net/mohron/skyclaims/command/argument/package-info.java new file mode 100644 index 00000000..4f4493b2 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/argument/package-info.java @@ -0,0 +1,21 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ +@NonnullByDefault +package net.mohron.skyclaims.command.argument; + +import org.spongepowered.api.util.annotation.NonnullByDefault; \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/command/debug/CommandPlayerInfo.java b/src/main/java/net/mohron/skyclaims/command/debug/CommandPlayerInfo.java new file mode 100644 index 00000000..64db37de --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/debug/CommandPlayerInfo.java @@ -0,0 +1,109 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.debug; + +import com.google.common.collect.Lists; +import java.util.List; +import java.util.UUID; +import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.permissions.Options; +import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; +import org.spongepowered.api.CatalogType; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.args.GenericArguments; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.entity.living.player.User; +import org.spongepowered.api.service.pagination.PaginationList; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.action.TextActions; +import org.spongepowered.api.text.format.TextColor; +import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.text.format.TextStyles; + +public class CommandPlayerInfo extends CommandBase { + + public static final String HELP_TEXT = "display info about a player as SkyClaims sees it."; + private static final Text USER = Text.of("user"); + + public static void register() { + CommandSpec commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_PLAYER_INFO) + .description(Text.of(HELP_TEXT)) + .arguments(GenericArguments.optional(GenericArguments.user(USER))) + .executor(new CommandPlayerInfo()) + .build(); + + try { + PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec, "scplayerinfo"); + PLUGIN.getLogger().debug("Registered command: CommandPlayerInfo"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandPlayerInfo", e); + } + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + if (!args.hasAny(USER) && !(src instanceof Player)) { + throw new CommandException(Text.of(TextColors.RED, "You must provide a player argument to use this command!")); + } + User user = args.getOne(USER).orElse((User) src); + + PaginationList.builder() + .title(Text.of(TextColors.AQUA, user.getName(), "'s SkyClaims Info")) + .padding(Text.of(TextColors.AQUA, TextStyles.STRIKETHROUGH, "-")) + .contents(getUserInfo(user)) + .sendTo(src); + + return CommandResult.success(); + } + + private List getUserInfo(User user) { + final UUID uuid = user.getUniqueId(); + final List options = Lists.newArrayList(); + final Text defaultSchematic = Options.getDefaultSchematic(uuid).map(IslandSchematic::getText).orElse(Text.of("none")); + final String defaultBiome = Options.getDefaultBiome(uuid).map(CatalogType::getName).orElse("none"); + + options.add(getOptionText(Options.DEFAULT_SCHEMATIC, "Default Schematic", defaultSchematic)); + options.add(getOptionText(Options.DEFAULT_BIOME, "Default Biome", defaultBiome)); + options.add(getOptionText(Options.MIN_SIZE, "Minimum Size", Options.getMinSize(uuid) * 2)); + options.add(getOptionText(Options.MAX_SIZE, "Maximum Size", Options.getMaxSize(uuid) * 2)); + options.add(getOptionText(Options.MAX_SPAWNS, "Maximum Entity Spawns", Options.getMaxSpawns(uuid))); + options.add(getOptionText(Options.MAX_HOSTILE, "Maximum Hostile Spawns", Options.getMaxHostileSpawns(uuid))); + options.add(getOptionText(Options.MAX_PASSIVE, "Maximum Passive Spawns", Options.getMaxPassiveSpawns(uuid))); + options.add(getOptionText(Options.EXPIRATION, "Island Expiration (days)", Options.getExpiration(uuid))); + options.add(getOptionText(Options.MAX_ISLANDS, "Maximum Islands", Options.getMaxIslands(uuid))); + options.add(getOptionText(Options.MAX_TEAMMATES, "Maximum Teammates", Options.getMaxTeammates(uuid))); + + return options; + } + + private Text getOptionText(String option, String name, Object value) { + TextColor valueColor = value instanceof Integer ? TextColors.LIGHT_PURPLE : TextColors.GRAY; + return Text.of( + Text.builder(name).color(TextColors.YELLOW).onHover(TextActions.showText(Text.of(option))), + TextColors.WHITE, " : ", + valueColor, value + ); + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/debug/CommandVersion.java b/src/main/java/net/mohron/skyclaims/command/debug/CommandVersion.java index 3f950282..fb66a071 100644 --- a/src/main/java/net/mohron/skyclaims/command/debug/CommandVersion.java +++ b/src/main/java/net/mohron/skyclaims/command/debug/CommandVersion.java @@ -35,9 +35,7 @@ import org.spongepowered.api.service.permission.PermissionService; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandVersion extends CommandBase { public static final String HELP_TEXT = "used to view loaded config settings."; @@ -73,28 +71,19 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm TextColors.YELLOW, sponge.getName(), " ", sponge.getVersion().orElse("Unknown") )); // SkyClaims - texts.add(Text.of( - TextColors.DARK_AQUA, "SkyClaims", TextColors.WHITE, " : ", - TextColors.YELLOW, PluginInfo.VERSION - )); + texts.add(Text.of(TextColors.DARK_AQUA, "SkyClaims", TextColors.WHITE, " : ", TextColors.YELLOW, PluginInfo.VERSION)); // GriefPrevention String gp; try { - gp = (PLUGIN.getGriefPrevention() != null) ? PLUGIN.getGriefPrevention() - .getImplementationVersion() : "Error/Missing"; + gp = (PLUGIN.getGriefPrevention() != null) ? PLUGIN.getGriefPrevention().getImplementationVersion() : "Error/Missing"; } catch (Exception e) { PLUGIN.getLogger().error("Error getting Grief Prevention version.", e); Optional plugin = Sponge.getPluginManager().getPlugin("griefprevention"); - gp = plugin.map(pluginContainer -> pluginContainer.getVersion().get()) - .orElse("Error/Missing"); + gp = plugin.map(pluginContainer -> pluginContainer.getVersion().get()).orElse("Error/Missing"); } - texts.add(Text.of( - TextColors.DARK_AQUA, "Grief Prevention", TextColors.WHITE, " : ", - TextColors.YELLOW, gp - )); + texts.add(Text.of(TextColors.DARK_AQUA, "Grief Prevention", TextColors.WHITE, " : ", TextColors.YELLOW, gp)); // Permissions - PluginContainer perms = Sponge.getServiceManager().getRegistration(PermissionService.class) - .get().getPlugin(); + PluginContainer perms = Sponge.getServiceManager().getRegistration(PermissionService.class).get().getPlugin(); texts.add(Text.of( TextColors.DARK_AQUA, "Permissions", TextColors.WHITE, " : ", TextColors.YELLOW, perms.getName(), " ", perms.getVersion().orElse("Unknown") diff --git a/src/main/java/net/mohron/skyclaims/command/debug/package-info.java b/src/main/java/net/mohron/skyclaims/command/debug/package-info.java new file mode 100644 index 00000000..65b4f576 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/debug/package-info.java @@ -0,0 +1,21 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ +@NonnullByDefault +package net.mohron.skyclaims.command.debug; + +import org.spongepowered.api.util.annotation.NonnullByDefault; \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/command/package-info.java b/src/main/java/net/mohron/skyclaims/command/package-info.java new file mode 100644 index 00000000..eda75f76 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/package-info.java @@ -0,0 +1,21 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ +@NonnullByDefault +package net.mohron.skyclaims.command; + +import org.spongepowered.api.util.annotation.NonnullByDefault; \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematic.java b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematic.java new file mode 100644 index 00000000..95c41194 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematic.java @@ -0,0 +1,83 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.schematic; + +import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.CommandIsland; +import net.mohron.skyclaims.permissions.Permissions; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.text.Text; + +public class CommandSchematic extends CommandBase { + + public static final String HELP_TEXT = "used to manage island schematics"; + + public static CommandSpec commandSpec; + + public static void register() { + commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_SCHEMATIC) + .description(Text.of(HELP_TEXT)) + .child(CommandSchematicCommand.commandSpec, "command") + .child(CommandSchematicCreate.commandSpec, "create") + .child(CommandSchematicDelete.commandSpec, "delete") + .child(CommandSchematicInfo.commandSpec, "info") + .child(CommandSchematicList.commandSpec, "list") + .child(CommandSchematicSetBiome.commandSpec, "setbiome") + .child(CommandSchematicSetHeight.commandSpec, "setheight") + .child(CommandSchematicSetIcon.commandSpec, "seticon") + .child(CommandSchematicSetName.commandSpec, "setname") + .child(CommandSchematicSetPreset.commandSpec, "setpreset") + .childArgumentParseExceptionFallback(false) + .executor(new CommandSchematicList()) + .build(); + + try { + registerSubCommands(); + CommandIsland.addSubCommand(commandSpec, "schematic"); + Sponge.getCommandManager().register(PLUGIN, commandSpec); + PLUGIN.getLogger().debug("Registered command: CommandSchematic"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandSchematic", e); + } + } + + private static void registerSubCommands() { + CommandSchematicCommand.register(); + CommandSchematicCreate.register(); + CommandSchematicDelete.register(); + CommandSchematicInfo.register(); + CommandSchematicList.register(); + CommandSchematicSetBiome.register(); + CommandSchematicSetHeight.register(); + CommandSchematicSetIcon.register(); + CommandSchematicSetName.register(); + CommandSchematicSetPreset.register(); + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + return CommandResult.success(); + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicCommand.java b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicCommand.java new file mode 100644 index 00000000..f884e0b8 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicCommand.java @@ -0,0 +1,93 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.schematic; + +import java.util.List; +import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.argument.Arguments; +import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.args.GenericArguments; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColors; + +public class CommandSchematicCommand extends CommandBase { + + public static final String HELP_TEXT = "used to configure schematic commands"; + private static final Text SCHEMATIC = Text.of("schematic"); + private static final Text ACTION = Text.of("add|remove"); + private static final Text COMMAND = Text.of("command"); + + private enum Action { + add, remove + } + + public static CommandSpec commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_SCHEMATIC_COMMAND) + .description(Text.of(HELP_TEXT)) + .arguments( + Arguments.schematic(SCHEMATIC), + GenericArguments.enumValue(ACTION, Action.class), + GenericArguments.remainingJoinedStrings(COMMAND) + ) + .executor(new CommandSchematicCommand()) + .build(); + + public static void register() { + try { + PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); + PLUGIN.getLogger().debug("Registered command: CommandSchematicAddCommand"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandSchematicAddCommand", e); + } + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + IslandSchematic schematic = args.getOne(SCHEMATIC) + .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "You must provide a schematic argument to use this command!"))); + Action action = args.getOne(ACTION) + .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "You must provide an action argument to use this command!"))); + String command = args.getOne(COMMAND) + .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "You must provide a command argument to use this command!"))); + + List commands; + if (action == Action.add) { + commands = schematic.getCommands(); + commands.add(command); + schematic.setCommands(commands); + } else { + commands = schematic.getCommands(); + commands.remove(command); + schematic.setCommands(commands); + } + + if (PLUGIN.getSchematicManager().save(schematic)) { + src.sendMessage(Text.of(TextColors.GREEN, "Successfully updated schematic.")); + return CommandResult.success(); + } else { + throw new CommandException(Text.of(TextColors.RED, "Failed to update schematic.")); + } + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/admin/CommandCreateSchematic.java b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicCreate.java similarity index 62% rename from src/main/java/net/mohron/skyclaims/command/admin/CommandCreateSchematic.java rename to src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicCreate.java index cf79f941..280e81ee 100644 --- a/src/main/java/net/mohron/skyclaims/command/admin/CommandCreateSchematic.java +++ b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicCreate.java @@ -16,44 +16,36 @@ * along with SkyClaims. If not, see . */ -package net.mohron.skyclaims.command.admin; +package net.mohron.skyclaims.command.schematic; import static org.spongepowered.api.command.args.GenericArguments.string; import com.flowpowered.math.vector.Vector3i; -import java.io.File; -import java.io.FileOutputStream; -import java.util.zip.GZIPOutputStream; +import java.time.Instant; import net.mohron.skyclaims.command.CommandBase; -import net.mohron.skyclaims.command.argument.SchematicArgument; import net.mohron.skyclaims.listener.SchematicHandler; import net.mohron.skyclaims.permissions.Permissions; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.args.CommandContext; import org.spongepowered.api.command.spec.CommandSpec; -import org.spongepowered.api.data.DataContainer; -import org.spongepowered.api.data.persistence.DataFormats; -import org.spongepowered.api.data.persistence.DataTranslators; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; import org.spongepowered.api.world.extent.ArchetypeVolume; import org.spongepowered.api.world.schematic.BlockPaletteTypes; import org.spongepowered.api.world.schematic.Schematic; -@NonnullByDefault -public class CommandCreateSchematic extends CommandBase.PlayerCommand { +public class CommandSchematicCreate extends CommandBase.PlayerCommand { public static final String HELP_TEXT = "used to save the selected area as an island schematic"; private static final Text NAME = Text.of("name"); public static CommandSpec commandSpec = CommandSpec.builder() - .permission(Permissions.COMMAND_CREATE_SCHEMATIC) + .permission(Permissions.COMMAND_SCHEMATIC_CREATE) .description(Text.of(HELP_TEXT)) .arguments(string(NAME)) - .executor(new CommandCreateSchematic()) + .executor(new CommandSchematicCreate()) .build(); public static void register() { @@ -69,39 +61,34 @@ public static void register() { public CommandResult execute(Player player, CommandContext args) throws CommandException { SchematicHandler.PlayerData data = SchematicHandler.get(player); if (data.getPos1() == null || data.getPos2() == null) { - player.sendMessage(Text.of(TextColors.RED, "You must set both positions before copying.")); - return CommandResult.success(); + throw new CommandException(Text.of(TextColors.RED, "You must set both positions before copying.")); } Vector3i min = data.getPos1().min(data.getPos2()); Vector3i max = data.getPos1().max(data.getPos2()); - ArchetypeVolume volume = player.getWorld() - .createArchetypeVolume(min, max, player.getLocation().getPosition().toInt()); + ArchetypeVolume volume = player.getWorld().createArchetypeVolume(min, max, player.getLocation().getPosition().toInt()); String name = args.getOne(NAME) - .orElseThrow(() -> new CommandException( - Text.of(TextColors.RED, "You must supply a name to use this command!"))); + .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "You must supply a name to use this command!"))); Schematic schematic = Schematic.builder() .volume(volume) .metaValue(Schematic.METADATA_AUTHOR, player.getName()) .metaValue(Schematic.METADATA_NAME, name) + .metaValue(Schematic.METADATA_DATE, Instant.now().toString()) .paletteType(BlockPaletteTypes.LOCAL) .build(); - DataContainer schematicData = DataTranslators.SCHEMATIC.translate(schematic); - File outputFile = new File(PLUGIN.getConfigDir().toFile(), - String.format("schematics%s%s.schematic", File.separator, name.toLowerCase())); - try { - DataFormats.NBT - .writeTo(new GZIPOutputStream(new FileOutputStream(outputFile)), schematicData); - player.sendMessage( - Text.of(TextColors.GREEN, "Saved schematic to " + outputFile.getAbsolutePath())); - SchematicArgument.SCHEMATICS.put(name.toLowerCase(), name); - } catch (Exception e) { - e.printStackTrace(); - player.sendMessage(Text.of(TextColors.DARK_RED, "Error saving schematic: " + e.getMessage())); + if (PLUGIN.getSchematicManager().create(schematic, name)) { + player.sendMessage(Text.of(TextColors.GREEN, "Successfully created ", TextColors.WHITE, name, TextColors.GREEN, ".")); + if (PLUGIN.getConfig().getPermissionConfig().isSeparateSchematicPerms()){ + player.sendMessage(Text.of( + TextColors.GREEN, "Use ", TextColors.GRAY, Permissions.COMMAND_ARGUMENTS_SCHEMATICS, ".", name, + TextColors.GREEN, " to give permission to use." + )); + } return CommandResult.success(); + } else { + throw new CommandException(Text.of(TextColors.RED, "Error saving schematic!")); } - return CommandResult.success(); } } diff --git a/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicDelete.java b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicDelete.java new file mode 100644 index 00000000..8a109870 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicDelete.java @@ -0,0 +1,66 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.schematic; + +import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.argument.Arguments; +import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColors; + +public class CommandSchematicDelete extends CommandBase { + + public static final String HELP_TEXT = "deletes a schematic"; + private static final Text SCHEMATIC = Text.of("schematic"); + + public static CommandSpec commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_SCHEMATIC_DELETE) + .description(Text.of(HELP_TEXT)) + .arguments(Arguments.schematic(SCHEMATIC)) + .executor(new CommandSchematicDelete()) + .build(); + + public static void register() { + try { + PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); + PLUGIN.getLogger().debug("Registered command: CommandSchematicDelete"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandSchematicDelete", e); + } + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + IslandSchematic schematic = args.getOne(SCHEMATIC) + .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "You must provide a schematic to use this command!"))); + + if (PLUGIN.getSchematicManager().delete(schematic)) { + src.sendMessage(Text.of(TextColors.GREEN, "Successfully deleted schematic.")); + return CommandResult.success(); + } else { + throw new CommandException(Text.of(TextColors.RED, "Failed to delete schematic.")); + } + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicInfo.java b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicInfo.java new file mode 100644 index 00000000..edebcf1b --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicInfo.java @@ -0,0 +1,157 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.schematic; + +import com.google.common.collect.Lists; +import java.util.List; +import java.util.stream.Collectors; +import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.argument.Arguments; +import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; +import org.spongepowered.api.CatalogType; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.service.pagination.PaginationList; +import org.spongepowered.api.text.LiteralText; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.action.TextActions; +import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.text.format.TextStyles; + +public class CommandSchematicInfo extends CommandBase { + + public static final String HELP_TEXT = "used to view detailed schematic info"; + private static final Text SCHEMATIC = Text.of("schematic"); + private static final LiteralText NONE = Text.of("none"); + + private enum Category { + DETAILS, COMMANDS, RESET_COMMANDS + } + + public static final CommandSpec commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_SCHEMATIC_INFO) + .description(Text.of(HELP_TEXT)) + .arguments(Arguments.schematic(SCHEMATIC)) + .executor(new CommandSchematicInfo()) + .build(); + + public static void register() { + try { + PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); + PLUGIN.getLogger().debug("Registered command: CommandSchematicInfo"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandSchematicInfo", e); + } + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + IslandSchematic schematic = args.getOne(SCHEMATIC) + .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "You must provide a schematic to use this command!"))); + + getPaginationList(schematic, Category.DETAILS, src).sendTo(src); + + return CommandResult.success(); + } + + private PaginationList getPaginationList(IslandSchematic schematic, Category category, CommandSource src) { + Text title = Text.of( + schematic.getText(), TextColors.AQUA, " : ", + category == Category.DETAILS ? TextColors.AQUA : TextColors.GRAY, "[", + Text.builder("Details") + .color(category == Category.DETAILS ? TextColors.GREEN : TextColors.GRAY) + .onHover(TextActions.showText(Text.of("Click here to show details"))) + .onClick(TextActions.executeCallback(s -> getPaginationList(schematic, Category.DETAILS, s).sendTo(s))), + category == Category.DETAILS ? TextColors.AQUA : TextColors.GRAY, "] ", + category == Category.COMMANDS ? TextColors.AQUA : TextColors.GRAY, "[", + Text.builder("Commands") + .color(category == Category.COMMANDS ? TextColors.GREEN : TextColors.GRAY) + .onHover(TextActions.showText(Text.of("Click here to show commands"))) + .onClick(TextActions.executeCallback(s -> getPaginationList(schematic, Category.COMMANDS, s).sendTo(s))), + category == Category.COMMANDS ? TextColors.AQUA : TextColors.GRAY, "] " + ); + + List contents = Lists.newArrayList(); + switch (category) { + case DETAILS: + contents = getDetails(schematic); + break; + case COMMANDS: + contents = getCommands(schematic, src.hasPermission(Permissions.COMMAND_SCHEMATIC_COMMAND)); + break; + } + + return PaginationList.builder() + .title(title) + .padding(Text.of(TextColors.AQUA, TextStyles.STRIKETHROUGH, "-")) + .contents(contents) + .build(); + } + + private List getDetails(IslandSchematic schematic) { + List contents = Lists.newArrayList(); + contents.add(Text.of(TextColors.YELLOW, "Author", TextColors.WHITE, " : ", TextColors.GRAY, schematic.getAuthor())); + contents.add(Text.of(TextColors.YELLOW, "Date", TextColors.WHITE, " : ", TextColors.GRAY, schematic.getDate())); + contents.add(Text.of(TextColors.YELLOW, "Filename", TextColors.WHITE, " : ", TextColors.GRAY, schematic.getName())); + contents.add(Text.of(TextColors.YELLOW, "Biome", TextColors.WHITE, " : ", TextColors.GRAY, schematic.getBiomeType().map(CatalogType::getName).orElse("none"))); + contents.add(Text.of(TextColors.YELLOW, "Height", TextColors.WHITE, " : ", TextColors.LIGHT_PURPLE, schematic.getHeight().map(Text::of).orElse(NONE))); + contents.add(Text.of(TextColors.YELLOW, "Icon", TextColors.WHITE, " : ", TextColors.GRAY, schematic.getIcon().map(i -> Text.of(i).toText()).orElse(NONE))); + contents.add(Text.of(TextColors.YELLOW, "Preset", TextColors.WHITE, " : ", TextColors.GRAY, schematic.getPreset().map(Text::of).orElse(NONE))); + return contents; + } + + private List getCommands(IslandSchematic schematic, boolean canEdit) { + List contents = schematic.getCommands().stream() + .map(s -> Text.of(canEdit ? deleteCommandButton(schematic, s) : Text.EMPTY, "/", s)) + .collect(Collectors.toList()); + if (contents.isEmpty()) { + contents.add(Text.of(TextColors.RED, "No commands set")); + } + if (canEdit) { + contents.add( + Text.of(TextColors.WHITE, "[", TextColors.GREEN, "+", TextColors.WHITE, "]", TextColors.GREEN, " Add new command").toBuilder() + .onHover(TextActions.showText(Text.of("Click to add"))) + .onClick(TextActions.suggestCommand("/is schematic command " + schematic.getName() + " add ")) + .build()); + } + return contents; + } + + private Text deleteCommandButton(IslandSchematic schematic, String command) { + return Text.of(TextColors.WHITE, "[", + Text.builder("✗") + .color(TextColors.RED) + .onHover(TextActions.showText(Text.of(TextColors.RED, "Click to delete"))) + .onClick(TextActions.executeCallback(src -> { + List commands = schematic.getCommands(); + commands.remove(command); + schematic.setCommands(commands); + if (PLUGIN.getSchematicManager().save(schematic)) { + src.sendMessage(Text.of(TextColors.GREEN, "Successfully removed ", TextColors.WHITE, command, TextColors.GREEN, ".")); + } else { + src.sendMessage(Text.of(TextColors.RED, "Failed to remove ", TextColors.WHITE, command, TextColors.RED, ".")); + } + })), + TextColors.WHITE, "] "); + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicList.java b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicList.java new file mode 100644 index 00000000..a6d31dd0 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicList.java @@ -0,0 +1,112 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.schematic; + +import java.util.List; +import java.util.stream.Collectors; +import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.args.GenericArguments; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.service.pagination.PaginationList; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.action.TextActions; +import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.text.format.TextStyles; + +public class CommandSchematicList extends CommandBase { + + public static final String HELP_TEXT = "used to list available island schematics"; + + public static CommandSpec commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_SCHEMATIC_LIST) + .arguments(GenericArguments.flags().permissionFlag(Permissions.COMMAND_SCHEMATIC_LIST_ALL, "a", "-all").buildWith(GenericArguments.none())) + .executor(new CommandSchematicList()) + .build(); + + public static void register() { + try { + Sponge.getCommandManager().register(PLUGIN, commandSpec); + PLUGIN.getLogger().debug("Registered command: CommandSchematicList"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandSchematicList", e); + } + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + boolean canDelete = src.hasPermission(Permissions.COMMAND_SCHEMATIC_DELETE); + boolean checkPerms = !args.getOne("a").orElse(false) && PLUGIN.getConfig().getPermissionConfig().isSeparateSchematicPerms(); + List schematics = PLUGIN.getSchematicManager().getSchematics().stream() + .filter(s -> !checkPerms || src.hasPermission(Permissions.COMMAND_ARGUMENTS_SCHEMATICS + "." + s.getName())) + .map(s -> Text.of( + canDelete ? deleteSchematicButton(s) : Text.EMPTY, + s.getText().toBuilder() + .onHover(TextActions.showText(Text.of("Click to view schematic info"))) + .onClick(TextActions.runCommand("/is schematic info " + s.getName())), + TextColors.WHITE, " - ", + TextColors.GRAY, s.getBiomeType().isPresent() ? s.getBiomeType().get().getName() : "none", TextColors.WHITE, " - ", + TextColors.LIGHT_PURPLE, s.getCommands().size(), TextColors.GRAY, " command", s.getCommands().size() != 1 ? "s" : "" + )) + .collect(Collectors.toList()); + + PaginationList.builder() + .title(Text.of(TextColors.AQUA, "Schematics")) + .header(Text.of(TextStyles.BOLD, "NAME", " - ", "BIOME", " - ", "COMMANDS")) + .padding(Text.of(TextColors.AQUA, TextStyles.STRIKETHROUGH, "-")) + .contents(schematics) + .sendTo(src); + + return CommandResult.success(); + } + + private Text deleteSchematicButton(IslandSchematic schematic) { + return Text.of(TextColors.WHITE, "[", + Text.builder("✗") + .color(TextColors.RED) + .onHover(TextActions.showText(Text.of(TextColors.RED, "Click to delete"))) + .onClick(TextActions.executeCallback(src -> src.sendMessage(Text.of( + TextColors.WHITE, "Are you sure you want to delete ", schematic.getText(), TextColors.WHITE, "?", Text.NEW_LINE, + TextColors.WHITE, "[", + Text.builder("YES") + .color(TextColors.GREEN) + .onHover(TextActions.showText(Text.of("Click to delete"))) + .onClick(TextActions.executeCallback(source -> { + if (PLUGIN.getSchematicManager().delete(schematic)) { + src.sendMessage(Text.of(TextColors.GREEN, "Successfully deleted ", TextColors.WHITE, schematic.getText(), TextColors.GREEN, ".")); + } else { + src.sendMessage(Text.of(TextColors.RED, "Failed to delete ", TextColors.WHITE, schematic.getText(), TextColors.RED, ".")); + } + })), + TextColors.WHITE, "] [", + Text.builder("NO") + .color(TextColors.RED) + .onHover(TextActions.showText(Text.of("Click to cancel"))) + .onClick(TextActions.executeCallback(s -> s.sendMessage(Text.of("Schematic deletion canceled!")))), + TextColors.WHITE, "]" + )))), + TextColors.WHITE, "] "); + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetBiome.java b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetBiome.java new file mode 100644 index 00000000..ea982c1b --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetBiome.java @@ -0,0 +1,78 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.schematic; + +import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.argument.Arguments; +import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.args.GenericArguments; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.world.biome.BiomeType; + +public class CommandSchematicSetBiome extends CommandBase { + + public static final String HELP_TEXT = "used to set the default biome for a schematic"; + private static final Text SCHEMATIC = Text.of("schematic"); + private static final Text BIOME = Text.of("biome-type"); + + public static CommandSpec commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_SCHEMATIC_SET_BIOME) + .description(Text.of(HELP_TEXT)) + .arguments( + Arguments.schematic(SCHEMATIC), + GenericArguments.optional(Arguments.biome(BIOME)) + ) + .executor(new CommandSchematicSetBiome()) + .build(); + + public static void register() { + try { + PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); + PLUGIN.getLogger().debug("Registered command: CommandSchematicSetBiome"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandSchematicSetBiome", e); + } + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + IslandSchematic schematic = args.getOne(SCHEMATIC) + .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "You must provide a schematic to use this command!"))); + BiomeType biome = args.getOne(BIOME).orElse(null); + + schematic.setBiomeType(biome); + + if (PLUGIN.getSchematicManager().save(schematic)) { + src.sendMessage(Text.of( + TextColors.GREEN, "Successfully updated schematic biome to ", + TextColors.WHITE, biome != null ? biome.getName() : "none", TextColors.GREEN, "." + )); + return CommandResult.success(); + } else { + throw new CommandException(Text.of(TextColors.RED, "Failed to update schematic.")); + } + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetHeight.java b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetHeight.java new file mode 100644 index 00000000..16fd66e4 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetHeight.java @@ -0,0 +1,77 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.schematic; + +import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.argument.Arguments; +import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.args.GenericArguments; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColors; + +public class CommandSchematicSetHeight extends CommandBase { + + public static final String HELP_TEXT = "used to set the generation height for a schematic"; + private static final Text SCHEMATIC = Text.of("schematic"); + private static final Text HEIGHT = Text.of("height"); + + public static CommandSpec commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_SCHEMATIC_SET_HEIGHT) + .description(Text.of(HELP_TEXT)) + .arguments( + Arguments.schematic(SCHEMATIC), + GenericArguments.optional(GenericArguments.integer(HEIGHT)) + ) + .executor(new CommandSchematicSetHeight()) + .build(); + + public static void register() { + try { + PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); + PLUGIN.getLogger().debug("Registered command: CommandSchematicSetHeight"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandSchematicSetHeight", e); + } + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + IslandSchematic schematic = args.getOne(SCHEMATIC) + .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "You must provide a schematic to use this command!"))); + Integer height = args.getOne(HEIGHT).orElse(null); + if (height != null && (height < 0 || height > 255)) { + throw new CommandException(Text.of(TextColors.RED, "Schematic height must be between ", TextColors.LIGHT_PURPLE, "0-255", TextColors.RED, "!")); + } + + schematic.setHeight(height); + + if (PLUGIN.getSchematicManager().save(schematic)) { + src.sendMessage(Text.of(TextColors.GREEN, "Successfully updated schematic height to ", TextColors.LIGHT_PURPLE, height, TextColors.GREEN, ".")); + return CommandResult.success(); + } else { + throw new CommandException(Text.of(TextColors.RED, "Failed to update schematic.")); + } + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetIcon.java b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetIcon.java new file mode 100644 index 00000000..bf47a893 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetIcon.java @@ -0,0 +1,98 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.schematic; + +import java.util.Optional; +import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.argument.Arguments; +import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.args.GenericArguments; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.data.key.Keys; +import org.spongepowered.api.data.type.HandTypes; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.item.ItemType; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.action.TextActions; +import org.spongepowered.api.text.format.TextColors; + +public class CommandSchematicSetIcon extends CommandBase { + + public static final String HELP_TEXT = "used to set the menu icon for a schematic"; + private static final Text SCHEMATIC = Text.of("schematic"); + private static final Text ICON = Text.of("icon"); + + public static final CommandSpec commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_SCHEMATIC_SET_ICON) + .description(Text.of(HELP_TEXT)) + .arguments( + Arguments.schematic(SCHEMATIC), + GenericArguments.optional(GenericArguments.catalogedElement(ICON, ItemType.class)) + ) + .executor(new CommandSchematicSetIcon()) + .build(); + + public static void register() { + try { + PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); + PLUGIN.getLogger().debug("Registered command: CommandSchematicSetIcon"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandSchematicSetIcon", e); + } + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + IslandSchematic schematic = args.getOne(SCHEMATIC) + .orElseThrow( + () -> new CommandException(Text.of(TextColors.RED, "You must provide a schematic to use this command!"))); + Optional icon = args.getOne(ICON); + + if (icon.isPresent() || (src instanceof Player + && ((Player) src).getItemInHand(HandTypes.MAIN_HAND).isPresent() + && !((Player) src).getItemInHand(HandTypes.MAIN_HAND).get().isEmpty())) { + ItemType itemType = icon.orElse(((Player) src).getItemInHand(HandTypes.MAIN_HAND).get().getType()); + schematic.setIcon(itemType); + ItemStackSnapshot snapshot = ItemStack.of(itemType).createSnapshot(); + src.sendMessage(Text.of( + TextColors.GREEN, "Successfully updated schematic icon to ", + snapshot.get(Keys.DISPLAY_NAME).orElse(Text.of(itemType.getTranslation())).toBuilder() + .color(TextColors.WHITE) + .onHover(TextActions.showItem(snapshot)), + TextColors.GREEN, "." + )); + } else { + schematic.setIcon(null); + src.sendMessage(Text.of(TextColors.GREEN, "Successfully removed schematic icon.")); + } + + if (PLUGIN.getSchematicManager().save(schematic)) { + return CommandResult.success(); + } else { + throw new CommandException(Text.of(TextColors.RED, "Failed to update schematic.")); + } + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetName.java b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetName.java new file mode 100644 index 00000000..17d4c043 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetName.java @@ -0,0 +1,77 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.schematic; + +import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.argument.Arguments; +import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.args.GenericArguments; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.text.serializer.TextSerializers; + +public class CommandSchematicSetName extends CommandBase { + + public static final String HELP_TEXT = "used to set the name for a schematic"; + private static final Text SCHEMATIC = Text.of("schematic"); + private static final Text NAME = Text.of("name"); + + public static CommandSpec commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_SCHEMATIC_SET_NAME) + .description(Text.of(HELP_TEXT)) + .arguments( + Arguments.schematic(SCHEMATIC), + GenericArguments.optional(GenericArguments.text(NAME, TextSerializers.FORMATTING_CODE, true)) + ) + .executor(new CommandSchematicSetName()) + .build(); + + public static void register() { + try { + PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); + PLUGIN.getLogger().debug("Registered command: CommandSchematicSetName"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandSchematicSetName", e); + } + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + IslandSchematic schematic = args.getOne(SCHEMATIC) + .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "You must provide a schematic to use this command!"))); + Text text = args.getOne(NAME).orElse(Text.of(schematic.getName())); + + schematic.setText(text); + + if (PLUGIN.getSchematicManager().save(schematic)) { + src.sendMessage(Text.of( + TextColors.GREEN, "Successfully updated schematic name to ", TextColors.WHITE, text, TextColors.GREEN, "." + )); + return CommandResult.success(); + } else { + throw new CommandException(Text.of(TextColors.RED, "Failed to update schematic.")); + } + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetPreset.java b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetPreset.java new file mode 100644 index 00000000..8488cef7 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/schematic/CommandSchematicSetPreset.java @@ -0,0 +1,81 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.schematic; + +import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.argument.Arguments; +import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.args.GenericArguments; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColors; + +public class CommandSchematicSetPreset extends CommandBase { + + public static final String HELP_TEXT = "used to set the flat world preset for a schematic"; + private static final Text SCHEMATIC = Text.of("schematic"); + private static final Text PRESET = Text.of("preset"); + + public static CommandSpec commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_SCHEMATIC_SET_PRESET) + .description(Text.of(HELP_TEXT)) + .arguments( + Arguments.schematic(SCHEMATIC), + GenericArguments.optional(GenericArguments.string(PRESET)) + ) + .executor(new CommandSchematicSetPreset()) + .build(); + + public static void register() { + try { + PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); + PLUGIN.getLogger().debug("Registered command: CommandSchematicSetPreset"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandSchematicSetPreset", e); + } + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + IslandSchematic schematic = args.getOne(SCHEMATIC) + .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "You must provide a schematic to use this command!"))); + String preset = args.getOne(PRESET).orElse(null); + + schematic.setPreset(preset); + + if (PLUGIN.getSchematicManager().save(schematic)) { + if (preset != null) { + src.sendMessage(Text.of( + TextColors.GREEN, "Successfully updated schematic preset to ", + TextColors.WHITE, preset, TextColors.GREEN, "." + )); + } else { + src.sendMessage(Text.of(TextColors.GREEN, "Successfully removed schematic preset.")); + } + return CommandResult.success(); + } else { + throw new CommandException(Text.of(TextColors.RED, "Failed to update schematic.")); + } + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/schematic/package-info.java b/src/main/java/net/mohron/skyclaims/command/schematic/package-info.java new file mode 100644 index 00000000..3840c148 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/schematic/package-info.java @@ -0,0 +1,21 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ +@NonnullByDefault +package net.mohron.skyclaims.command.schematic; + +import org.spongepowered.api.util.annotation.NonnullByDefault; \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/command/team/CommandDemote.java b/src/main/java/net/mohron/skyclaims/command/team/CommandDemote.java index 3760f3ec..80395a3b 100644 --- a/src/main/java/net/mohron/skyclaims/command/team/CommandDemote.java +++ b/src/main/java/net/mohron/skyclaims/command/team/CommandDemote.java @@ -32,9 +32,7 @@ import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandDemote extends CommandBase.IslandCommand { public static final String HELP_TEXT = "used to demote a player on an island."; diff --git a/src/main/java/net/mohron/skyclaims/command/team/CommandInvite.java b/src/main/java/net/mohron/skyclaims/command/team/CommandInvite.java index bea60380..141dc3e4 100644 --- a/src/main/java/net/mohron/skyclaims/command/team/CommandInvite.java +++ b/src/main/java/net/mohron/skyclaims/command/team/CommandInvite.java @@ -20,6 +20,7 @@ import net.mohron.skyclaims.command.CommandBase; import net.mohron.skyclaims.command.CommandIsland; +import net.mohron.skyclaims.permissions.Options; import net.mohron.skyclaims.permissions.Permissions; import net.mohron.skyclaims.team.Invite; import net.mohron.skyclaims.team.PrivilegeType; @@ -34,9 +35,7 @@ import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.text.format.TextStyles; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandInvite extends CommandBase.IslandCommand { public static final String HELP_TEXT = "used to invite players to your island or list your pending invites."; @@ -50,8 +49,7 @@ public static void register() { .arguments(GenericArguments.optional(GenericArguments.firstParsing( GenericArguments.seq( GenericArguments.user(USER), - GenericArguments - .optional(PrivilegeType.getCommandArgument(PRIVILEGE), PrivilegeType.MEMBER) + GenericArguments.optional(PrivilegeType.getCommandArgument(PRIVILEGE), PrivilegeType.MEMBER) ), GenericArguments.literal(LIST, "list") ))) @@ -69,15 +67,13 @@ public static void register() { } @Override - public CommandResult execute(Player player, Island island, CommandContext args) - throws CommandException { + public CommandResult execute(Player player, Island island, CommandContext args) throws CommandException { User user = args.getOne(USER).orElse(null); PrivilegeType type = args.getOne(PRIVILEGE).orElse(PrivilegeType.MEMBER); + int maxTeammates = Options.getMaxTeammates(island.getOwnerUniqueId()); if (type == PrivilegeType.NONE) { - throw new CommandException( - Text.of(TextStyles.ITALIC, "What kind of invite is ", TextStyles.RESET, type.toText(), - TextStyles.ITALIC, "?")); + throw new CommandException(Text.of(TextStyles.ITALIC, "What kind of invite is ", TextStyles.RESET, type.toText(), TextStyles.ITALIC, "?")); } if (user == null || args.hasAny(LIST)) { @@ -90,13 +86,14 @@ public CommandResult execute(Player player, Island island, CommandContext args) island.getPrivilegeType(user).toText(), TextColors.RED, " on ", island.getName(), TextColors.RED, "!" )); - } else if (!island.isOwner(player) || island.getPrivilegeType(player).ordinal() >= type - .ordinal()) { + } else if (!island.isOwner(player) || island.getPrivilegeType(player).ordinal() >= type.ordinal()) { throw new CommandException(Text.of( TextColors.RED, "You do not have permission to send ", type == PrivilegeType.OWNER ? "an " : "a ", type.toText(), TextColors.RED, " invite for ", island.getName(), TextColors.RED, "!" )); + } else if (maxTeammates > 0 && island.getTotalMembers() >= maxTeammates) { + throw new CommandException(Text.of(island.getName(), TextColors.RED, " has reached its maximum team size (", maxTeammates, ")!")); } else { Invite.builder() .island(island) @@ -105,9 +102,7 @@ public CommandResult execute(Player player, Island island, CommandContext args) .privilegeType(type) .build() .send(); - player.sendMessage( - Text.of(TextColors.GREEN, "Island invite sent to ", type.format(user.getName()), - TextColors.GREEN, ".")); + player.sendMessage(Text.of(TextColors.GREEN, "Island invite sent to ", type.format(user.getName()), TextColors.GREEN, ".")); } return CommandResult.success(); diff --git a/src/main/java/net/mohron/skyclaims/command/team/CommandKick.java b/src/main/java/net/mohron/skyclaims/command/team/CommandKick.java index ddd5d89c..9f5e770c 100644 --- a/src/main/java/net/mohron/skyclaims/command/team/CommandKick.java +++ b/src/main/java/net/mohron/skyclaims/command/team/CommandKick.java @@ -32,9 +32,7 @@ import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandKick extends CommandBase.IslandCommand { public static final String HELP_TEXT = "used to remove players from an island."; @@ -71,8 +69,11 @@ public CommandResult execute(Player player, Island island, CommandContext args) PrivilegeType.NONE.format(user.getName()), TextColors.RED, " is not a member of ", island.getName(), TextColors.RED, "!" )); - } else if (island.getPrivilegeType(player).ordinal() >= island.getPrivilegeType(user) - .ordinal()) { + } else if (user.hasPermission(Permissions.EXEMPT_KICK)) { + throw new CommandException(Text.of( + island.getPrivilegeType(user).format(user.getName()), TextColors.RED, " is exempt from being kicked!") + ); + } else if (island.getPrivilegeType(player).ordinal() >= island.getPrivilegeType(user).ordinal()) { throw new CommandException(Text.of( TextColors.RED, "You do not have permission to kick ", island.getPrivilegeType(user).format(user.getName()), @@ -82,13 +83,13 @@ public CommandResult execute(Player player, Island island, CommandContext args) PrivilegeType type = island.getPrivilegeType(user); user.getPlayer().ifPresent(p -> { - if (island.getPlayers().contains(p) && !p.hasPermission(Permissions.EXEMPT_KICK)) { + if (island.getPlayers().contains(p)) { p.setLocationSafely(PLUGIN.getConfig().getWorldConfig().getSpawn()); - p.sendMessage( - Text.of(TextColors.RED, "You have been removed from ", island.getName(), TextColors.RED, - "!")); + p.sendMessage(Text.of(TextColors.RED, "You have been removed from ", island.getName(), TextColors.RED, "!")); } }); + + clearMemberInventory(user, Permissions.KEEP_INV_PLAYER_KICK, Permissions.KEEP_INV_ENDERCHEST_KICK); island.removeMember(user); player.sendMessage(Text.of( diff --git a/src/main/java/net/mohron/skyclaims/command/team/CommandLeave.java b/src/main/java/net/mohron/skyclaims/command/team/CommandLeave.java index 0b564d6e..00526d4b 100644 --- a/src/main/java/net/mohron/skyclaims/command/team/CommandLeave.java +++ b/src/main/java/net/mohron/skyclaims/command/team/CommandLeave.java @@ -32,9 +32,7 @@ import org.spongepowered.api.text.Text; import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandLeave extends CommandBase.IslandCommand { public static final String HELP_TEXT = "used to leave an island."; @@ -60,12 +58,9 @@ public CommandResult execute(Player player, Island island, CommandContext args) throws CommandException { if (island.isOwner(player)) { - throw new CommandException( - Text.of(TextColors.RED, "You must transfer island ownership before leaving.")); + throw new CommandException(Text.of(TextColors.RED, "You must transfer island ownership before leaving.")); } else if (!island.isMember(player)) { - throw new CommandException( - Text.of(TextColors.RED, "You are not a member of ", island.getName(), TextColors.RED, - "!")); + throw new CommandException(Text.of(TextColors.RED, "You are not a member of ", island.getName(), TextColors.RED, "!")); } player.sendMessage(Text.of( @@ -93,10 +88,10 @@ private Consumer leaveIsland(Player player, Island island) { player.setLocationSafely(PLUGIN.getConfig().getWorldConfig().getSpawn()); } + clearMemberInventory(player, Permissions.KEEP_INV_PLAYER_LEAVE, Permissions.KEEP_INV_ENDERCHEST_LEAVE); + island.removeMember(player); - player.sendMessage( - Text.of(TextColors.RED, "You have been removed from ", island.getName(), TextColors.RED, - "!")); + player.sendMessage(Text.of(TextColors.RED, "You have been removed from ", island.getName(), TextColors.RED, "!")); }; } } diff --git a/src/main/java/net/mohron/skyclaims/command/team/CommandPromote.java b/src/main/java/net/mohron/skyclaims/command/team/CommandPromote.java index b39f6429..1269f86b 100644 --- a/src/main/java/net/mohron/skyclaims/command/team/CommandPromote.java +++ b/src/main/java/net/mohron/skyclaims/command/team/CommandPromote.java @@ -33,9 +33,8 @@ import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault + public class CommandPromote extends CommandBase.IslandCommand { public static final String HELP_TEXT = "used to promote a player on an island."; diff --git a/src/main/java/net/mohron/skyclaims/command/team/package-info.java b/src/main/java/net/mohron/skyclaims/command/team/package-info.java new file mode 100644 index 00000000..8c044527 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/team/package-info.java @@ -0,0 +1,21 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ +@NonnullByDefault +package net.mohron.skyclaims.command.team; + +import org.spongepowered.api.util.annotation.NonnullByDefault; \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandCreate.java b/src/main/java/net/mohron/skyclaims/command/user/CommandCreate.java index b96d01d8..121a7b60 100644 --- a/src/main/java/net/mohron/skyclaims/command/user/CommandCreate.java +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandCreate.java @@ -18,18 +18,17 @@ package net.mohron.skyclaims.command.user; -import java.util.List; import java.util.Optional; import java.util.function.Consumer; -import java.util.stream.Collectors; -import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.CommandBase.ListSchematicCommand; import net.mohron.skyclaims.command.CommandIsland; import net.mohron.skyclaims.command.argument.Arguments; -import net.mohron.skyclaims.command.argument.SchematicArgument; import net.mohron.skyclaims.exception.CreateIslandException; import net.mohron.skyclaims.permissions.Options; import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; @@ -37,18 +36,12 @@ import org.spongepowered.api.command.args.GenericArguments; import org.spongepowered.api.command.spec.CommandSpec; import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.service.pagination.PaginationList; import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.text.format.TextStyles; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault -public class CommandCreate extends CommandBase.PlayerCommand { +public class CommandCreate extends ListSchematicCommand { public static final String HELP_TEXT = "create an island."; - private static final Text SCHEMATIC = Text.of("schematic"); public static void register() { CommandSpec commandSpec = CommandSpec.builder() @@ -69,77 +62,65 @@ public static void register() { @Override public CommandResult execute(Player player, CommandContext args) throws CommandException { - if (Island.hasIsland(player.getUniqueId())) { + if (IslandManager.hasIsland(player.getUniqueId())) { throw new CommandException(Text.of(TextColors.RED, "You already have an island!")); } - boolean canCreate = Options.getMaxIslands(player.getUniqueId()) < 1 - || Options.getMaxIslands(player.getUniqueId()) - Island.getTotalIslands(player) > 0; + int maxIslands = Options.getMaxIslands(player.getUniqueId()); + boolean canCreate = maxIslands < 1 || maxIslands - IslandManager.getTotalIslands(player) > 0; if (!canCreate) { throw new CommandException(Text.of(TextColors.RED, "You have reached your maximum number of islands!")); } - Optional schematic = args.getOne(SCHEMATIC); + Optional schematic = args.getOne(SCHEMATIC); + Optional defaultSchematic = Options.getDefaultSchematic(player.getUniqueId()); if (schematic.isPresent()) { return createIsland(player, schematic.get()); - } else if (PLUGIN.getConfig().getMiscConfig().isListSchematics() - && SchematicArgument.SCHEMATICS.size() > 1) { - return listSchematics(player); + } else if (!defaultSchematic.isPresent()) { + return listSchematics(player, this::createIsland); } else { - return createIsland(player, Options.getDefaultSchematic(player.getUniqueId())); + return createIsland(player, defaultSchematic.get()); } } - private CommandResult createIsland(Player player, String schematic) throws CommandException { + private CommandResult createIsland(Player player, IslandSchematic schematic) throws CommandException { + if (IslandManager.hasIsland(player.getUniqueId())) { + player.sendMessage(Text.of(TextColors.RED, "You already have an island!")); + return CommandResult.empty(); + } + player.sendMessage(Text.of( TextColors.GREEN, "Your island is being created.", - PLUGIN.getConfig().getMiscConfig().isTeleportOnCreate() ? " You will be teleported shortly." - : Text.EMPTY + PLUGIN.getConfig().getMiscConfig().isTeleportOnCreate() ? " You will be teleported shortly." : Text.EMPTY )); try { - new Island(player, schematic); + Island island = new Island(player, schematic); + clearIslandMemberInventories(island, Permissions.KEEP_INV_PLAYER_CREATE, Permissions.KEEP_INV_ENDERCHEST_CREATE); return CommandResult.success(); } catch (CreateIslandException e) { - throw new CommandException( - Text.of(TextColors.RED, "Unable to create island!", Text.NEW_LINE, TextColors.RESET, - e.getText())); + throw new CommandException(Text.of(TextColors.RED, "Unable to create island!", Text.NEW_LINE, TextColors.RESET, e.getText())); } } - private CommandResult listSchematics(Player player) { - boolean checkPerms = PLUGIN.getConfig().getPermissionConfig().isSeparateSchematicPerms(); - List schematics = SchematicArgument.SCHEMATICS.keySet().stream() - .filter(s -> !checkPerms || player - .hasPermission(Permissions.COMMAND_ARGUMENTS_SCHEMATICS + "." + s.toLowerCase())) - .map(s -> Text.builder(s).onClick(TextActions.executeCallback(createIsland(s))).build()) - .collect(Collectors.toList()); - PaginationList.builder() - .title(Text.of(TextColors.AQUA, "Starter Islands")) - .padding(Text.of(TextColors.AQUA, TextStyles.STRIKETHROUGH, "-")) - .contents(schematics) - .sendTo(player); - return CommandResult.empty(); - } - - private Consumer createIsland(String s) { + private Consumer createIsland(IslandSchematic schematic) { return src -> { if (src instanceof Player) { Player player = (Player) src; - if (Island.hasIsland(player.getUniqueId())) { + if (IslandManager.hasIsland(player.getUniqueId())) { player.sendMessage(Text.of(TextColors.RED, "You already have an island!")); return; } + + player.sendMessage(Text.of( + TextColors.GREEN, "Your island is being created.", + PLUGIN.getConfig().getMiscConfig().isTeleportOnCreate() ? " You will be teleported shortly." : Text.EMPTY + )); + try { - player.sendMessage(Text.of( - TextColors.GREEN, "Your island is being created.", - PLUGIN.getConfig().getMiscConfig().isTeleportOnCreate() - ? " You will be teleported shortly." : Text.EMPTY - )); - new Island(player, s); + Island island = new Island(player, schematic); + clearIslandMemberInventories(island, Permissions.KEEP_INV_PLAYER_CREATE, Permissions.KEEP_INV_ENDERCHEST_CREATE); } catch (CreateIslandException e) { - player.sendMessage( - Text.of(TextColors.RED, "Unable to create island!", Text.NEW_LINE, TextColors.RESET, - e.getText())); + player.sendMessage(Text.of(TextColors.RED, "Unable to create island!", Text.NEW_LINE, TextColors.RESET, e.getText())); } } }; diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandDelete.java b/src/main/java/net/mohron/skyclaims/command/user/CommandDelete.java index 9364693e..e2ba7ae4 100644 --- a/src/main/java/net/mohron/skyclaims/command/user/CommandDelete.java +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandDelete.java @@ -25,6 +25,8 @@ import net.mohron.skyclaims.permissions.Permissions; import net.mohron.skyclaims.team.PrivilegeType; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; +import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandPermissionException; import org.spongepowered.api.command.CommandResult; @@ -36,9 +38,7 @@ import org.spongepowered.api.text.Text; import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandDelete extends CommandBase.IslandCommand { public static final String HELP_TEXT = "used to permanently delete an island."; @@ -92,14 +92,12 @@ private Consumer getConfirmation(Island island, boolean clear) { Text.builder("YES") .color(TextColors.GREEN) .onHover(TextActions.showText(Text.of("Click to delete"))) - .onClick( - TextActions.executeCallback(deleteIsland(island, clear))), + .onClick(TextActions.executeCallback(deleteIsland(island, clear))), TextColors.WHITE, "] [", Text.builder("NO") .color(TextColors.RED) - .onHover(TextActions.showText(Text.of("Click to delete"))) - .onClick(TextActions - .executeCallback(s -> s.sendMessage(Text.of("Island deletion canceled!")))), + .onHover(TextActions.showText(Text.of("Click to cancel"))) + .onClick(TextActions.executeCallback(s -> s.sendMessage(Text.of("Island deletion canceled!")))), TextColors.WHITE, "]" )); } @@ -108,14 +106,20 @@ private Consumer getConfirmation(Island island, boolean clear) { private Consumer deleteIsland(Island island, boolean clear) { return src -> { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); + if (!IslandManager.ISLANDS.containsKey(island.getUniqueId())) { + src.sendMessage(Text.of(island.getName(), TextColors.RED, " has already been deleted!")); + return; + } if (clear) { island.clear(); } - island.getPlayers() - .forEach(p -> p.setLocationSafely(PLUGIN.getConfig().getWorldConfig().getSpawn())); + clearIslandMemberInventories(island, Permissions.KEEP_INV_PLAYER_DELETE, Permissions.KEEP_INV_ENDERCHEST_DELETE); + island.getPlayers().forEach(p -> p.setLocationSafely(PLUGIN.getConfig().getWorldConfig().getSpawn())); island.delete(); src.sendMessage(Text.of(island.getName(), TextColors.GREEN, " has been deleted!")); + Sponge.getCauseStackManager().popCause(); }; } } diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandEntityInfo.java b/src/main/java/net/mohron/skyclaims/command/user/CommandEntityInfo.java new file mode 100644 index 00000000..b4883a46 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandEntityInfo.java @@ -0,0 +1,171 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.user; + +import com.google.common.collect.Lists; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import net.mohron.skyclaims.command.CommandBase.IslandCommand; +import net.mohron.skyclaims.command.CommandIsland; +import net.mohron.skyclaims.command.argument.Arguments; +import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.world.Island; +import org.spongepowered.api.CatalogType; +import org.spongepowered.api.block.tileentity.TileEntity; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.args.GenericArguments; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.service.pagination.PaginationList; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.action.TextActions; +import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.text.format.TextStyles; + +public class CommandEntityInfo extends IslandCommand { + + public static final String HELP_TEXT = "display details about the entities on an island."; + + private enum Category {SUMMARY, PASSIVE, HOSTILE, TILE} + + public static void register() { + CommandSpec commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_ENTITY_INFO) + .description(Text.of(HELP_TEXT)) + .arguments(GenericArguments.optional(Arguments.island(ISLAND))) + .executor(new CommandEntityInfo()) + .build(); + + try { + CommandIsland.addSubCommand(commandSpec, "entity"); + PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); + PLUGIN.getLogger().debug("Registered command: CommandEntityInfo"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandEntityInfo", e); + } + } + + @Override + public CommandResult execute(Player player, Island island, CommandContext args) throws CommandException { + + sendEntityInfo(island, Category.SUMMARY).accept(player); + + return CommandResult.success(); + } + + private Consumer sendEntityInfo(Island island, Category category) { + return src -> { + List info = Lists.newArrayList(); + + switch (category) { + case SUMMARY: + info.add(Text.of( + TextColors.YELLOW, "Passive", + TextColors.WHITE, " : ", + TextColors.LIGHT_PURPLE, island.getPassiveEntities().size() + )); + info.add(Text.of( + TextColors.YELLOW, "Hostile", + TextColors.WHITE, " : ", + TextColors.LIGHT_PURPLE, island.getHostileEntities().size() + )); + info.add(Text.of( + TextColors.YELLOW, "Item", + TextColors.WHITE, " : ", + TextColors.LIGHT_PURPLE, island.getItemEntities().size() + )); + info.add(Text.of( + TextColors.YELLOW, "Tile", + TextColors.WHITE, " : ", + TextColors.LIGHT_PURPLE, island.getTileEntities().size() + )); + info.add(Text.of( + TextColors.YELLOW, "Total", + TextColors.WHITE, " : ", + TextColors.LIGHT_PURPLE, island.getEntities().size() + )); + break; + case PASSIVE: + island.getPassiveEntities().stream() + .collect(Collectors.groupingBy(Entity::getType, Collectors.counting())) + .forEach((e, c) -> info.add(getEntityDetails(e, c))); + break; + case HOSTILE: + island.getHostileEntities().stream() + .collect(Collectors.groupingBy(Entity::getType, Collectors.counting())) + .forEach((e, c) -> info.add(getEntityDetails(e, c))); + break; + case TILE: + island.getTileEntities().stream() + .collect(Collectors.groupingBy(TileEntity::getType, Collectors.counting())) + .forEach((e, c) -> info.add(getEntityDetails(e, c))); + break; + } + + PaginationList.builder() + .title(Text.of(TextColors.AQUA, "Island Entity Info")) + .padding(Text.of(TextColors.AQUA, TextStyles.STRIKETHROUGH, "-")) + .header(getMenuText(island, category)) + .contents(info) + .sendTo(src); + }; + } + + private Text getEntityDetails(CatalogType e, Long c) { + return Text.of( + TextColors.YELLOW, e.getName(), + TextColors.WHITE, " : ", + TextColors.LIGHT_PURPLE, c + ); + } + + private Text getMenuText(Island island, Category category) { + return Text.of( + category == Category.SUMMARY ? TextColors.AQUA : TextColors.GRAY, "[", + Text.builder("Summary") + .color(category == Category.SUMMARY ? TextColors.GREEN : TextColors.GRAY) + .onHover(TextActions.showText(Text.of("Click here to show entity summary"))) + .onClick(TextActions.executeCallback(sendEntityInfo(island, Category.SUMMARY))), + category == Category.SUMMARY ? TextColors.AQUA : TextColors.GRAY, "] ", + category == Category.PASSIVE ? TextColors.AQUA : TextColors.GRAY, "[", + Text.builder("Passive") + .color(category == Category.PASSIVE ? TextColors.GREEN : TextColors.GRAY) + .onHover(TextActions.showText(Text.of("Click here to show passive entity details"))) + .onClick(TextActions.executeCallback(sendEntityInfo(island, Category.PASSIVE))), + category == Category.PASSIVE ? TextColors.AQUA : TextColors.GRAY, "] ", + category == Category.HOSTILE ? TextColors.AQUA : TextColors.GRAY, "[", + Text.builder("Hostile") + .color(category == Category.HOSTILE ? TextColors.GREEN : TextColors.GRAY) + .onHover(TextActions.showText(Text.of("Click here to show hostile entity details"))) + .onClick(TextActions.executeCallback(sendEntityInfo(island, Category.HOSTILE))), + category == Category.HOSTILE ? TextColors.AQUA : TextColors.GRAY, "] ", + category == Category.TILE ? TextColors.AQUA : TextColors.GRAY, "[", + Text.builder("Tile") + .color(category == Category.TILE ? TextColors.GREEN : TextColors.GRAY) + .onHover(TextActions.showText(Text.of("Click here to show tile entity details"))) + .onClick(TextActions.executeCallback(sendEntityInfo(island, Category.TILE))), + category == Category.TILE ? TextColors.AQUA : TextColors.GRAY, "]" + ); + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandExpand.java b/src/main/java/net/mohron/skyclaims/command/user/CommandExpand.java index 1d52b72b..1dc19f65 100644 --- a/src/main/java/net/mohron/skyclaims/command/user/CommandExpand.java +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandExpand.java @@ -18,6 +18,8 @@ package net.mohron.skyclaims.command.user; +import java.math.BigDecimal; +import java.util.Optional; import java.util.function.Consumer; import me.ryanhamshire.griefprevention.api.GriefPreventionApi; import me.ryanhamshire.griefprevention.api.claim.Claim; @@ -26,10 +28,12 @@ import net.mohron.skyclaims.command.CommandBase; import net.mohron.skyclaims.command.CommandIsland; import net.mohron.skyclaims.command.argument.Arguments; +import net.mohron.skyclaims.config.type.EconomyConfig; import net.mohron.skyclaims.permissions.Options; import net.mohron.skyclaims.permissions.Permissions; import net.mohron.skyclaims.team.PrivilegeType; import net.mohron.skyclaims.world.Island; +import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; @@ -37,12 +41,15 @@ import org.spongepowered.api.command.args.GenericArguments; import org.spongepowered.api.command.spec.CommandSpec; import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.service.economy.Currency; +import org.spongepowered.api.service.economy.EconomyService; +import org.spongepowered.api.service.economy.account.UniqueAccount; +import org.spongepowered.api.service.economy.transaction.ResultType; +import org.spongepowered.api.service.economy.transaction.TransactionResult; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandExpand extends CommandBase.IslandCommand { public static final String HELP_TEXT = "used to expand your island."; @@ -73,19 +80,19 @@ public static void register() { public CommandResult execute(Player player, Island island, CommandContext args) throws CommandException { int blocks = args.getOne(BLOCKS).orElse(1); - Claim claim = island.getClaim() - .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "This command can only be used on claimed islands."))); + Claim claim = island.getClaim().orElseThrow(() -> new CommandException(Text.of( + TextColors.RED, "This command can only be used on claimed islands." + ))); // Check if the player is a Manager if (!island.isManager(player)) { throw new CommandException(Text.of(TextColors.RED, "Only an island manager may use this command!")); } - int width = claim.getWidth(); int maxSize = Options.getMaxSize(island.getOwnerUniqueId()) * 2; // Check if expanding would exceed the max size - if (width >= maxSize || width + blocks * 2 > maxSize) { + if (exceedsMaxSize(island, claim, blocks)) { throw new CommandException(Text.of( TextColors.RED, "You cannot expand ", island.getName(), TextColors.RED, " greater than ", TextColors.LIGHT_PURPLE, maxSize, TextColors.GRAY, "x", TextColors.LIGHT_PURPLE, maxSize, @@ -94,12 +101,11 @@ public CommandResult execute(Player player, Island island, CommandContext args) } player.sendMessage(Text.of( - TextColors.GRAY, "It will cost ", TextColors.LIGHT_PURPLE, - (int) Math.pow(width + blocks, 2) * (GP.getClaimBlockSystem() == ClaimBlockSystem.VOLUME - ? 256 : 1) - claim.getClaimBlocks(), - TextColors.GRAY, " claim blocks to expand ", island.getName(), TextColors.GRAY, " by ", + TextColors.GRAY, "It will cost ", TextColors.LIGHT_PURPLE, getCost(blocks, claim), + TextColors.GRAY, " to expand ", island.getName(), TextColors.GRAY, " by ", TextColors.LIGHT_PURPLE, blocks, TextColors.GRAY, "." )); + player.sendMessage(Text.of( TextColors.GRAY, "Do you want to continue expanding your island?", Text.NEW_LINE, @@ -107,13 +113,12 @@ public CommandResult execute(Player player, Island island, CommandContext args) Text.builder("YES") .color(TextColors.GREEN) .onHover(TextActions.showText(Text.of("Click to expand"))) - .onClick(TextActions.executeCallback(expandIsland(island, blocks))), + .onClick(TextActions.executeCallback(expandIsland(island, claim, blocks))), TextColors.WHITE, "] [", Text.builder("NO") .color(TextColors.RED) .onHover(TextActions.showText(Text.of("Click to cancel"))) - .onClick(TextActions - .executeCallback(s -> s.sendMessage(Text.of("Island expansion canceled!")))), + .onClick(TextActions.executeCallback(s -> s.sendMessage(Text.of("Island expansion canceled!")))), TextColors.WHITE, "]" ) ); @@ -121,48 +126,86 @@ public CommandResult execute(Player player, Island island, CommandContext args) return CommandResult.success(); } - private Consumer expandIsland(Island island, int blocks) { + private Consumer expandIsland(Island island, Claim claim, int blocks) { return src -> { - Claim claim = island.getClaim().orElse(null); - PlayerData playerData = GP - .getWorldPlayerData(island.getWorld().getProperties(), island.getOwnerUniqueId()) - .orElse(null); - - if (claim == null || playerData == null) { - src.sendMessage(Text.of(TextColors.RED, "An error occurred while attempting to expand ", island.getName(), TextColors.RED, "!")); - PLUGIN.getLogger().error("Expansion Failed: {} - claim: {}, player-data: {}", island.getSortableName(), claim != null, playerData != null); + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); + + if (exceedsMaxSize(island, claim, blocks)) { + int maxSize = Options.getMaxSize(island.getOwnerUniqueId()) * 2; + src.sendMessage(Text.of( + TextColors.RED, "You cannot expand ", island.getName(), TextColors.RED, " greater than ", + TextColors.LIGHT_PURPLE, maxSize, TextColors.GRAY, "x", TextColors.LIGHT_PURPLE, maxSize, + TextColors.RED, "." + )); return; } + int cost = getCost(blocks, claim); - int bal = playerData.getRemainingClaimBlocks(); - int cost = (int) Math.pow(claim.getWidth() + blocks, 2) - * (GP.getClaimBlockSystem() == ClaimBlockSystem.VOLUME ? 256 : 1) - - claim.getClaimBlocks(); - - // Check if the Owner, has enough claim blocks to expand - if (bal < cost) { + // Attempt to charge the required currency to the island owner. + if (charge(island, cost)) { + island.expand(blocks); + src.sendMessage(Text.of( + TextColors.GREEN, "Your island has been expanded to ", + TextColors.LIGHT_PURPLE, island.getWidth(), + TextColors.GRAY, "x", + TextColors.LIGHT_PURPLE, island.getWidth(), + TextColors.GREEN, "." + )); + } else { src.sendMessage(Text.of( - TextColors.RED, "You need ", + TextColors.RED, "You do not have the required currency (", TextColors.LIGHT_PURPLE, cost, - TextColors.RED, " claim blocks (", - TextColors.LIGHT_PURPLE, bal, TextColors.RED, ") to expand your island by ", TextColors.LIGHT_PURPLE, blocks, TextColors.RED, "." )); - return; } - - // Use the Owner's claim blocks to expand the island - playerData.setBonusClaimBlocks(playerData.getBonusClaimBlocks() - cost); - island.expand(blocks); - src.sendMessage(Text.of( - TextColors.GREEN, "Your island has been expanded to ", - TextColors.LIGHT_PURPLE, island.getWidth(), - TextColors.GRAY, "x", - TextColors.LIGHT_PURPLE, island.getWidth(), - TextColors.GREEN, "." - )); + Sponge.getCauseStackManager().popCause(); }; } + + private boolean exceedsMaxSize(Island island, Claim claim, int blocks) { + return claim.getWidth() + blocks * 2 > Options.getMaxSize(island.getOwnerUniqueId()) * 2; + } + + private int getCost(int blocks, Claim claim) { + return (int) Math.pow(claim.getWidth() + blocks, 2) + * (GP.getClaimBlockSystem() == ClaimBlockSystem.VOLUME ? 256 : 1) - claim.getClaimBlocks(); + } + + private boolean charge(Island island, int cost) { + EconomyConfig config = PLUGIN.getConfig().getEconomyConfig(); + Optional economyService = Sponge.getServiceManager().provide(EconomyService.class); + + if (!config.isUseClaimBlocks() && economyService.isPresent()) { + Optional account = economyService.get().getOrCreateAccount(island.getOwnerUniqueId()); + Currency currency = config.getCurrency().orElse(economyService.get().getDefaultCurrency()); + if (account.isPresent()) { + // Charge the player's currency account + TransactionResult transaction = account.get().withdraw( + currency, + BigDecimal.valueOf(cost), + Sponge.getCauseStackManager().getCurrentCause() + ); + return transaction.getResult() == ResultType.SUCCESS; + } else { + PLUGIN.getLogger().error("Could not find {} account for {}.", currency.getDisplayName().toPlain(), island.getOwnerName()); + return false; + } + } else { + // Use GP claim blocks by manipulating the player's bonus claim block balance + Optional data = GP.getWorldPlayerData(island.getWorld().getProperties(), island.getOwnerUniqueId()); + if (data.isPresent()) { + if (data.get().getRemainingClaimBlocks() >= cost) { + // Use the Owner's claim blocks to expand the island + data.get().setBonusClaimBlocks(data.get().getBonusClaimBlocks() - cost); + return true; + } + return false; + } else { + PLUGIN.getLogger().error("Could not load GP player data for {}.", island.getOwnerName()); + return false; + } + } + } } diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandInfo.java b/src/main/java/net/mohron/skyclaims/command/user/CommandInfo.java index 9cc46a40..8cc7951e 100644 --- a/src/main/java/net/mohron/skyclaims/command/user/CommandInfo.java +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandInfo.java @@ -33,6 +33,8 @@ import net.mohron.skyclaims.team.PrivilegeType; import net.mohron.skyclaims.util.CommandUtil; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; +import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; @@ -45,9 +47,7 @@ import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.text.format.TextStyles; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandInfo extends CommandBase { public static final String HELP_TEXT = "display detailed information on your island."; @@ -75,13 +75,13 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm List islands = Lists.newArrayList(); if (src instanceof Player && !args.hasAny(ISLAND)) { - islands.add(Island.get(((Player) src).getLocation()) + islands.add(IslandManager.get(((Player) src).getLocation()) .orElseThrow(() -> new CommandException( Text.of(TextColors.RED, "You must be on an island to use this command."))) ); } else { Collection islandIds = args.getAll(ISLAND); - islandIds.forEach(i -> Island.get(i).ifPresent(islands::add)); + islandIds.forEach(i -> IslandManager.get(i).ifPresent(islands::add)); if (islands.size() > 1) { return listIslands(); } @@ -94,18 +94,13 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm (src instanceof Player) ? getAdminShortcuts(src, island) : Text.EMPTY, TextColors.YELLOW, "Name", TextColors.WHITE, " : ", island.getName(), getLocked(island), Text.NEW_LINE, - TextColors.YELLOW, "Members", TextColors.WHITE, " : ", getMembers(island), - Text.NEW_LINE, - TextColors.YELLOW, "Size", TextColors.WHITE, " : ", TextColors.LIGHT_PURPLE, - island.getWidth(), + TextColors.YELLOW, "Members", TextColors.WHITE, " : ", getMembers(island), Text.NEW_LINE, + TextColors.YELLOW, "Size", TextColors.WHITE, " : ", TextColors.LIGHT_PURPLE, island.getWidth(), TextColors.GRAY, "x", TextColors.LIGHT_PURPLE, island.getWidth(), Text.NEW_LINE, - TextColors.YELLOW, "Entities", TextColors.WHITE, " : ", getEntities(island), - Text.NEW_LINE, + TextColors.YELLOW, "Entities", TextColors.WHITE, " : ", getEntities(island), Text.NEW_LINE, TextColors.YELLOW, "Spawn", TextColors.WHITE, " : ", getSpawn(island), Text.NEW_LINE, - TextColors.YELLOW, "Created", TextColors.WHITE, " : ", TextColors.GRAY, - sdf.format(island.getDateCreated()), Text.NEW_LINE, - TextColors.YELLOW, "Last Active", TextColors.WHITE, " : ", TextColors.GRAY, - sdf.format(island.getDateLastActive()), Text.NEW_LINE, + TextColors.YELLOW, "Created", TextColors.WHITE, " : ", TextColors.GRAY, sdf.format(island.getDateCreated()), Text.NEW_LINE, + TextColors.YELLOW, "Last Active", TextColors.WHITE, " : ", TextColors.GRAY, sdf.format(island.getDateLastActive()), Text.NEW_LINE, TextColors.YELLOW, "UUID", TextColors.WHITE, " : ", TextColors.GRAY, island.getUniqueId(), Text.NEW_LINE, (island.getClaim().isPresent()) ? Text.of( @@ -167,8 +162,7 @@ private static Text getAdminShortcuts(CommandSource src, Island island) { .onClick(TextActions.executeCallback(s -> { island.clear(); island.delete(); - src.sendMessage( - Text.of(island.getOwnerName(), "'s island has been deleted!")); + src.sendMessage(Text.of(island.getOwnerName(), "'s island has been deleted!")); })), TextColors.WHITE, "] [", Text.builder("NO") @@ -184,34 +178,61 @@ private static Text getAdminShortcuts(CommandSource src, Island island) { Text expand = src.hasPermission(Permissions.COMMAND_EXPAND_OTHERS) ? Text.of( TextColors.WHITE, "[", TextColors.GOLD, Text.builder("Expand") - .onHover(TextActions.showText( - Text.of("Click to expand this island's width by ", TextColors.LIGHT_PURPLE, 2))) + .onHover(TextActions.showText(Text.of("Click to expand this island's width by ", TextColors.LIGHT_PURPLE, 2))) + .onClick(TextActions.executeCallback(consumer -> { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); + + if (island.getWidth() < 512) { + island.expand(1); + src.sendMessage(Text.of( + island.getOwnerName(), + TextColors.GREEN, "'s island has been expanded to ", + TextColors.LIGHT_PURPLE, island.getWidth(), + TextColors.GRAY, "x", + TextColors.LIGHT_PURPLE, island.getWidth(), + TextColors.RESET, "!" + )); + } else { + src.sendMessage(Text.of(island.getOwnerName(), TextColors.RED, "'s island cannot be expanded further!")); + } + + Sponge.getCauseStackManager().popCause(); + })), + TextColors.WHITE, "] " + ) : Text.EMPTY; + + Text shrink = src.hasPermission(Permissions.COMMAND_EXPAND_OTHERS) ? Text.of( + TextColors.WHITE, "[", + TextColors.GOLD, Text.builder("Shrink") + .onHover(TextActions.showText(Text.of("Click to shrink this island's width by ", TextColors.LIGHT_PURPLE, 2))) .onClick(TextActions.executeCallback(consumer -> { - island.expand(1); + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); + + island.shrink(1); src.sendMessage(Text.of( - island.getOwnerName(), "'s island has been expanded to ", - TextColors.LIGHT_PURPLE, island.getWidth(), TextColors.RESET, "x", - TextColors.LIGHT_PURPLE, island.getWidth(), + island.getOwnerName(), "'s island has been shrunk to ", + TextColors.LIGHT_PURPLE, island.getWidth(), TextColors.RESET, "x", TextColors.LIGHT_PURPLE, island.getWidth(), TextColors.RESET, "!" )); + + Sponge.getCauseStackManager().popCause(); })), TextColors.WHITE, "] " ) : Text.EMPTY; - return (teleport.isEmpty() && transfer.isEmpty() && delete.isEmpty() && expand.isEmpty()) - ? Text.EMPTY : Text.of( + return (teleport.isEmpty() && transfer.isEmpty() && delete.isEmpty() && expand.isEmpty() && shrink.isEmpty()) ? Text.EMPTY : Text.of( TextColors.GOLD, "Admin", TextColors.WHITE, " : ", - teleport, transfer, delete, expand, Text.NEW_LINE + teleport, transfer, delete, expand, shrink, Text.NEW_LINE ); } private static Text getMembers(Island island) { List members = Lists.newArrayList(); members.add(PrivilegeType.OWNER.format(island.getOwnerName())); - for (String manager : island.getManagers()) { + for (String manager : island.getManagerNames()) { members.add(PrivilegeType.MANAGER.format(manager)); } - for (String member : island.getMembers()) { + for (String member : island.getMemberNames()) { members.add(PrivilegeType.MEMBER.format(member)); } return Text.joinWith(Text.of(TextColors.GRAY, ", "), members); diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandList.java b/src/main/java/net/mohron/skyclaims/command/user/CommandList.java index a6c5e1e8..96a5e69a 100644 --- a/src/main/java/net/mohron/skyclaims/command/user/CommandList.java +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandList.java @@ -24,13 +24,16 @@ import java.util.UUID; import java.util.function.Consumer; import java.util.stream.Collectors; -import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.command.CommandBase; import net.mohron.skyclaims.command.CommandIsland; import net.mohron.skyclaims.command.argument.Arguments; +import net.mohron.skyclaims.command.argument.IslandSortType; +import net.mohron.skyclaims.command.argument.IslandSortType.Order; +import net.mohron.skyclaims.config.type.MiscConfig; import net.mohron.skyclaims.permissions.Permissions; import net.mohron.skyclaims.util.CommandUtil; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; @@ -43,24 +46,23 @@ import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.text.format.TextStyles; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandList extends CommandBase { public static final String HELP_TEXT = "display a list of the current islands."; private static final Text ISLAND = Text.of("island"); - private static final Text SORT = Text.of("sort"); + private static final Text SORT_TYPE = Text.of("sort type"); + private static final Text SORT_ORDER = Text.of("sort order"); public static void register() { CommandSpec commandSpec = CommandSpec.builder() .permission(Permissions.COMMAND_LIST) .description(Text.of(HELP_TEXT)) - .arguments(GenericArguments.firstParsing( - GenericArguments.optional(Arguments.island(ISLAND)), - GenericArguments.optional(GenericArguments - .requiringPermission(Arguments.sort(SORT), Permissions.COMMAND_LIST_SORT)) - )) + .arguments( + GenericArguments.optionalWeak(Arguments.island(ISLAND)), + GenericArguments.optional(GenericArguments.requiringPermission(GenericArguments.enumValue(SORT_TYPE, IslandSortType.class), Permissions.COMMAND_LIST_SORT)), + GenericArguments.optional(GenericArguments.enumValue(SORT_ORDER, Order.class)) + ) .executor(new CommandList()) .build(); @@ -73,37 +75,52 @@ public static void register() { } } + @SuppressWarnings("unchecked") @Override public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { - if (SkyClaims.islands.isEmpty()) { + if (IslandManager.ISLANDS.isEmpty()) { src.sendMessage(Text.of(TextColors.RED, "There are currently no islands!")); return CommandResult.empty(); } Player player = (src instanceof Player) ? (Player) src : null; Collection islands = args.getAll(ISLAND).stream() - .map(uuid -> SkyClaims.islands.get(uuid)).collect(Collectors.toList()); - Comparator sortType = args.>getOne(SORT) - .orElse(Comparator.comparing(Island::getSortableName)); + .map(uuid -> IslandManager.ISLANDS.get(uuid)).collect(Collectors.toList()); + + MiscConfig config = PLUGIN.getConfig().getMiscConfig(); + IslandSortType primaryListSort = config.getPrimaryListSort(); + IslandSortType sortType = args.getOne(SORT_TYPE).orElse(primaryListSort); + Order order = args.getOne(SORT_ORDER).orElse(sortType.getOrder()); + Comparator sortFunction; + Text sortText; + if (primaryListSort != IslandSortType.NONE && sortType != primaryListSort) { + sortFunction = Comparator.comparing(primaryListSort.getSortFunction(), primaryListSort.getOrder().getComparator()) + .thenComparing(sortType.getSortFunction(), order.getComparator()); + sortText = Text.of( + TextColors.GRAY, primaryListSort.name(), primaryListSort.getOrder().toText(), + TextColors.AQUA, ", ", + TextColors.GRAY, sortType.name(), order.toText() + ); + } else { + sortFunction = Comparator.comparing(sortType.getSortFunction()); + sortText = Text.of(TextColors.GRAY, sortType.name(), order.toText()); + } boolean showUnlocked = src.hasPermission(Permissions.COMMAND_LIST_UNLOCKED); boolean showAll = src.hasPermission(Permissions.COMMAND_LIST_ALL); if (islands.isEmpty()) { - islands = SkyClaims.islands.values(); + islands = IslandManager.ISLANDS.values(); } List listText = islands.stream() - .filter( - i -> player == null || i.isMember(player) || !i.isLocked() && showUnlocked || showAll) - .sorted(sortType) + .filter(i -> player == null || i.isMember(player) || !i.isLocked() && showUnlocked || showAll) + .sorted(sortFunction) .map(island -> Text.of( getAccess(island, src), island.getName().toBuilder() .onHover(TextActions.showText(Text.of("Click here to view island info"))) .onClick(TextActions.executeCallback( - CommandUtil - .createCommandConsumer(src, "islandinfo", island.getUniqueId().toString(), - createReturnConsumer()) + CommandUtil.createCommandConsumer(src, "islandinfo", island.getUniqueId().toString(), createReturnConsumer()) )), getCoords(island, src) )) @@ -113,7 +130,7 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm src.sendMessage(Text.of(TextColors.RED, "There are no islands to display!")); } else if (src instanceof Player) { PaginationList.builder() - .title(Text.of(TextColors.AQUA, "Island List")) + .title(Text.of(TextColors.AQUA, "Island List | ", TextColors.LIGHT_PURPLE, listText.size(), TextColors.AQUA, " | ", sortText)) .padding(Text.of(TextColors.AQUA, TextStyles.STRIKETHROUGH, "-")) .contents(listText) .sendTo(src); @@ -150,14 +167,12 @@ private Text getAccess(Island island, CommandSource src) { } hover = hover.concat(Text.of(island.getName(), TextColors.WHITE, " is ", - island.isLocked() ? Text.of(TextColors.RED, "Locked") - : Text.of(TextColors.GREEN, "Unlocked") + island.isLocked() ? Text.of(TextColors.RED, "Locked") : Text.of(TextColors.GREEN, "Unlocked") )); return Text.of( TextColors.WHITE, " [", - access.toBuilder().onHover(TextActions.showText(hover)) - .onClick(TextActions.executeCallback(toggleLock(island))), + access.toBuilder().onHover(TextActions.showText(hover)).onClick(TextActions.executeCallback(toggleLock(island))), TextColors.WHITE, "] " ); } @@ -189,8 +204,7 @@ private Text getCoords(Island island, CommandSource src) { .hasPermission(Permissions.COMMAND_SPAWN_OTHERS) ? coords.toBuilder() .onHover(TextActions.showText(Text.of("Click here to teleport to this island"))) - .onClick(TextActions.executeCallback( - CommandUtil.createTeleportConsumer(src, island.getSpawn().getLocation()))) + .onClick(TextActions.executeCallback(CommandUtil.createTeleportConsumer(src, island.getSpawn().getLocation()))) .build() : coords; } diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandLock.java b/src/main/java/net/mohron/skyclaims/command/user/CommandLock.java index 6da4801f..1109c611 100644 --- a/src/main/java/net/mohron/skyclaims/command/user/CommandLock.java +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandLock.java @@ -32,9 +32,7 @@ import org.spongepowered.api.command.spec.CommandSpec; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandLock extends CommandBase.LockCommand { public static final String HELP_TEXT = "used to prevent untrusted players from visiting to your island."; @@ -48,9 +46,7 @@ public static void register() { .permission(Permissions.COMMAND_LOCK) .description(Text.of(HELP_TEXT)) .arguments(GenericArguments.firstParsing( - GenericArguments - .optional(GenericArguments.requiringPermission(GenericArguments.literal(ALL, "all"), - Permissions.COMMAND_LOCK_OTHERS)), + GenericArguments.optional(GenericArguments.requiringPermission(GenericArguments.literal(ALL, "all"), Permissions.COMMAND_LOCK_OTHERS)), GenericArguments.optional(Arguments.island(ISLAND, PrivilegeType.MANAGER)) )) .executor(new CommandLock()) @@ -66,8 +62,7 @@ public static void register() { } @Override - public CommandResult execute(CommandSource src, Island island, CommandContext args) - throws CommandException { + public CommandResult execute(CommandSource src, Island island, CommandContext args) throws CommandException { island.setLocked(true); island.getPlayers().forEach(p -> { diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandReset.java b/src/main/java/net/mohron/skyclaims/command/user/CommandReset.java index 97dbee1f..f8eeb8ff 100644 --- a/src/main/java/net/mohron/skyclaims/command/user/CommandReset.java +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandReset.java @@ -18,17 +18,16 @@ package net.mohron.skyclaims.command.user; -import java.util.List; import java.util.Optional; import java.util.function.Consumer; -import java.util.stream.Collectors; -import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.CommandBase.ListSchematicCommand; import net.mohron.skyclaims.command.CommandIsland; import net.mohron.skyclaims.command.argument.Arguments; -import net.mohron.skyclaims.command.argument.SchematicArgument; import net.mohron.skyclaims.permissions.Options; import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.schematic.IslandSchematic; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; @@ -36,18 +35,13 @@ import org.spongepowered.api.command.args.GenericArguments; import org.spongepowered.api.command.spec.CommandSpec; import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.service.pagination.PaginationList; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.text.format.TextStyles; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault -public class CommandReset extends CommandBase.PlayerCommand { +public class CommandReset extends ListSchematicCommand { public static final String HELP_TEXT = "reset your island and inventory so you can start over."; - private static final Text SCHEMATIC = Text.of("schematic"); private static final Text KEEP_INV = Text.of("keepinv"); public static void register() { @@ -56,9 +50,7 @@ public static void register() { .description(Text.of(HELP_TEXT)) .arguments( GenericArguments.optional(Arguments.schematic(SCHEMATIC)), - GenericArguments.optional(GenericArguments - .requiringPermission(GenericArguments.bool(KEEP_INV), - Permissions.COMMAND_RESET_KEEP_INV)) + GenericArguments.optional(GenericArguments.requiringPermission(GenericArguments.bool(KEEP_INV), Permissions.COMMAND_RESET_KEEP_INV)) ) .executor(new CommandReset()) .build(); @@ -74,78 +66,57 @@ public static void register() { @Override public CommandResult execute(Player player, CommandContext args) throws CommandException { - Island island = Island.getByOwner(player.getUniqueId()) - .orElseThrow( - () -> new CommandException(Text.of("You must have an island to run this command!"))); - boolean keepInv = args.hasAny(KEEP_INV); + Island island = IslandManager.getByOwner(player.getUniqueId()) + .orElseThrow(() -> new CommandException(Text.of("You must have an island to run this command!"))); + boolean keepInv = args.getOne(KEEP_INV).orElse(false); - Optional schematic = args.getOne(SCHEMATIC); + Optional schematic = args.getOne(SCHEMATIC); + Optional defaultSchematic = Options.getDefaultSchematic(player.getUniqueId()); if (schematic.isPresent()) { getConfirmation(island, schematic.get(), keepInv).accept(player); - } else if (PLUGIN.getConfig().getMiscConfig().isListSchematics() - && SchematicArgument.SCHEMATICS.size() > 1) { - listSchematics(player, island, keepInv); + } else if (!defaultSchematic.isPresent()) { + return listSchematics(player, s -> getConfirmation(island, s, keepInv)); } else { - getConfirmation(island, Options.getDefaultSchematic(player.getUniqueId()), keepInv) - .accept(player); + getConfirmation(island, defaultSchematic.get(), keepInv).accept(player); } return CommandResult.empty(); } - private void listSchematics(Player player, Island island, boolean keepInv) { - boolean checkPerms = PLUGIN.getConfig().getPermissionConfig().isSeparateSchematicPerms(); - List schematics = SchematicArgument.SCHEMATICS.keySet().stream() - .filter(s -> !checkPerms || player - .hasPermission(Permissions.COMMAND_ARGUMENTS_SCHEMATICS + "." + s.toLowerCase())) - .map(s -> Text.builder(s) - .onClick(TextActions.executeCallback(getConfirmation(island, s, keepInv))).build()) - .collect(Collectors.toList()); - PaginationList.builder() - .title(Text.of(TextColors.AQUA, "Starter Islands")) - .padding(Text.of(TextColors.AQUA, TextStyles.STRIKETHROUGH, "-")) - .contents(schematics) - .sendTo(player); - } - - private Consumer getConfirmation(Island island, String schematic, - boolean keepInv) { + private Consumer getConfirmation(Island island, IslandSchematic schematic, boolean keepInv) { return src -> { if (src instanceof Player) { Player player = (Player) src; player.sendMessage(Text.of( - "Are you sure you want to reset your island", !keepInv ? " and inventory" : Text.EMPTY, + "Are you sure you want to reset your island", + !keepInv ? " and inventory" : Text.EMPTY, "? This cannot be undone!", Text.NEW_LINE, TextColors.GOLD, "Do you want to continue?", Text.NEW_LINE, TextColors.WHITE, "[", Text.builder("YES") .color(TextColors.GREEN) .onHover(TextActions.showText(Text.of("Click to reset"))) - .onClick( - TextActions.executeCallback(resetIsland(player, island, schematic, keepInv))), + .onClick(TextActions.executeCallback(resetIsland(player, island, schematic, keepInv))), TextColors.WHITE, "] [", Text.builder("NO") .color(TextColors.RED) .onHover(TextActions.showText(Text.of("Click to cancel"))) - .onClick(TextActions - .executeCallback(s -> s.sendMessage(Text.of("Island reset canceled!")))), + .onClick(TextActions.executeCallback(s -> s.sendMessage(Text.of("Island reset canceled!")))), TextColors.WHITE, "]" )); } }; } - private Consumer resetIsland(Player player, Island island, String schematic, - boolean keepInv) { + private Consumer resetIsland(Player player, Island island, IslandSchematic schematic, boolean keepInv) { return src -> { + // The keep inv argument will skip individual permission checks. if (!keepInv) { - player.getEnderChestInventory().clear(); - player.getInventory().clear(); + clearIslandMemberInventories(island, Permissions.KEEP_INV_PLAYER_RESET, Permissions.KEEP_INV_ENDERCHEST_RESET); } // Teleport any players located in the island's region to spawn - island.getPlayers() - .forEach(p -> p.setLocationSafely(PLUGIN.getConfig().getWorldConfig().getSpawn())); + island.getPlayers().forEach(p -> p.setLocationSafely(PLUGIN.getConfig().getWorldConfig().getSpawn())); player.sendMessage(Text.of("Please be patient while your island is reset.")); island.reset(schematic, !keepInv); diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandSetBiome.java b/src/main/java/net/mohron/skyclaims/command/user/CommandSetBiome.java index 24304af6..ab1a9c3d 100644 --- a/src/main/java/net/mohron/skyclaims/command/user/CommandSetBiome.java +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandSetBiome.java @@ -25,6 +25,7 @@ import net.mohron.skyclaims.permissions.Permissions; import net.mohron.skyclaims.util.WorldUtil; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandPermissionException; import org.spongepowered.api.command.CommandResult; @@ -34,10 +35,8 @@ import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; import org.spongepowered.api.world.biome.BiomeType; -@NonnullByDefault public class CommandSetBiome extends CommandBase.PlayerCommand { public static final String HELP_TEXT = "set the biome of a block, chunk or island."; @@ -67,11 +66,9 @@ public static void register() { @Override public CommandResult execute(Player player, CommandContext args) throws CommandException { BiomeType biome = args.getOne(BIOME) - .orElseThrow( - () -> new CommandException(Text.of("You must supply a biome to use this command"))); - Island island = Island.get(player.getLocation()) - .orElseThrow( - () -> new CommandException(Text.of("You must be on an island to use this command"))); + .orElseThrow(() -> new CommandException(Text.of("You must supply a biome to use this command"))); + Island island = IslandManager.get(player.getLocation()) + .orElseThrow(() -> new CommandException(Text.of("You must be on an island to use this command"))); if (!island.isManager(player) && !player.hasPermission(Permissions.COMMAND_SET_BIOME_OTHERS)) { throw new CommandPermissionException( diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandSetName.java b/src/main/java/net/mohron/skyclaims/command/user/CommandSetName.java new file mode 100644 index 00000000..60000292 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandSetName.java @@ -0,0 +1,76 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.command.user; + +import net.mohron.skyclaims.command.CommandBase; +import net.mohron.skyclaims.command.CommandIsland; +import net.mohron.skyclaims.command.argument.Arguments; +import net.mohron.skyclaims.permissions.Permissions; +import net.mohron.skyclaims.team.PrivilegeType; +import net.mohron.skyclaims.world.Island; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.args.GenericArguments; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.text.serializer.TextSerializers; + +public class CommandSetName extends CommandBase.IslandCommand { + + public static final String HELP_TEXT = "set your name of your island."; + private static final Text NAME = Text.of("name"); + + public static void register() { + CommandSpec commandSpec = CommandSpec.builder() + .permission(Permissions.COMMAND_SET_NAME) + .description(Text.of(HELP_TEXT)) + .arguments( + GenericArguments.optionalWeak(Arguments.island(ISLAND, PrivilegeType.MANAGER)), + GenericArguments.text(NAME, TextSerializers.FORMATTING_CODE, true) + ) + .executor(new CommandSetName()) + .build(); + + try { + CommandIsland.addSubCommand(commandSpec, "setname"); + PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); + PLUGIN.getLogger().debug("Registered command: CommandSetName"); + } catch (UnsupportedOperationException e) { + PLUGIN.getLogger().error("Failed to register command: CommandSetName", e); + } + } + + @Override + public CommandResult execute(Player player, Island island, CommandContext args) throws CommandException { + if (!island.isManager(player) && !player.hasPermission(Permissions.COMMAND_SET_NAME_OTHERS)) { + throw new CommandException(Text.of( + TextColors.RED, "Only an island ", PrivilegeType.MANAGER.toText(), TextColors.RED, " may use this command!" + )); + } + + Text name = args.getOne(NAME).orElse(null); + island.setName(name); + player.sendMessage(Text.of(TextColors.GREEN, "Your island name has been changed to ", island.getName())); + + return CommandResult.success(); + } +} diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandSetSpawn.java b/src/main/java/net/mohron/skyclaims/command/user/CommandSetSpawn.java index 3fd2e5ac..9c37078e 100644 --- a/src/main/java/net/mohron/skyclaims/command/user/CommandSetSpawn.java +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandSetSpawn.java @@ -22,6 +22,7 @@ import net.mohron.skyclaims.command.CommandIsland; import net.mohron.skyclaims.permissions.Permissions; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.args.CommandContext; @@ -29,9 +30,7 @@ import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandSetSpawn extends CommandBase.PlayerCommand { public static final String HELP_TEXT = "set your spawn location for your island."; @@ -54,9 +53,8 @@ public static void register() { @Override public CommandResult execute(Player player, CommandContext args) throws CommandException { - Island island = Island.get(player.getLocation()) - .orElseThrow( - () -> new CommandException(Text.of("You must be on an island to use this command!"))); + Island island = IslandManager.get(player.getLocation()) + .orElseThrow(() -> new CommandException(Text.of("You must be on an island to use this command!"))); if (!island.isManager(player) && !player.hasPermission(Permissions.COMMAND_SET_SPAWN_OTHERS)) { throw new CommandException(Text.of("Only the island owner may use this command!")); @@ -66,8 +64,8 @@ public CommandResult execute(Player player, CommandContext args) throws CommandE player.sendMessage(Text.of("Your island spawn has been set to ", TextColors.GRAY, "(", TextColors.LIGHT_PURPLE, island.getSpawn().getPosition().getFloorX(), TextColors.GRAY, ", ", TextColors.LIGHT_PURPLE, island.getSpawn().getPosition().getFloorY(), TextColors.GRAY, ", ", - TextColors.LIGHT_PURPLE, island.getSpawn().getPosition().getFloorZ(), TextColors.GRAY, - ")")); + TextColors.LIGHT_PURPLE, island.getSpawn().getPosition().getFloorZ(), TextColors.GRAY, ")" + )); return CommandResult.success(); } diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandSpawn.java b/src/main/java/net/mohron/skyclaims/command/user/CommandSpawn.java index cd1fbf89..5271c363 100644 --- a/src/main/java/net/mohron/skyclaims/command/user/CommandSpawn.java +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandSpawn.java @@ -23,6 +23,7 @@ import net.mohron.skyclaims.permissions.Permissions; import net.mohron.skyclaims.util.CommandUtil; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.args.CommandContext; @@ -32,9 +33,7 @@ import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandSpawn extends CommandBase.PlayerCommand { public static final String HELP_TEXT = "teleport to an island's spawn point."; @@ -60,14 +59,12 @@ public static void register() { @Override public CommandResult execute(Player player, CommandContext args) throws CommandException { User user = args.getOne(USER).orElse(player); - Island island = Island.getByOwner(user.getUniqueId()) + Island island = IslandManager.getByOwner(user.getUniqueId()) .orElseThrow(() -> new CommandException( Text.of(TextColors.RED, user.getName(), " must have an Island to use this command!"))); - if (island.isLocked() && !island.isMember(player) && !player - .hasPermission(Permissions.COMMAND_SPAWN_OTHERS)) { - throw new CommandException(Text.of(TextColors.RED, "You must be trusted on ", user.getName(), - "'s island to use this command!")); + if (island.isLocked() && !island.isMember(player) && !player.hasPermission(Permissions.COMMAND_SPAWN_OTHERS)) { + throw new CommandException(Text.of(TextColors.RED, "You must be trusted on ", user.getName(), "'s island to use this command!")); } PLUGIN.getGame().getScheduler().createTaskBuilder() diff --git a/src/main/java/net/mohron/skyclaims/command/user/CommandUnlock.java b/src/main/java/net/mohron/skyclaims/command/user/CommandUnlock.java index c30bd3c0..d4c2213e 100644 --- a/src/main/java/net/mohron/skyclaims/command/user/CommandUnlock.java +++ b/src/main/java/net/mohron/skyclaims/command/user/CommandUnlock.java @@ -32,9 +32,7 @@ import org.spongepowered.api.command.spec.CommandSpec; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.annotation.NonnullByDefault; -@NonnullByDefault public class CommandUnlock extends CommandBase.LockCommand { public static final String HELP_TEXT = "used to allow untrusted players to visit your island."; @@ -48,9 +46,7 @@ public static void register() { .permission(Permissions.COMMAND_LOCK) .description(Text.of(HELP_TEXT)) .arguments(GenericArguments.firstParsing( - GenericArguments - .optional(GenericArguments.requiringPermission(GenericArguments.literal(ALL, "all"), - Permissions.COMMAND_LOCK_OTHERS)), + GenericArguments.optional(GenericArguments.requiringPermission(GenericArguments.literal(ALL, "all"), Permissions.COMMAND_LOCK_OTHERS)), GenericArguments.optional(Arguments.island(ISLAND, PrivilegeType.MANAGER)) )) .executor(new CommandUnlock()) @@ -66,8 +62,7 @@ public static void register() { } @Override - public CommandResult execute(CommandSource src, Island island, CommandContext args) - throws CommandException { + public CommandResult execute(CommandSource src, Island island, CommandContext args) throws CommandException { island.setLocked(false); src.sendMessage(Text.of(island.getName(), TextColors.GREEN, " is now unlocked!")); diff --git a/src/main/java/net/mohron/skyclaims/command/user/package-info.java b/src/main/java/net/mohron/skyclaims/command/user/package-info.java new file mode 100644 index 00000000..2343f902 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/command/user/package-info.java @@ -0,0 +1,21 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ +@NonnullByDefault +package net.mohron.skyclaims.command.user; + +import org.spongepowered.api.util.annotation.NonnullByDefault; \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/config/ConfigManager.java b/src/main/java/net/mohron/skyclaims/config/ConfigManager.java index 3958658b..20690d2d 100644 --- a/src/main/java/net/mohron/skyclaims/config/ConfigManager.java +++ b/src/main/java/net/mohron/skyclaims/config/ConfigManager.java @@ -18,7 +18,6 @@ package net.mohron.skyclaims.config; -import com.google.common.io.Resources; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -51,7 +50,6 @@ public ConfigManager(ConfigurationLoader loader) { this.load(); this.initializeData(); - this.initializeSchematic(); } /** @@ -91,40 +89,4 @@ private void initializeData() { } } } - - /** - * Create the default schematic file, from resource, into the config-specified folder - */ - private void initializeSchematic() { - String[] schematics = {"gardenofglass", "grass", "sand", "skyfactory", "skyresources", "snow", - "wood"}; - File schemDir = Paths.get(PLUGIN.getConfigDir() + File.separator + "schematics").toFile(); - if (!schemDir.exists() || !schemDir.isDirectory()) { - try { - boolean success = schemDir.mkdir(); - if (!success) { - throw new IOException(); - } - } catch (SecurityException | IOException e) { - LOGGER - .error(String.format("Failed to create schematics directory.\r\n %s", e.getMessage())); - } - } - try { - //noinspection ConstantConditions - schemDir.list() is being checked for null - if (schemDir.list() == null || schemDir.list().length < 1) { - for (String name : schematics) { - File schematic = Paths - .get(String.format("%s%s%s.schematic", schemDir.toPath(), File.separator, name)) - .toFile(); - //noinspection ConstantConditions - Resource will always be included - Resources.asByteSource(this.getClass().getClassLoader() - .getResource(name + ".schematic")) - .copyTo(com.google.common.io.Files.asByteSink(schematic)); - } - } - } catch (SecurityException | IOException e) { - LOGGER.error(String.format("Failed to create default schematic.\r\n %s", e.getMessage())); - } - } } \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/config/type/CommandConfig.java b/src/main/java/net/mohron/skyclaims/config/type/CommandConfig.java index 3627eff6..2cb99faf 100644 --- a/src/main/java/net/mohron/skyclaims/config/type/CommandConfig.java +++ b/src/main/java/net/mohron/skyclaims/config/type/CommandConfig.java @@ -28,14 +28,8 @@ public class CommandConfig { @Setting(value = "Base-Command-Alias", comment = "The alias to use as the base command.") private List baseAlias = Lists.newArrayList("is", "island"); - @Setting(value = "Admin-Command-Alias", comment = "The alias to use as the base admin command.") - private List adminAlias = Lists.newArrayList("sc", "isa"); public List getBaseAlias() { return baseAlias.isEmpty() ? Lists.newArrayList("is") : baseAlias; } - - public List getAdminAlias() { - return adminAlias.isEmpty() ? Lists.newArrayList("sc") : adminAlias; - } } diff --git a/src/main/java/net/mohron/skyclaims/config/type/EconomyConfig.java b/src/main/java/net/mohron/skyclaims/config/type/EconomyConfig.java new file mode 100644 index 00000000..a92b1b7b --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/config/type/EconomyConfig.java @@ -0,0 +1,30 @@ +package net.mohron.skyclaims.config.type; + +import java.util.Optional; +import ninja.leaping.configurate.objectmapping.Setting; +import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.service.economy.Currency; +import org.spongepowered.api.service.economy.EconomyService; + +@ConfigSerializable +public class EconomyConfig { + + @Setting(value = "use-claim-blocks", comment = "If set to true, claim blocks will be used as a currency.") + private boolean useClaimBlocks = false; + + @Setting(value = "currency", comment = "The name of the currency to use when a Economy plugin is available.\n" + + "The default currency will be used if not configured or an invalid currency is configured.") + private String currency = ""; + + public boolean isUseClaimBlocks() { + return useClaimBlocks; + } + + public Optional getCurrency() { + return Sponge.getServiceManager().provide(EconomyService.class) + .flatMap(economyService -> economyService.getCurrencies().stream() + .filter(c -> c.getName().equalsIgnoreCase(currency)) + .findAny()); + } +} diff --git a/src/main/java/net/mohron/skyclaims/config/type/GlobalConfig.java b/src/main/java/net/mohron/skyclaims/config/type/GlobalConfig.java index 75b58358..d52ae3c6 100644 --- a/src/main/java/net/mohron/skyclaims/config/type/GlobalConfig.java +++ b/src/main/java/net/mohron/skyclaims/config/type/GlobalConfig.java @@ -29,6 +29,8 @@ public class GlobalConfig { private int version; @Setting(value = "Command") private CommandConfig commandConfig = new CommandConfig(); + @Setting(value = "Economy") + private EconomyConfig economyConfig = new EconomyConfig(); @Setting(value = "Entity") private EntityConfig entityConfig = new EntityConfig(); @Setting(value = "Integration") @@ -56,6 +58,10 @@ public CommandConfig getCommandConfig() { return commandConfig; } + public EconomyConfig getEconomyConfig() { + return economyConfig; + } + public EntityConfig getEntityConfig() { return entityConfig; } diff --git a/src/main/java/net/mohron/skyclaims/config/type/MiscConfig.java b/src/main/java/net/mohron/skyclaims/config/type/MiscConfig.java index 8ddc9057..7d202e3f 100644 --- a/src/main/java/net/mohron/skyclaims/config/type/MiscConfig.java +++ b/src/main/java/net/mohron/skyclaims/config/type/MiscConfig.java @@ -22,58 +22,75 @@ import java.util.ArrayList; import java.util.List; import net.mohron.skyclaims.SkyClaims; +import net.mohron.skyclaims.command.argument.IslandSortType; import ninja.leaping.configurate.objectmapping.Setting; import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable; +import org.spongepowered.api.item.ItemType; @ConfigSerializable public class MiscConfig { + public enum ClearItemsType {BLACKLIST, WHITELIST} + @Setting(value = "Log-Biomes", comment = "Whether a list of biomes and their permissions should be logged.") private boolean logBiomes = false; - @Setting(value = "Island-on-Join", comment = "Automatically create an island for a player on join.") + @Setting(value = "Island-on-Join", comment = "Automatically create an island for a player on join.\n" + + "Requires a valid default schematic to be set (skyclaims.default-schematic)") private boolean islandOnJoin = false; - @Setting(value = "List-Schematics", comment = "Whether players with access to multiple schematics see a list when not specifying a schematic.") - private boolean listSchematics = true; @Setting(value = "Teleport-on-Creation", comment = "Automatically teleport the owner to their island on creation.") private boolean teleportOnCreate = true; - @Setting(value = "Create-Commands", comment = "Commands to run on island creation and reset. Use @p in place of the player's name.") - private List createCommands = new ArrayList<>(); - @Setting(value = "Reset-Commands", comment = "Commands to run on island resets only. Use @p in place of the player's name.") - private List resetCommands = new ArrayList<>(); + @Setting(value = "Text-Schematic-List", comment = "Enable to use a text based schematic list instead of a chest UI.") + private boolean textSchematicList = false; + @Setting(value = "Island-Commands", comment = "Commands to run on island creation, join or reset. Use @p in place of the player's name.") + private List islandCommands = new ArrayList<>(); + @Setting(value = "Clear-Items", comment = "Items to be removed from players inventories when going on or off an island / claim") + private List clearItems = new ArrayList<>(); + @Setting(value = "Clear-Items-Type", comment = "Sets whether the Clear-Items list should be treated as a blacklist or whitelist.") + private ClearItemsType clearItemsType = ClearItemsType.BLACKLIST; @Setting(value = "Date-Format", comment = "The date format used throughout the plugin.\n" + "http://docs.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html") private String dateFormat = "MMMM d, yyyy h:mm a"; + @Setting(value = "Primary-List-Sort", comment = "If set, SkyClaims will sort islands in the list command by this before applying the sort argument.") + private IslandSortType primaryListSort = IslandSortType.NONE; public boolean isLogBiomes() { return logBiomes; } - public boolean createIslandOnJoin() { + public boolean isCreateIslandOnJoin() { return islandOnJoin; } - public boolean isListSchematics() { - return listSchematics; - } - public boolean isTeleportOnCreate() { return teleportOnCreate; } - public List getCreateCommands() { - return createCommands; + public boolean isTextSchematicList() { + return textSchematicList; + } + + public List getIslandCommands() { + return islandCommands; } - public List getResetCommands() { - return resetCommands; + public List getClearItems() { + return clearItems; + } + + public ClearItemsType getClearItemsType() { + return clearItemsType; } public SimpleDateFormat getDateFormat() { try { return new SimpleDateFormat(dateFormat); } catch (IllegalArgumentException e) { - SkyClaims.getInstance().getLogger().info("Invalid Date Format: {}", dateFormat); + SkyClaims.getInstance().getLogger().error("Invalid Date Format: {}", dateFormat); return new SimpleDateFormat("MMMM d, yyyy h:mm a"); } } -} \ No newline at end of file + + public IslandSortType getPrimaryListSort() { + return primaryListSort; + } +} diff --git a/src/main/java/net/mohron/skyclaims/config/type/MysqlConfig.java b/src/main/java/net/mohron/skyclaims/config/type/MysqlConfig.java index cc41ceb4..da8c4d19 100644 --- a/src/main/java/net/mohron/skyclaims/config/type/MysqlConfig.java +++ b/src/main/java/net/mohron/skyclaims/config/type/MysqlConfig.java @@ -28,7 +28,7 @@ public class MysqlConfig { private String databaseName; @Setting("Location") private String location; - @Setting("Table-Prefix") + @Setting("Table-Prefix (not implemented)") private String tablePrefix; @Setting("Username") private String username; diff --git a/src/main/java/net/mohron/skyclaims/config/type/WorldConfig.java b/src/main/java/net/mohron/skyclaims/config/type/WorldConfig.java index f89667de..c8dc6d6b 100644 --- a/src/main/java/net/mohron/skyclaims/config/type/WorldConfig.java +++ b/src/main/java/net/mohron/skyclaims/config/type/WorldConfig.java @@ -18,10 +18,14 @@ package net.mohron.skyclaims.config.type; +import com.google.common.collect.Lists; +import java.util.List; +import java.util.Optional; import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.util.WorldUtil; import ninja.leaping.configurate.objectmapping.Setting; import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable; +import org.apache.commons.lang3.StringUtils; import org.spongepowered.api.Sponge; import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; @@ -33,20 +37,30 @@ public class WorldConfig { private String worldName = "world"; @Setting(value = "Spawn-World", comment = "Use to override the world used when sending players to spawn.") private String spawnWorld = ""; - // @Setting(value = "Void-Dimensions", comment = "A list of world names to generate as void. Default: world, DIM-1, DIM1") -// private List voidDimensions = Lists.newArrayList("world", "DIM-1", "DIM1"); + @Setting(value = "Void-Dimensions", comment = "A list of world names to generate as void. Default: world, DIM-1, DIM1") + private List voidDimensions = Lists.newArrayList("world", "DIM-1", "DIM1"); @Setting(value = "Island-Height", comment = "Height to build islands at (1-255). Default: 72") private int islandHeight = 72; @Setting(value = "Spawn-Regions", comment = "The height & width of regions to reserve for spawn (min 1). Default: 1") private int spawnRegions = 1; + @Setting(value = "Preset-Code", comment = "A flat world preset code to use when regenerating a region. Only the block ID list is used.\n" + + "See https://minecraft.gamepedia.com/Superflat#Preset_code_format for more details.") + private String presetCode = ""; + @Setting(value = "Regen-On-Create", comment = "If enabled, SkyClaims will regen the target region before an island is created.") + private boolean regenOnCreate = false; public String getWorldName() { return worldName; } public World getWorld() { - return SkyClaims.getInstance().getGame().getServer().getWorld(worldName) - .orElse(WorldUtil.getDefaultWorld()); + final Optional world = SkyClaims.getInstance().getGame().getServer().getWorld(worldName); + if (world.isPresent()) { + return world.get(); + } else { + SkyClaims.getInstance().getLogger().warn("Unable to locate world {}.", worldName); + return WorldUtil.getDefaultWorld(); + } } public Location getSpawn() { @@ -55,9 +69,13 @@ public Location getSpawn() { return world.isLoaded() ? world.getSpawnLocation() : getWorld().getSpawnLocation(); } -// public List getVoidDimensions() { -// return voidDimensions; -// } + public List getVoidDimensions() { + return voidDimensions; + } + + public boolean isSeparateSpawn() { + return !StringUtils.isEmpty(spawnWorld) && Sponge.getServer().getWorld(spawnWorld).isPresent(); + } public int getIslandHeight() { return Math.max(1, Math.min(255, islandHeight)); @@ -67,4 +85,11 @@ public int getSpawnRegions() { return Math.max(1, spawnRegions); } + public String getPresetCode() { + return presetCode; + } + + public boolean isRegenOnCreate() { + return regenOnCreate; + } } \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/database/Database.java b/src/main/java/net/mohron/skyclaims/database/Database.java index 5951ef40..c3579db0 100644 --- a/src/main/java/net/mohron/skyclaims/database/Database.java +++ b/src/main/java/net/mohron/skyclaims/database/Database.java @@ -57,8 +57,7 @@ void createTable() { // Create the islands table (execute statement) statement.executeUpdate(table); } catch (SQLException e) { - e.printStackTrace(); - SkyClaims.getInstance().getLogger().error("Unable to create SkyClaims database"); + SkyClaims.getInstance().getLogger().error("Unable to create SkyClaims database", e); } } @@ -67,11 +66,11 @@ void createTable() { * * @return Returns a new DataStore generated from the database data */ - public HashMap loadData() { + public Map loadData() { HashMap islands = Maps.newHashMap(); - try (Statement statement = getConnection().createStatement()) { - ResultSet results = statement.executeQuery("SELECT * FROM islands"); + try (Statement statement = getConnection().createStatement(); + ResultSet results = statement.executeQuery("SELECT * FROM islands")) { while (results.next()) { UUID islandId = UUID.fromString(results.getString("island")); @@ -89,12 +88,10 @@ public HashMap loadData() { } return islands; } catch (SQLException e) { - e.printStackTrace(); - SkyClaims.getInstance().getLogger().error("Unable to read from the database."); + SkyClaims.getInstance().getLogger().error("Unable to read from the database.", e); } - SkyClaims.getInstance().getLogger() - .info("Loaded SkyClaims MySQL Data. Count: {}", islands.size()); + SkyClaims.getInstance().getLogger().info("Loaded SkyClaims MySQL Data. Count: {}", islands.size()); return islands; } @@ -139,8 +136,7 @@ public void saveIsland(Island island) { statement.execute(); } catch (SQLException e) { - SkyClaims.getInstance().getLogger() - .error("Error inserting Island into the database: {}", e.getMessage()); + SkyClaims.getInstance().getLogger().error("Error inserting Island into the database:", e); } } @@ -157,8 +153,7 @@ public void removeIsland(Island island) { statement.execute(); } catch (SQLException e) { - SkyClaims.getInstance().getLogger() - .error("Error removing Island from the database: {}", e.getMessage()); + SkyClaims.getInstance().getLogger().error("Error removing Island from the database:", e); } } @@ -171,10 +166,11 @@ public int countColumns() { int total = 0; String sql = "SELECT * FROM islands LIMIT 1"; - try (PreparedStatement statement = getConnection().prepareStatement(sql)) { - return statement.executeQuery().getMetaData().getColumnCount(); + try (PreparedStatement statement = getConnection().prepareStatement(sql); + ResultSet rs = statement.executeQuery()) { + return rs.getMetaData().getColumnCount(); } catch (SQLException e) { - e.printStackTrace(); + SkyClaims.getInstance().getLogger().error("Unable to get database column count:", e); } return total; diff --git a/src/main/java/net/mohron/skyclaims/database/IDatabase.java b/src/main/java/net/mohron/skyclaims/database/IDatabase.java index fb2d4c61..ebc155f9 100644 --- a/src/main/java/net/mohron/skyclaims/database/IDatabase.java +++ b/src/main/java/net/mohron/skyclaims/database/IDatabase.java @@ -19,14 +19,13 @@ package net.mohron.skyclaims.database; import java.util.Collection; -import java.util.HashMap; import java.util.Map; import java.util.UUID; import net.mohron.skyclaims.world.Island; public interface IDatabase { - HashMap loadData(); + Map loadData(); void saveData(Collection islands); diff --git a/src/main/java/net/mohron/skyclaims/database/MysqlDatabase.java b/src/main/java/net/mohron/skyclaims/database/MysqlDatabase.java index 63dff56c..988628d3 100644 --- a/src/main/java/net/mohron/skyclaims/database/MysqlDatabase.java +++ b/src/main/java/net/mohron/skyclaims/database/MysqlDatabase.java @@ -30,6 +30,7 @@ public class MysqlDatabase extends Database { private String connectionString; private String databaseLocation; private String databaseTablePrefix; + private String databaseName; private String username; private String password; private Integer port; @@ -38,20 +39,19 @@ public MysqlDatabase() { this.config = SkyClaims.getInstance().getConfig().getStorageConfig().getMysqlConfig(); databaseLocation = config.getLocation(); databaseTablePrefix = config.getTablePrefix(); + databaseName = config.getDatabaseName(); username = config.getUsername(); password = config.getPassword(); port = config.getPort(); - connectionString = String.format("jdbc:mysql://%s:%s/%s", databaseLocation, port, "islands"); + connectionString = String.format("jdbc:mysql://%s:%s/%s", databaseLocation, port, databaseName); try { Class.forName("com.mysql.jdbc.Driver"); getConnection(); } catch (ClassNotFoundException e) { - SkyClaims.getInstance().getLogger().error("Unable to load MySQL JDBC driver!"); - e.printStackTrace(); + SkyClaims.getInstance().getLogger().error("Unable to load MySQL JDBC driver!", e); } catch (SQLException e) { - SkyClaims.getInstance().getLogger().error("Unable to connect to the database!"); - e.printStackTrace(); + SkyClaims.getInstance().getLogger().error("Unable to connect to the database:", e); } createTable(); diff --git a/src/main/java/net/mohron/skyclaims/database/SqliteDatabase.java b/src/main/java/net/mohron/skyclaims/database/SqliteDatabase.java index 39188116..31e1d346 100644 --- a/src/main/java/net/mohron/skyclaims/database/SqliteDatabase.java +++ b/src/main/java/net/mohron/skyclaims/database/SqliteDatabase.java @@ -30,6 +30,7 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; +import java.util.Map; import java.util.UUID; import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.config.type.StorageConfig; @@ -50,11 +51,10 @@ public SqliteDatabase() { String.format("jdbc:sqlite:%s%sskyclaims.db", config.getLocation(), File.separator)); SkyClaims.getInstance().getLogger().info("Successfully connected to SkyClaims SQLite DB."); } catch (ClassNotFoundException e) { - e.printStackTrace(); - SkyClaims.getInstance().getLogger().error("Unable to load the JDBC driver"); + SkyClaims.getInstance().getLogger().error("Unable to load the JDBC driver:", e); return; } catch (SQLException e) { - e.printStackTrace(); + SkyClaims.getInstance().getLogger().error("Unable to connect to SkyClaims SQLite DB:", e); return; } @@ -102,9 +102,7 @@ public void migrate() { saveData(islands); SkyClaims.getInstance().getLogger().info("Repopulated islands table, migration complete."); } catch (SQLException e) { - e.printStackTrace(); - SkyClaims.getInstance().getLogger() - .error("Unable to drop islands table, check the console"); + SkyClaims.getInstance().getLogger().error("Unable to drop islands table, check the console:", e); } } @@ -114,17 +112,13 @@ public void migrate() { * Creates a file backup of the existing database in the configured directory */ public void backup() { - File inputFile = new File( - String.format("%s%sskyclaims.db", config.getLocation(), File.separator)); - File outputFile = new File( - String.format("%s%sskyclaims_backup.db", config.getLocation(), File.separator)); + File inputFile = new File(String.format("%s%sskyclaims.db", config.getLocation(), File.separator)); + File outputFile = new File(String.format("%s%sskyclaims_backup.db", config.getLocation(), File.separator)); try { Files.copy(inputFile, outputFile); } catch (IOException e) { - e.printStackTrace(); - SkyClaims.getInstance().getLogger() - .error("Error occurred while backing up legacy SQLite DB."); + SkyClaims.getInstance().getLogger().error("Error occurred while backing up legacy SQLite DB:", e); } } @@ -134,11 +128,11 @@ public void backup() { * @return Returns a new DataStore generated from the database data */ @Override - public HashMap loadData() { + public Map loadData() { HashMap islands = Maps.newHashMap(); - try (Statement statement = getConnection().createStatement()) { - ResultSet results = statement.executeQuery("SELECT * FROM islands"); + try (Statement statement = getConnection().createStatement(); + ResultSet results = statement.executeQuery("SELECT * FROM islands")) { UUID claimId; while (results.next()) { if (results.getString("claim").length() != 36) { @@ -160,12 +154,10 @@ public HashMap loadData() { islands.put(islandId, island); } } catch (SQLException e) { - e.printStackTrace(); - SkyClaims.getInstance().getLogger().error("Unable to read from the database."); + SkyClaims.getInstance().getLogger().error("Unable to read from the database:", e); } - SkyClaims.getInstance().getLogger() - .info("Loaded SkyClaims SQLite Data. Count: {}", islands.size()); + SkyClaims.getInstance().getLogger().info("Loaded SkyClaims SQLite Data. Count: {}", islands.size()); return islands; } @@ -177,9 +169,8 @@ public HashMap loadData() { private HashMap loadLegacyData() { HashMap islands = Maps.newHashMap(); - try (Statement statement = getConnection().createStatement()) { - ResultSet results = statement.executeQuery("SELECT * FROM islands"); - + try (Statement statement = getConnection().createStatement(); + ResultSet results = statement.executeQuery("SELECT * FROM islands")) { while (results.next()) { UUID ownerId = UUID.fromString(results.getString("owner")); UUID claimId = UUID.fromString(results.getString("id")); @@ -194,12 +185,10 @@ private HashMap loadLegacyData() { islands.put(id, island); } } catch (SQLException e) { - e.printStackTrace(); - SkyClaims.getInstance().getLogger().error("Unable to read from the database."); + SkyClaims.getInstance().getLogger().error("Unable to read from the database:", e); } - SkyClaims.getInstance().getLogger() - .info("Loaded SkyClaims SQLite Legacy Data. Count: {}", islands.size()); + SkyClaims.getInstance().getLogger().info("Loaded SkyClaims SQLite Legacy Data. Count: {}", islands.size()); return islands; } } \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/integration/nucleus/CommandHome.java b/src/main/java/net/mohron/skyclaims/integration/nucleus/CommandHome.java index a4af4e27..0d04eaf2 100644 --- a/src/main/java/net/mohron/skyclaims/integration/nucleus/CommandHome.java +++ b/src/main/java/net/mohron/skyclaims/integration/nucleus/CommandHome.java @@ -52,8 +52,7 @@ public static void register() { PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); PLUGIN.getLogger().debug("Registered command: CommandHome"); } catch (UnsupportedOperationException e) { - e.printStackTrace(); - PLUGIN.getLogger().error("Failed to register command: CommandHome"); + PLUGIN.getLogger().error("Failed to register command: CommandHome:", e); } } @@ -65,8 +64,7 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm Player player = (Player) src; Transform transform = getHome(player) - .orElseThrow(() -> new CommandException( - Text.of(TextColors.RED, "You must set a home before using this command!"))); + .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "You must set a home before using this command!"))); player.setTransformSafely(transform); diff --git a/src/main/java/net/mohron/skyclaims/integration/nucleus/CommandSetHome.java b/src/main/java/net/mohron/skyclaims/integration/nucleus/CommandSetHome.java index 53c9acb7..71af9b77 100644 --- a/src/main/java/net/mohron/skyclaims/integration/nucleus/CommandSetHome.java +++ b/src/main/java/net/mohron/skyclaims/integration/nucleus/CommandSetHome.java @@ -23,6 +23,7 @@ import net.mohron.skyclaims.command.CommandIsland; import net.mohron.skyclaims.permissions.Permissions; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; @@ -49,8 +50,7 @@ public static void register() { PLUGIN.getGame().getCommandManager().register(PLUGIN, commandSpec); PLUGIN.getLogger().debug("Registered command: CommandSetHome"); } catch (UnsupportedOperationException e) { - e.printStackTrace(); - PLUGIN.getLogger().error("Failed to register command: CommandSetHome"); + PLUGIN.getLogger().error("Failed to register command: CommandSetHome:", e); } } @@ -60,19 +60,18 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm } Player player = (Player) src; - Island island = Island.get(player.getLocation()) - .orElseThrow(() -> new CommandException( - Text.of(TextColors.RED, "You must be on an island to set a home!"))); + Island island = IslandManager.get(player.getLocation()) + .orElseThrow(() -> new CommandException(Text.of(TextColors.RED, "You must be on an island to set a home!"))); if (!island.isMember(player)) { - throw new CommandException( - Text.of(TextColors.RED, "You must have permission to set home on this island!")); + throw new CommandException(Text.of(TextColors.RED, "You must have permission to set home on this island!")); } boolean success = modifyOrCreateHome(player); if (!success) { - throw new CommandException( - Text.of(TextColors.RED, "An error was encountered while attempting to set your home!")); + throw new CommandException(Text.of( + TextColors.RED, "An error was encountered while attempting to set your home!" + )); } return CommandResult.success(); @@ -81,14 +80,17 @@ public CommandResult execute(CommandSource src, CommandContext args) throws Comm private boolean modifyOrCreateHome(Player player) { try { - NucleusIntegration.getHomeService() - .modifyOrCreateHome(Sponge.getCauseStackManager().getCurrentCause(), player, "Island", - player.getLocation(), player.getRotation()); + NucleusIntegration.getHomeService().modifyOrCreateHome( + Sponge.getCauseStackManager().getCurrentCause(), + player, + "Island", + player.getLocation(), + player.getRotation() + ); player.sendMessage(Text.of(TextColors.GREEN, "Your home has been set!")); return true; } catch (NucleusException e) { - player.sendMessage( - Text.of(TextColors.RED, "An error was encountered while attempting to set your home!")); + player.sendMessage(Text.of(TextColors.RED, "An error was encountered while attempting to set your home!")); PLUGIN.getGame().getServer().getConsole().sendMessage(e.getText()); return false; } diff --git a/src/main/java/net/mohron/skyclaims/listener/ClaimEventHandler.java b/src/main/java/net/mohron/skyclaims/listener/ClaimEventHandler.java index 23f91f54..4d8774b6 100644 --- a/src/main/java/net/mohron/skyclaims/listener/ClaimEventHandler.java +++ b/src/main/java/net/mohron/skyclaims/listener/ClaimEventHandler.java @@ -27,14 +27,21 @@ import me.ryanhamshire.griefprevention.api.event.UserTrustClaimEvent; import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.SkyClaimsTimings; +import net.mohron.skyclaims.config.type.MiscConfig.ClearItemsType; import net.mohron.skyclaims.permissions.Permissions; import net.mohron.skyclaims.team.Invite; import net.mohron.skyclaims.team.PrivilegeType; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.event.Event; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.filter.Getter; -import org.spongepowered.api.event.filter.cause.Root; +import org.spongepowered.api.event.filter.cause.First; +import org.spongepowered.api.item.ItemType; +import org.spongepowered.api.item.inventory.Inventory; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.query.QueryOperationTypes; import org.spongepowered.api.service.user.UserStorageService; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.action.TextActions; @@ -47,42 +54,42 @@ public class ClaimEventHandler { private static final SkyClaims PLUGIN = SkyClaims.getInstance(); @Listener - public void onClaimCreate(CreateClaimEvent event, @Root Player player, - @Getter(value = "getClaim") Claim claim) { + public void onClaimCreate(CreateClaimEvent event, @First Player player, @Getter(value = "getClaim") Claim claim) { SkyClaimsTimings.CLAIM_HANDLER.startTimingIfSync(); World world = PLUGIN.getConfig().getWorldConfig().getWorld(); - if (!claim.getWorld().equals(world) || claim.isAdminClaim() || claim.getParent().isPresent()) { + if (!claim.getWorld().equals(world) || isSkyClaims(event) || claim.isAdminClaim() || claim.getParent().isPresent()) { SkyClaimsTimings.CLAIM_HANDLER.abort(); return; } - event.setMessage(Text.of(TextColors.RED, "You cannot create a basic claim in this dimension!")); + event.setMessage(Text.of(TextColors.RED, "You cannot create a player claim in this dimension!")); event.setCancelled(true); SkyClaimsTimings.CLAIM_HANDLER.stopTimingIfSync(); } @Listener - public void onClaimDelete(DeleteClaimEvent event, @Root Player player) { + public void onClaimDelete(DeleteClaimEvent event, @First Player player) { SkyClaimsTimings.CLAIM_HANDLER.startTimingIfSync(); World world = PLUGIN.getConfig().getWorldConfig().getWorld(); + if (isSkyClaims(event)) { + SkyClaimsTimings.CLAIM_HANDLER.abort(); + return; + } + for (Claim claim : event.getClaims()) { - if (claim.getWorld().equals(world) && !claim.isAdminClaim() && !claim.getParent() - .isPresent()) { + if (claim.getWorld().equals(world) && IslandManager.get(claim).isPresent()) { if (event instanceof DeleteClaimEvent.Abandon) { event.setMessage(Text.of(TextColors.RED, "You cannot abandon an island claim!")); } else { - Island.get(claim).ifPresent((Island island) -> { - event.setMessage(Text.of(TextColors.RED, - "A claim you are attempting to delete belongs to an island.\n", Text - .of(TextColors.AQUA, "Do you want to delete ", island.getOwnerName(), - "'s island?").toBuilder() - .onHover(TextActions.showText(Text.of("Click here to delete."))) - .onClick(TextActions.executeCallback(src -> island.delete())) - )); - }); + IslandManager.get(claim).ifPresent((Island island) -> event.setMessage(Text.of( + TextColors.RED, "A claim you are attempting to delete belongs to an island.", Text.NEW_LINE, + Text.of(TextColors.AQUA, "Do you want to delete ", island.getOwnerName(), "'s island?").toBuilder() + .onHover(TextActions.showText(Text.of("Click here to delete."))) + .onClick(TextActions.executeCallback(src -> island.delete())) + ))); } event.setCancelled(true); } @@ -92,12 +99,11 @@ public void onClaimDelete(DeleteClaimEvent event, @Root Player player) { } @Listener - public void onClaimChanged(ChangeClaimEvent event, @Root Player player, - @Getter(value = "getClaim") Claim claim) { + public void onClaimChanged(ChangeClaimEvent event, @First Player player, @Getter(value = "getClaim") Claim claim) { SkyClaimsTimings.CLAIM_HANDLER.startTimingIfSync(); World world = PLUGIN.getConfig().getWorldConfig().getWorld(); - if (!claim.getWorld().equals(world) || claim.isAdminClaim() || claim.getParent().isPresent()) { + if (!claim.getWorld().equals(world) || isSkyClaims(event) || !IslandManager.get(claim).isPresent()) { SkyClaimsTimings.CLAIM_HANDLER.abort(); return; } @@ -113,23 +119,55 @@ public void onClaimChanged(ChangeClaimEvent event, @Root Player player, } @Listener - public void onClaimBorder(BorderClaimEvent event, @Root Player player, - @Getter(value = "getClaim") Claim claim) { + public void onClaimResized(ChangeClaimEvent.Resize event, @Getter(value = "getClaim") Claim claim) { + SkyClaimsTimings.CLAIM_HANDLER.startTimingIfSync(); + World world = PLUGIN.getConfig().getWorldConfig().getWorld(); + + if (!claim.getWorld().equals(world) || !IslandManager.get(claim).isPresent()) { + SkyClaimsTimings.CLAIM_HANDLER.abort(); + return; + } + + if (event.getResizedClaim().getWidth() >= 512) { + event.setMessage(Text.of( + TextColors.RED, "An island claim can not be expanded beyond ", + TextColors.LIGHT_PURPLE, 512, TextColors.RED, " x ", TextColors.LIGHT_PURPLE, 512, TextColors.RED, "!" + )); + event.setCancelled(true); + } + + SkyClaimsTimings.CLAIM_HANDLER.stopTimingIfSync(); + } + + @Listener + public void onClaimBorder(BorderClaimEvent event, @First Player player, @Getter(value = "getClaim") Claim claim) { SkyClaimsTimings.CLAIM_HANDLER.startTimingIfSync(); World world = PLUGIN.getConfig().getWorldConfig().getWorld(); - if (claim.getWorld().equals(world) && !claim.isAdminClaim() && !claim.getParent().isPresent()) { - if (!Island.get(claim).isPresent()) { - SkyClaimsTimings.CLAIM_HANDLER.abort(); - return; + if (!claim.getWorld().equals(world) || !IslandManager.get(claim).isPresent()) { + SkyClaimsTimings.CLAIM_HANDLER.abort(); + return; + } + + Island island = IslandManager.get(claim).get(); + if (island.isLocked() && !island.isMember(player) && !player.hasPermission(Permissions.BYPASS_LOCK)) { + event.setCancelled(true); + event.setMessage(Text.of(TextColors.RED, "You do not have permission to enter ", island.getName(), TextColors.RED, "!")); + } + + // Clears configured items when entering/leaving an island + if (PLUGIN.getConfig().getMiscConfig().getClearItemsType() == ClearItemsType.BLACKLIST) { + // If set to blacklist, remove all matching items + for (ItemType item : PLUGIN.getConfig().getMiscConfig().getClearItems()) { + ItemStack stack = ItemStack.builder().itemType(item).build(); + player.getInventory().query(QueryOperationTypes.ITEM_STACK_IGNORE_QUANTITY.of(stack)).poll(); } - Island island = Island.get(claim).get(); - if (island.isLocked() && !island.isMember(player) && !player - .hasPermission(Permissions.BYPASS_LOCK)) { - event.setCancelled(true); - event.setMessage( - Text.of(TextColors.RED, "You do not have permission to enter ", island.getName(), - TextColors.RED, "!")); + } else { + // If set to whitelist, remove all non-matching items + for (Inventory slot : player.getInventory().slots()) { + if (slot.peek().isPresent() && !PLUGIN.getConfig().getMiscConfig().getClearItems().contains(slot.peek().get().getType())) { + slot.poll(); + } } } @@ -137,73 +175,74 @@ public void onClaimBorder(BorderClaimEvent event, @Root Player player, } @Listener - public void onClaimTrust(UserTrustClaimEvent event, @Root Player player, - @Getter(value = "getClaim") Claim claim) { + public void onClaimTrust(UserTrustClaimEvent event, @First Player player, @Getter(value = "getClaim") Claim claim) { SkyClaimsTimings.CLAIM_HANDLER.startTimingIfSync(); - if (PLUGIN.getConfig().getIntegrationConfig().getGriefPrevention().getDisabledTrustTypes() - .contains(event.getTrustType())) { - event.setCancelled(true); - event.setMessage(Text.of(TextColors.RED, "The use of ", TextColors.GOLD, event.getTrustType(), - TextColors.RED, " has been disabled!")); + if (isSkyClaims(event) || player.hasPermission(Permissions.BYPASS_TRUST)) { SkyClaimsTimings.CLAIM_HANDLER.abort(); return; } - if (player.hasPermission(Permissions.BYPASS_TRUST)) { + if (PLUGIN.getConfig().getIntegrationConfig().getGriefPrevention().getDisabledTrustTypes().contains(event.getTrustType())) { + event.setCancelled(true); + event.setMessage(Text.of( + TextColors.RED, "The use of ", TextColors.GOLD, event.getTrustType(), TextColors.RED, " has been disabled!" + )); SkyClaimsTimings.CLAIM_HANDLER.abort(); return; } World world = PLUGIN.getConfig().getWorldConfig().getWorld(); - if (claim.getWorld().equals(world)) { - // Get The top level claim - if (claim.isSubdivision()) { - Claim parent = claim; - while (parent.getParent().isPresent()) { - parent = parent.getParent().get(); - } - claim = parent; - } - // Ignore non-basic claims or claims without an island. - if (!claim.isBasicClaim() && !Island.get(claim).isPresent()) { - SkyClaimsTimings.CLAIM_HANDLER.abort(); - return; + if (!claim.getWorld().equals(world)) { + SkyClaimsTimings.CLAIM_HANDLER.abort(); + return; + } + + // Get The top level claim + if (claim.isSubdivision()) { + Claim parent = claim; + while (parent.getParent().isPresent()) { + parent = parent.getParent().get(); } - // Send out invites - Island island = Island.get(claim).get(); - for (PrivilegeType type : PrivilegeType.values()) { - if (type.getTrustType() == event.getTrustType()) { - event.setCancelled(true); - event.getUsers().forEach(uuid -> - PLUGIN.getGame().getServiceManager().provideUnchecked(UserStorageService.class) - .get(uuid).ifPresent(user -> { - if (event instanceof TrustClaimEvent.Add && island.getPrivilegeType(user) != type) { - Invite.builder() - .island(island) - .sender(player) - .receiver(user) - .privilegeType(type) - .build() - .send(); - event.setMessage(Text.of( - TextColors.GREEN, "Island invite sent to ", type.format(user.getName()), - TextColors.GREEN, "." - )); - } - if (event instanceof TrustClaimEvent.Remove) { - event.setMessage(Text.of( - TextColors.RED, "Use ", - Text.builder("/is kick").color(TextColors.AQUA).style(TextStyles.ITALIC) - .onClick(TextActions.suggestCommand("/is kick ")), - " to remove a player from this island.") - ); - } - })); - } + claim = parent; + } + // Ignore claims without an island. + if (!IslandManager.get(claim).isPresent()) { + SkyClaimsTimings.CLAIM_HANDLER.abort(); + return; + } + // Send out invites + Island island = IslandManager.get(claim).get(); + for (PrivilegeType type : PrivilegeType.values()) { + if (type.getTrustType() == event.getTrustType()) { + event.setCancelled(true); + event.getUsers().forEach(uuid -> + PLUGIN.getGame().getServiceManager().provideUnchecked(UserStorageService.class).get(uuid).ifPresent(user -> { + if (event instanceof TrustClaimEvent.Add && island.getPrivilegeType(user) != type) { + Invite.builder() + .island(island) + .sender(player) + .receiver(user) + .privilegeType(type) + .build() + .send(); + event.setMessage(Text.of(TextColors.GREEN, "Island invite sent to ", type.format(user.getName()), TextColors.GREEN, ".")); + } + if (event instanceof TrustClaimEvent.Remove) { + event.setMessage(Text.of( + TextColors.RED, "Use ", + Text.builder("/is kick").color(TextColors.AQUA).style(TextStyles.ITALIC).onClick(TextActions.suggestCommand("/is kick ")), + " to remove a player from this island.") + ); + } + })); } } SkyClaimsTimings.CLAIM_HANDLER.stopTimingIfSync(); } + + private boolean isSkyClaims(Event event) { + return event.getCause().contains(PLUGIN.getPluginContainer()); + } } diff --git a/src/main/java/net/mohron/skyclaims/listener/ClientJoinHandler.java b/src/main/java/net/mohron/skyclaims/listener/ClientJoinHandler.java index d8c49fe0..33730f44 100644 --- a/src/main/java/net/mohron/skyclaims/listener/ClientJoinHandler.java +++ b/src/main/java/net/mohron/skyclaims/listener/ClientJoinHandler.java @@ -23,6 +23,7 @@ import net.mohron.skyclaims.exception.CreateIslandException; import net.mohron.skyclaims.permissions.Options; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.Sponge; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.Listener; @@ -38,11 +39,11 @@ public class ClientJoinHandler { @Listener public void onClientJoin(ClientConnectionEvent.Join event, @Root Player player) { - if (PLUGIN.getConfig().getMiscConfig().createIslandOnJoin() && !Island - .hasIsland(player.getUniqueId())) { + if (PLUGIN.getConfig().getMiscConfig().isCreateIslandOnJoin() && !IslandManager.hasIsland(player.getUniqueId())) { createIslandOnJoin(player); } deliverInvites(player); + checkIslandSize(player); } private void createIslandOnJoin(Player player) { @@ -51,13 +52,15 @@ private void createIslandOnJoin(Player player) { Sponge.getScheduler().createTaskBuilder() .execute(src -> { try { - new Island(player, Options.getDefaultSchematic(player.getUniqueId())); + new Island( + player, + Options.getDefaultSchematic(player.getUniqueId()) + .orElseThrow(() -> new CreateIslandException(Text.of(TextColors.RED, "Unable to load default schematic!"))) + ); PLUGIN.getLogger().info("Automatically created an island for {}.", player.getName()); } catch (CreateIslandException e) { // Oh well, we tried! - PLUGIN.getLogger() - .warn(String.format("Failed to create an island on join for %s.", player.getName()), - e); + PLUGIN.getLogger().warn(String.format("Failed to create an island on join for %s.", player.getName()), e); } }) .delayTicks(40) @@ -78,12 +81,23 @@ private void deliverInvites(Player player) { TextColors.WHITE, "[", Text.builder("OPEN") .color(TextColors.GREEN) - .onClick( - TextActions.executeCallback(PLUGIN.getInviteService().listIncomingInvites())), + .onClick(TextActions.executeCallback(PLUGIN.getInviteService().listIncomingInvites())), TextColors.WHITE, "]" )); } SkyClaimsTimings.DELIVER_INVITES.stopTimingIfSync(); } + + private void checkIslandSize(Player player) { + IslandManager.getByOwner(player.getUniqueId()).ifPresent(island -> { + final int width = island.getWidth(); + int minWidth = Options.getMinSize(player.getUniqueId()) * 2; + + if (width < minWidth) { + PLUGIN.getLogger().info("{} will be expanded from {} to {}.", island.getName().toPlain(), width, minWidth); + island.setWidth(minWidth); + } + }); + } } diff --git a/src/main/java/net/mohron/skyclaims/listener/EntitySpawnHandler.java b/src/main/java/net/mohron/skyclaims/listener/EntitySpawnHandler.java index 97283094..18e78b55 100644 --- a/src/main/java/net/mohron/skyclaims/listener/EntitySpawnHandler.java +++ b/src/main/java/net/mohron/skyclaims/listener/EntitySpawnHandler.java @@ -22,6 +22,7 @@ import net.mohron.skyclaims.SkyClaimsTimings; import net.mohron.skyclaims.permissions.Options; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.entity.living.Ambient; import org.spongepowered.api.entity.living.Aquatic; import org.spongepowered.api.entity.living.animal.Animal; @@ -48,7 +49,7 @@ public void onEntitySpawn(SpawnEntityEvent event) { } event.filterEntities(entity -> { - Island island = SkyClaims.islands.values().stream() + Island island = IslandManager.ISLANDS.values().stream() .filter(i -> i.contains(entity.getLocation())).findAny().orElse(null); if (island == null) { return true; @@ -61,8 +62,7 @@ public void onEntitySpawn(SpawnEntityEvent event) { if (limit > 0 && hostile >= limit) { return false; } - } else if (entity instanceof Animal || entity instanceof Aquatic - || entity instanceof Ambient) { + } else if (entity instanceof Animal || entity instanceof Aquatic || entity instanceof Ambient) { limit = Options.getMaxPassiveSpawns(island.getOwnerUniqueId()); if (limit > 0 && passive >= limit) { return false; diff --git a/src/main/java/net/mohron/skyclaims/listener/RespawnHandler.java b/src/main/java/net/mohron/skyclaims/listener/RespawnHandler.java index 81dda529..53c28886 100644 --- a/src/main/java/net/mohron/skyclaims/listener/RespawnHandler.java +++ b/src/main/java/net/mohron/skyclaims/listener/RespawnHandler.java @@ -17,29 +17,40 @@ */ package net.mohron.skyclaims.listener; +import java.util.Optional; +import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.SkyClaimsTimings; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; +import net.mohron.skyclaims.world.region.Region; import org.spongepowered.api.Sponge; -import org.spongepowered.api.entity.Transform; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.entity.living.humanoid.player.RespawnPlayerEvent; import org.spongepowered.api.event.filter.cause.Root; +import org.spongepowered.api.world.World; public class RespawnHandler { + private static final SkyClaims PLUGIN = SkyClaims.getInstance(); + @Listener public void onPlayerRespawn(RespawnPlayerEvent event, @Root Player player) { SkyClaimsTimings.PLAYER_RESPAWN.startTimingIfSync(); - if (event.isBedSpawn() || !Island.hasIsland(player.getUniqueId())) { + World world = PLUGIN.getConfig().getWorldConfig().getWorld(); + + if (!event.isDeath() || !world.equals(event.getFromTransform().getExtent())) { SkyClaimsTimings.PLAYER_RESPAWN.abort(); return; } - Island.getByOwner(player.getUniqueId()) - .ifPresent(island -> Sponge.getGame().getTeleportHelper() - .getSafeLocation(island.getSpawn().getLocation()) - .ifPresent(spawn -> event.setToTransform(new Transform<>(spawn)))); + final Optional island = IslandManager.get(event.getFromTransform()); + if (island.isPresent() && island.get().isMember(player)) { + Sponge.getTeleportHelper() + .getSafeLocation(island.get().getSpawn().getLocation()) + .ifPresent(spawn -> event.setToTransform(island.get().getSpawn().setLocation(spawn))); + } + SkyClaimsTimings.PLAYER_RESPAWN.stopTimingIfSync(); } } diff --git a/src/main/java/net/mohron/skyclaims/listener/SchematicHandler.java b/src/main/java/net/mohron/skyclaims/listener/SchematicHandler.java index 19374d1f..c50fde30 100644 --- a/src/main/java/net/mohron/skyclaims/listener/SchematicHandler.java +++ b/src/main/java/net/mohron/skyclaims/listener/SchematicHandler.java @@ -44,7 +44,7 @@ public class SchematicHandler { public void onInteract(InteractBlockEvent.Secondary.MainHand event, @Root Player player) { SkyClaimsTimings.SCHEMATIC_HANDLER.startTimingIfSync(); - if (!player.hasPermission(Permissions.COMMAND_CREATE_SCHEMATIC)) { + if (!player.hasPermission(Permissions.COMMAND_SCHEMATIC_CREATE)) { SkyClaimsTimings.SCHEMATIC_HANDLER.abort(); return; } @@ -65,7 +65,7 @@ public void onInteract(InteractBlockEvent.Secondary.MainHand event, @Root Player public void onInteract(InteractBlockEvent.Primary.MainHand event, @Root Player player) { SkyClaimsTimings.SCHEMATIC_HANDLER.startTimingIfSync(); - if (!player.hasPermission(Permissions.COMMAND_CREATE_SCHEMATIC)) { + if (!player.hasPermission(Permissions.COMMAND_SCHEMATIC_CREATE)) { SkyClaimsTimings.SCHEMATIC_HANDLER.abort(); return; } diff --git a/src/main/java/net/mohron/skyclaims/metrics/Metrics.java b/src/main/java/net/mohron/skyclaims/metrics/Metrics.java deleted file mode 100644 index ec9013dd..00000000 --- a/src/main/java/net/mohron/skyclaims/metrics/Metrics.java +++ /dev/null @@ -1,802 +0,0 @@ -/* - * SkyClaims - A Skyblock plugin made for Sponge - * Copyright (C) 2017 Mohron - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * SkyClaims is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with SkyClaims. If not, see . - */ - -package net.mohron.skyclaims.metrics; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import com.google.inject.Inject; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.net.URL; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.zip.GZIPOutputStream; -import javax.net.ssl.HttpsURLConnection; -import ninja.leaping.configurate.commented.CommentedConfigurationNode; -import ninja.leaping.configurate.hocon.HoconConfigurationLoader; -import org.apache.commons.lang3.Validate; -import org.slf4j.Logger; -import org.spongepowered.api.Platform; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.config.ConfigDir; -import org.spongepowered.api.plugin.PluginContainer; -import org.spongepowered.api.scheduler.Scheduler; -import org.spongepowered.api.scheduler.Task; - -/** - * bStats collects some data for plugin authors. - * - * Check out https://bStats.org/ to learn more about bStats! - */ -public class Metrics { - - static { - // You can use the property to disable the check in your test environment - if (System.getProperty("bstats.relocatecheck") == null || !System - .getProperty("bstats.relocatecheck").equals("false")) { - // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D - final String defaultPackage = new String( - new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 's', 'p', 'o', 'n', 'g', - 'e'}); - final String examplePackage = new String( - new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); - // We want to make sure nobody just copy & pastes the example and use the wrong package names - if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage() - .getName().equals(examplePackage)) { - throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); - } - } - } - - // The version of this bStats class - public static final int B_STATS_VERSION = 1; - - // The url to which the data is sent - private static final String URL = "https://bStats.org/submitData/sponge"; - - // We use this flag to ensure only one instance of this class exist - private static boolean created = false; - - // The logger - private Logger logger; - - // The plugin - private final PluginContainer plugin; - - // Is bStats enabled on this server? - private boolean enabled; - - // The uuid of the server - private String serverUUID; - - // Should failed requests be logged? - private boolean logFailedRequests = false; - - // A list with all known metrics class objects including this one - private static final List knownMetricsInstances = new ArrayList<>(); - - // A list with all custom charts - private final List charts = new ArrayList<>(); - - // The config path - private Path configDir; - - // The constructor is not meant to be called by the user himself. - // The instance is created using Dependency Injection (https://docs.spongepowered.org/master/en/plugin/injection.html) - @Inject - private Metrics(PluginContainer plugin, Logger logger, - @ConfigDir(sharedRoot = true) Path configDir) { - if (created) { - // We don't want more than one instance of this class - throw new IllegalStateException("There's already an instance of this Metrics class!"); - } else { - created = true; - } - - this.plugin = plugin; - this.logger = logger; - this.configDir = configDir; - - try { - loadConfig(); - } catch (IOException e) { - // Failed to load configuration - logger.warn("Failed to load bStats config!", e); - return; - } - - // We are not allowed to send data about this server :( - if (!enabled) { - return; - } - - Class usedMetricsClass = getFirstBStatsClass(); - if (usedMetricsClass == null) { - // Failed to get first metrics class - return; - } - if (usedMetricsClass == getClass()) { - // We are the first! :) - linkMetrics(this); - startSubmitting(); - } else { - // We aren't the first so we link to the first metrics class - try { - usedMetricsClass.getMethod("linkMetrics", Object.class).invoke(null, this); - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { - if (logFailedRequests) { - logger.warn("Failed to link to first metrics class {}!", usedMetricsClass.getName(), e); - } - } - } - } - - /** - * Adds a custom chart. - * - * @param chart The chart to add. - */ - public void addCustomChart(CustomChart chart) { - Validate.notNull(chart, "Chart cannot be null"); - charts.add(chart); - } - - /** - * Links an other metrics class with this class. This method is called using Reflection. - * - * @param metrics An object of the metrics class to link. - */ - public static void linkMetrics(Object metrics) { - knownMetricsInstances.add(metrics); - } - - /** - * Gets the plugin specific data. This method is called using Reflection. - * - * @return The plugin specific data. - */ - public JsonObject getPluginData() { - JsonObject data = new JsonObject(); - - String pluginName = plugin.getName(); - String pluginVersion = plugin.getVersion().orElse("unknown"); - - data.addProperty("pluginName", pluginName); - data.addProperty("pluginVersion", pluginVersion); - - JsonArray customCharts = new JsonArray(); - for (CustomChart customChart : charts) { - // Add the data of the custom charts - JsonObject chart = customChart.getRequestJsonObject(logger, logFailedRequests); - if (chart == null) { // If the chart is null, we skip it - continue; - } - customCharts.add(chart); - } - data.add("customCharts", customCharts); - - return data; - } - - private void startSubmitting() { - // We use a timer cause want to be independent from the server tps - final Timer timer = new Timer(true); - timer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - // Plugin was disabled, e.g. because of a reload (is this even possible in Sponge?) - if (!Sponge.getPluginManager().isLoaded(plugin.getId())) { - timer.cancel(); - return; - } - // The data collection (e.g. for custom graphs) is done sync - // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) - Scheduler scheduler = Sponge.getScheduler(); - Task.Builder taskBuilder = scheduler.createTaskBuilder(); - taskBuilder.execute(() -> submitData()).submit(plugin); - } - }, 1000 * 60 * 5, 1000 * 60 * 30); - // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start - // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! - // WARNING: Just don't do it! - } - - /** - * Gets the server specific data. - * - * @return The server specific data. - */ - private JsonObject getServerData() { - // Minecraft specific data - int playerAmount = Sponge.getServer().getOnlinePlayers().size(); - playerAmount = playerAmount > 200 ? 200 : playerAmount; - int onlineMode = Sponge.getServer().getOnlineMode() ? 1 : 0; - String minecraftVersion = Sponge.getGame().getPlatform().getMinecraftVersion().getName(); - String spongeImplementation = Sponge.getPlatform() - .getContainer(Platform.Component.IMPLEMENTATION).getName(); - - // OS/Java specific data - String javaVersion = System.getProperty("java.version"); - String osName = System.getProperty("os.name"); - String osArch = System.getProperty("os.arch"); - String osVersion = System.getProperty("os.version"); - int coreCount = Runtime.getRuntime().availableProcessors(); - - JsonObject data = new JsonObject(); - - data.addProperty("serverUUID", serverUUID); - - data.addProperty("playerAmount", playerAmount); - data.addProperty("onlineMode", onlineMode); - data.addProperty("minecraftVersion", minecraftVersion); - data.addProperty("spongeImplementation", spongeImplementation); - - data.addProperty("javaVersion", javaVersion); - data.addProperty("osName", osName); - data.addProperty("osArch", osArch); - data.addProperty("osVersion", osVersion); - data.addProperty("coreCount", coreCount); - - return data; - } - - /** - * Collects the data and sends it afterwards. - */ - private void submitData() { - final JsonObject data = getServerData(); - - JsonArray pluginData = new JsonArray(); - // Search for all other bStats Metrics classes to get their plugin data - for (Object metrics : knownMetricsInstances) { - try { - Object plugin = metrics.getClass().getMethod("getPluginData").invoke(metrics); - if (plugin instanceof JsonObject) { - pluginData.add((JsonObject) plugin); - } - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { - } - } - - data.add("plugins", pluginData); - - // Create a new thread for the connection to the bStats server - new Thread(() -> { - try { - // Send the data - sendData(data); - } catch (Exception e) { - // Something went wrong! :( - if (logFailedRequests) { - logger.warn("Could not submit plugin stats!", e); - } - } - }).start(); - } - - /** - * Loads the bStats configuration. - * - * @throws IOException If something did not work :( - */ - private void loadConfig() throws IOException { - Path configPath = configDir.resolve("bStats"); - configPath.toFile().mkdirs(); - File configFile = new File(configPath.toFile(), "config.conf"); - HoconConfigurationLoader configurationLoader = HoconConfigurationLoader.builder() - .setFile(configFile).build(); - CommentedConfigurationNode node; - if (!configFile.exists()) { - configFile.createNewFile(); - node = configurationLoader.load(); - - // Add default values - node.getNode("enabled").setValue(true); - // Every server gets it's unique random id. - node.getNode("serverUuid").setValue(UUID.randomUUID().toString()); - // Should failed request be logged? - node.getNode("logFailedRequests").setValue(false); - - // Add information about bStats - node.getNode("enabled").setComment( - "bStats collects some data for plugin authors like how many servers are using their plugins.\n" - + - "To honor their work, you should not disable it.\n" + - "This has nearly no effect on the server performance!\n" + - "Check out https://bStats.org/ to learn more :)" - ); - - configurationLoader.save(node); - } else { - node = configurationLoader.load(); - } - - // Load configuration - enabled = node.getNode("enabled").getBoolean(true); - serverUUID = node.getNode("serverUuid").getString(); - logFailedRequests = node.getNode("logFailedRequests").getBoolean(false); - } - - /** - * Gets the first bStat Metrics class. - * - * @return The first bStats metrics class. - */ - private Class getFirstBStatsClass() { - Path configPath = configDir.resolve("bStats"); - configPath.toFile().mkdirs(); - File tempFile = new File(configPath.toFile(), "temp.txt"); - - try { - String className = readFile(tempFile); - if (className != null) { - try { - // Let's check if a class with the given name exists. - return Class.forName(className); - } catch (ClassNotFoundException ignored) { - } - } - writeFile(tempFile, getClass().getName()); - return getClass(); - } catch (IOException e) { - if (logFailedRequests) { - logger.warn("Failed to get first bStats class!", e); - } - return null; - } - } - - /** - * Reads the first line of the file. - * - * @param file The file to read. Cannot be null. - * @return The first line of the file or null if the file does not exist or is empty. - * @throws IOException If something did not work :( - */ - private String readFile(File file) throws IOException { - if (!file.exists()) { - return null; - } - try ( - FileReader fileReader = new FileReader(file); - BufferedReader bufferedReader = new BufferedReader(fileReader); - ) { - return bufferedReader.readLine(); - } - } - - /** - * Writes a String to a file. It also adds a note for the user, - * - * @param file The file to write to. Cannot be null. - * @param text The text to write. - * @throws IOException If something did not work :( - */ - private void writeFile(File file, String text) throws IOException { - if (!file.exists()) { - file.createNewFile(); - } - try ( - FileWriter fileWriter = new FileWriter(file); - BufferedWriter bufferedWriter = new BufferedWriter(fileWriter) - ) { - bufferedWriter.write(text); - bufferedWriter.newLine(); - bufferedWriter - .write("Note: This class only exists for internal purpose. You can ignore it :)"); - } - } - - /** - * Sends the data to the bStats server. - * - * @param data The data to send. - * @throws Exception If the request failed. - */ - private static void sendData(JsonObject data) throws Exception { - Validate.notNull(data, "Data cannot be null"); - HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); - - // Compress the data to save bandwidth - byte[] compressedData = compress(data.toString()); - - // Add headers - connection.setRequestMethod("POST"); - connection.addRequestProperty("Accept", "application/json"); - connection.addRequestProperty("Connection", "close"); - connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request - connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); - connection - .setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format - connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); - - // Send data - connection.setDoOutput(true); - DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream()); - outputStream.write(compressedData); - outputStream.flush(); - outputStream.close(); - - connection.getInputStream().close(); // We don't care about the response - Just send our data :) - } - - /** - * Gzips the given String. - * - * @param str The string to gzip. - * @return The gzipped String. - * @throws IOException If the compression failed. - */ - private static byte[] compress(final String str) throws IOException { - if (str == null) { - return null; - } - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - GZIPOutputStream gzip = new GZIPOutputStream(outputStream); - gzip.write(str.getBytes("UTF-8")); - gzip.close(); - return outputStream.toByteArray(); - } - - /** - * Represents a custom chart. - */ - public static abstract class CustomChart { - - // The id of the chart - private final String chartId; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - */ - CustomChart(String chartId) { - if (chartId == null || chartId.isEmpty()) { - throw new IllegalArgumentException("ChartId cannot be null or empty!"); - } - this.chartId = chartId; - } - - private JsonObject getRequestJsonObject(Logger logger, boolean logFailedRequests) { - JsonObject chart = new JsonObject(); - chart.addProperty("chartId", chartId); - try { - JsonObject data = getChartData(); - if (data == null) { - // If the data is null we don't send the chart. - return null; - } - chart.add("data", data); - } catch (Throwable t) { - if (logFailedRequests) { - logger.warn("Failed to get data for custom chart with id {}", chartId, t); - } - return null; - } - return chart; - } - - protected abstract JsonObject getChartData() throws Exception; - - } - - /** - * Represents a custom simple pie. - */ - public static class SimplePie extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimplePie(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - String value = callable.call(); - if (value == null || value.isEmpty()) { - // Null = skip the chart - return null; - } - data.addProperty("value", value); - return data; - } - } - - /** - * Represents a custom advanced pie. - */ - public static class AdvancedPie extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedPie(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - JsonObject values = new JsonObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - continue; // Skip this invalid - } - allSkipped = false; - values.addProperty(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.add("values", values); - return data; - } - } - - /** - * Represents a custom drilldown pie. - */ - public static class DrilldownPie extends CustomChart { - - private final Callable>> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public DrilldownPie(String chartId, Callable>> callable) { - super(chartId); - this.callable = callable; - } - - @Override - public JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - JsonObject values = new JsonObject(); - Map> map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean reallyAllSkipped = true; - for (Map.Entry> entryValues : map.entrySet()) { - JsonObject value = new JsonObject(); - boolean allSkipped = true; - for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { - value.addProperty(valueEntry.getKey(), valueEntry.getValue()); - allSkipped = false; - } - if (!allSkipped) { - reallyAllSkipped = false; - values.add(entryValues.getKey(), value); - } - } - if (reallyAllSkipped) { - // Null = skip the chart - return null; - } - data.add("values", values); - return data; - } - } - - /** - * Represents a custom single line chart. - */ - public static class SingleLineChart extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SingleLineChart(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - int value = callable.call(); - if (value == 0) { - // Null = skip the chart - return null; - } - data.addProperty("value", value); - return data; - } - - } - - /** - * Represents a custom multi line chart. - */ - public static class MultiLineChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public MultiLineChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - JsonObject values = new JsonObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - continue; // Skip this invalid - } - allSkipped = false; - values.addProperty(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.add("values", values); - return data; - } - - } - - /** - * Represents a custom simple bar chart. - */ - public static class SimpleBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimpleBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - JsonObject values = new JsonObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - for (Map.Entry entry : map.entrySet()) { - JsonArray categoryValues = new JsonArray(); - categoryValues.add(new JsonPrimitive(entry.getValue())); - values.add(entry.getKey(), categoryValues); - } - data.add("values", values); - return data; - } - - } - - /** - * Represents a custom advanced bar chart. - */ - public static class AdvancedBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - JsonObject values = new JsonObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue().length == 0) { - continue; // Skip this invalid - } - allSkipped = false; - JsonArray categoryValues = new JsonArray(); - for (int categoryValue : entry.getValue()) { - categoryValues.add(new JsonPrimitive(categoryValue)); - } - values.add(entry.getKey(), categoryValues); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.add("values", values); - return data; - } - - } - -} \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/permissions/Options.java b/src/main/java/net/mohron/skyclaims/permissions/Options.java index 61bc2a4a..79dfaad1 100644 --- a/src/main/java/net/mohron/skyclaims/permissions/Options.java +++ b/src/main/java/net/mohron/skyclaims/permissions/Options.java @@ -22,28 +22,44 @@ import java.util.UUID; import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.command.argument.BiomeArgument; +import net.mohron.skyclaims.schematic.IslandSchematic; import org.apache.commons.lang3.StringUtils; import org.spongepowered.api.service.permission.PermissionService; +import org.spongepowered.api.service.permission.Subject; import org.spongepowered.api.world.biome.BiomeType; -public class Options { +public final class Options { private static final SkyClaims PLUGIN = SkyClaims.getInstance(); private static final PermissionService PERMISSION_SERVICE = SkyClaims.getInstance().getPermissionService(); // SkyClaims Options - private static final String DEFAULT_SCHEMATIC = "skyclaims.default-schematic"; - private static final String DEFAULT_BIOME = "skyclaims.default-biome"; - private static final String MIN_SIZE = "skyclaims.min-size"; - private static final String MAX_SIZE = "skyclaims.max-size"; - private static final String MAX_SPAWNS = "skyclaims.max-spawns"; - private static final String MAX_HOSTILE = "skyclaims.max-spawns.hostile"; - private static final String MAX_PASSIVE = "skyclaims.max-spawns.passive"; - private static final String EXPIRATION = "skyclaims.expiration"; - private static final String MAX_ISLANDS = "skyclaims.max-islands"; - - public static String getDefaultSchematic(UUID playerUniqueId) { - return getStringOption(playerUniqueId, DEFAULT_SCHEMATIC, "skyfactory"); + public static final String DEFAULT_SCHEMATIC = "skyclaims.default-schematic"; + public static final String DEFAULT_BIOME = "skyclaims.default-biome"; + public static final String MIN_SIZE = "skyclaims.min-size"; + public static final String MAX_SIZE = "skyclaims.max-size"; + public static final String MAX_SPAWNS = "skyclaims.max-spawns"; + public static final String MAX_HOSTILE = "skyclaims.max-spawns.hostile"; + public static final String MAX_PASSIVE = "skyclaims.max-spawns.passive"; + public static final String EXPIRATION = "skyclaims.expiration"; + public static final String MAX_ISLANDS = "skyclaims.max-islands"; + public static final String MAX_TEAMMATES = "skyclaims.max-teammates"; + + private Options() { + } + + public static Optional getDefaultSchematic(UUID playerUniqueId) { + String name = getStringOption(playerUniqueId, DEFAULT_SCHEMATIC, ""); + + if(PLUGIN.getSchematicManager().getSchematics().size() == 1) { + return Optional.of(PLUGIN.getSchematicManager().getSchematics().get(0)); + } else if (name.equalsIgnoreCase("random")) { + return Optional.of(PLUGIN.getSchematicManager().getRandomSchematic()); + } else { + return PLUGIN.getSchematicManager().getSchematics().stream() + .filter(s -> s.getName().equalsIgnoreCase(name)) + .findAny(); + } } public static Optional getDefaultBiome(UUID playerUniqueId) { @@ -87,10 +103,15 @@ public static int getMaxIslands(UUID playerUniqueId) { return getIntOption(playerUniqueId, MAX_ISLANDS, 0); } + public static int getMaxTeammates(UUID playerUniqueId) { + return getIntOption(playerUniqueId, MAX_TEAMMATES, 0); + } + private static String getStringOption(UUID uuid, String option, String defaultValue) { - return !PERMISSION_SERVICE.getUserSubjects().getSubject(uuid.toString()).isPresent() + Optional subject = PERMISSION_SERVICE.getUserSubjects().getSubject(uuid.toString()); + return !subject.isPresent() ? defaultValue - : PERMISSION_SERVICE.getUserSubjects().getSubject(uuid.toString()).get().getOption(option).orElse(defaultValue); + : subject.get().getOption(option).orElse(defaultValue); } private static int getIntOption(UUID uuid, String option, int defaultValue, int min, int max) { @@ -99,10 +120,11 @@ private static int getIntOption(UUID uuid, String option, int defaultValue, int } private static int getIntOption(UUID uuid, String option, int defaultValue) { - if (!PERMISSION_SERVICE.getUserSubjects().getSubject(uuid.toString()).isPresent()) { + Optional subject = PERMISSION_SERVICE.getUserSubjects().getSubject(uuid.toString()); + if (!subject.isPresent()) { return defaultValue; } - String value = PERMISSION_SERVICE.getUserSubjects().getSubject(uuid.toString()).get().getOption(option).orElse(String.valueOf(defaultValue)); + String value = subject.get().getOption(option).orElse(String.valueOf(defaultValue)); try { return Integer.parseInt(value); } catch (NumberFormatException e) { diff --git a/src/main/java/net/mohron/skyclaims/permissions/Permissions.java b/src/main/java/net/mohron/skyclaims/permissions/Permissions.java index 01073f18..97dd322d 100644 --- a/src/main/java/net/mohron/skyclaims/permissions/Permissions.java +++ b/src/main/java/net/mohron/skyclaims/permissions/Permissions.java @@ -25,6 +25,7 @@ public class Permissions { public static final String COMMAND_DELETE = "skyclaims.command.delete"; public static final String COMMAND_DEMOTE = "skyclaims.command.demote"; public static final String COMMAND_EXPAND = "skyclaims.command.expand"; + public static final String COMMAND_ENTITY_INFO = "skyclaims.command.entity.info"; public static final String COMMAND_HOME = "skyclaims.command.home"; public static final String COMMAND_INFO = "skyclaims.command.info"; public static final String COMMAND_INVITE = "skyclaims.command.invite"; @@ -40,6 +41,19 @@ public class Permissions { public static final String COMMAND_SET_HOME = "skyclaims.command.sethome"; public static final String COMMAND_SET_SPAWN = "skyclaims.command.setspawn"; public static final String COMMAND_SET_BIOME = "skyclaims.command.setbiome"; + public static final String COMMAND_SET_NAME = "skyclaims.command.setname"; + + // Keep Inventory + public static final String KEEP_INV_PLAYER_CREATE = "skyclaims.keepinv.player.create"; + public static final String KEEP_INV_PLAYER_DELETE = "skyclaims.keepinv.player.delete"; + public static final String KEEP_INV_PLAYER_KICK = "skyclaims.keepinv.player.kick"; + public static final String KEEP_INV_PLAYER_LEAVE = "skyclaims.keepinv.player.leave"; + public static final String KEEP_INV_PLAYER_RESET = "skyclaims.keepinv.player.reset"; + public static final String KEEP_INV_ENDERCHEST_CREATE = "skyclaims.keepinv.enderchest.create"; + public static final String KEEP_INV_ENDERCHEST_DELETE = "skyclaims.keepinv.enderchest.delete"; + public static final String KEEP_INV_ENDERCHEST_KICK = "skyclaims.keepinv.enderchest.kick"; + public static final String KEEP_INV_ENDERCHEST_LEAVE = "skyclaims.keepinv.enderchest.leave"; + public static final String KEEP_INV_ENDERCHEST_RESET = "skyclaims.keepinv.enderchest.reset"; // Command Arguments public static final String COMMAND_ARGUMENTS_SCHEMATICS = "skyclaims.arguments.schematics"; @@ -49,24 +63,35 @@ public class Permissions { // Admin Permissions // Commands - public static final String COMMAND_ADMIN = "skyclaims.admin.base"; - public static final String COMMAND_CONFIG = "skyclaims.admin.config"; - public static final String COMMAND_CREATE_SCHEMATIC = "skyclaims.admin.schematic.create"; public static final String COMMAND_DELETE_OTHERS = "skyclaims.admin.delete"; public static final String COMMAND_EXPAND_OTHERS = "skyclaims.admin.expand"; + public static final String COMMAND_ENTITY_CLEAR = "skyclaims.admin.entity.clear"; public static final String COMMAND_LIST_ALL = "skyclaims.admin.list"; public static final String COMMAND_LOCK_OTHERS = "skyclaims.admin.lock.others"; public static final String COMMAND_RELOAD = "skyclaims.admin.reload"; public static final String COMMAND_RESET_KEEP_INV = "skyclaims.admin.reset.keepinv"; public static final String COMMAND_SET_BIOME_OTHERS = "skyclaims.admin.setbiome"; - public static final String COMMAND_SETUP = "skyclaims.admin.setup"; public static final String COMMAND_SPAWN_OTHERS = "skyclaims.admin.spawn"; public static final String COMMAND_SET_SPAWN_OTHERS = "skyclaims.admin.setspawn"; + public static final String COMMAND_SET_NAME_OTHERS = "skyclaims.admin.setname"; public static final String COMMAND_TRANSFER = "skyclaims.admin.transfer"; public static final String COMMAND_VERSION = "skyclaims.admin.version"; + public static final String COMMAND_PLAYER_INFO = "skyclaims.admin.playerinfo"; + // Schematics + public static final String COMMAND_SCHEMATIC = "skyclaims.admin.schematic.base"; + public static final String COMMAND_SCHEMATIC_COMMAND = "skyclaims.admin.schematic.command"; + public static final String COMMAND_SCHEMATIC_CREATE = "skyclaims.admin.schematic.create"; + public static final String COMMAND_SCHEMATIC_DELETE = "skyclaims.admin.schematic.delete"; + public static final String COMMAND_SCHEMATIC_INFO = "skyclaims.admin.schematic.info"; + public static final String COMMAND_SCHEMATIC_LIST = "skyclaims.admin.schematic.list.base"; + public static final String COMMAND_SCHEMATIC_LIST_ALL = "skyclaims.admin.schematic.list.all"; + public static final String COMMAND_SCHEMATIC_SET_BIOME = "skyclaims.admin.schematic.setbiome"; + public static final String COMMAND_SCHEMATIC_SET_HEIGHT = "skyclaims.admin.schematic.setheight"; + public static final String COMMAND_SCHEMATIC_SET_ICON = "skyclaims.admin.schematic.seticon"; + public static final String COMMAND_SCHEMATIC_SET_NAME = "skyclaims.admin.schematic.setname"; + public static final String COMMAND_SCHEMATIC_SET_PRESET = "skyclaims.admin.schematic.setpreset"; // Bypass/Exemptions public static final String EXEMPT_KICK = "skyclaims.admin.kick.exempt"; public static final String BYPASS_LOCK = "skyclaims.admin.lock.bypass"; public static final String BYPASS_TRUST = "skyclaims.admin.trust.bypass"; - } diff --git a/src/main/java/net/mohron/skyclaims/schematic/IslandSchematic.java b/src/main/java/net/mohron/skyclaims/schematic/IslandSchematic.java new file mode 100644 index 00000000..55a9f3ec --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/schematic/IslandSchematic.java @@ -0,0 +1,144 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.schematic; + +import com.google.common.collect.Lists; +import java.time.Instant; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import net.mohron.skyclaims.SkyClaims; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.data.DataQuery; +import org.spongepowered.api.item.ItemType; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.serializer.TextSerializers; +import org.spongepowered.api.world.biome.BiomeType; +import org.spongepowered.api.world.schematic.Schematic; + +public class IslandSchematic { + + private static final DataQuery BIOME_TYPE = DataQuery.of("SkyClaims", "BiomeType"); + private static final DataQuery COMMANDS = DataQuery.of("SkyClaims", "Command"); + private static final DataQuery HEIGHT = DataQuery.of("SkyClaims", "Height"); + private static final DataQuery ICON = DataQuery.of("SkyClaims", "Icon"); + private static final DataQuery TEXT = DataQuery.of("SkyClaims", "Text"); + private static final DataQuery PRESET = DataQuery.of("SkyClaims", "Preset"); + + private final Schematic schematic; + private final String name; + + public IslandSchematic(Schematic schematic, String name) { + this.schematic = schematic; + this.name = name; + } + + public Schematic getSchematic() { + return schematic; + } + + public String getName() { + return name; + } + + public String getFileName() { + return String.format("%s.schematic", name); + } + + public String getAuthor() { + return schematic.getMetadata().getString(DataQuery.of("Author")).orElse("Unknown"); + } + + public String getDate() { + String date = "Unknown"; + try { + Instant instant = Instant.parse(schematic.getMetadata().getString(DataQuery.of("Date")).orElse("Unknown")); + date = SkyClaims.getInstance().getConfig().getMiscConfig().getDateFormat().format(Date.from(instant)); + } catch (Exception ignored) { + } + return date; + } + + public Optional getBiomeType() { + String biomeId = schematic.getMetadata().getString(BIOME_TYPE).orElse(null); + return biomeId != null ? + Sponge.getRegistry().getAllOf(BiomeType.class).stream().filter(b -> b.getId().equalsIgnoreCase(biomeId)).findAny() : + Optional.empty(); + } + + public void setBiomeType(BiomeType type) { + setMetadata(BIOME_TYPE, type.getId()); + } + + public List getCommands() { + return schematic.getMetadata().getStringList(COMMANDS).orElse(Lists.newArrayList()); + } + + public void setCommands(List commands) { + setMetadata(COMMANDS, commands); + } + + public Optional getHeight(){ + Integer height; + if (schematic.getMetadata().getInt(HEIGHT).isPresent()) { + height = Math.max(0, Math.min(255, schematic.getMetadata().getInt(HEIGHT).get())); + } else { + height = null; + } + return Optional.ofNullable(height); + } + + public void setHeight(Integer height) { + setMetadata(HEIGHT, height); + } + + public Text getText() { + String rawText = schematic.getMetadata().getString(TEXT).orElse(getName()); + return TextSerializers.FORMATTING_CODE.deserialize(rawText); + } + + public void setText(Text text) { + setMetadata(TEXT, TextSerializers.FORMATTING_CODE.serialize(text)); + } + + public Optional getIcon() { + String type = schematic.getMetadata().getString(ICON).orElse(""); + return Sponge.getRegistry().getType(ItemType.class, type); + } + + public void setIcon(ItemType icon) { + setMetadata(ICON, icon); + } + + public void setPreset(String preset) { + setMetadata(PRESET, preset); + } + + public Optional getPreset() { + return schematic.getMetadata().getString(PRESET); + } + + private void setMetadata(DataQuery path, Object value) { + if (value != null) { + schematic.getMetadata().set(path, value); + } else { + schematic.getMetadata().remove(path); + } + } +} diff --git a/src/main/java/net/mohron/skyclaims/schematic/SchematicManager.java b/src/main/java/net/mohron/skyclaims/schematic/SchematicManager.java new file mode 100644 index 00000000..2cbe00d8 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/schematic/SchematicManager.java @@ -0,0 +1,159 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.schematic; + +import com.google.common.collect.Lists; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Random; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; +import net.mohron.skyclaims.SkyClaims; +import org.spongepowered.api.data.DataContainer; +import org.spongepowered.api.data.persistence.DataFormats; +import org.spongepowered.api.data.persistence.DataTranslators; +import org.spongepowered.api.world.schematic.Schematic; + +public class SchematicManager { + + private static final String SCHEMATIC_FILE_EXT = ".schematic"; + + private final SkyClaims plugin; + private final Random random; + private final List schematics; + private final File directory; + + public SchematicManager(SkyClaims plugin) { + this.plugin = plugin; + this.random = new Random(); + this.schematics = Lists.newArrayList(); + this.directory = new File(plugin.getConfigDir() + File.separator + "schematics"); + } + + public List getSchematics() { + return schematics; + } + + public IslandSchematic getRandomSchematic() { + int r = random.nextInt(schematics.size()); + return schematics.get(r); + } + + public boolean create(Schematic schematic, String name) { + try { + DataContainer schematicData = DataTranslators.SCHEMATIC.translate(schematic); + DataFormats.NBT.writeTo(new GZIPOutputStream(new FileOutputStream( + new File(directory, String.format("%s.schematic", name)) + )), schematicData); + plugin.getSchematicManager().getSchematics().add(new IslandSchematic(schematic, name)); + return true; + } catch (Exception e) { + plugin.getLogger().error("Error saving schematic: {}\n{}", name, e.getStackTrace()); + return false; + } + } + + public boolean delete(IslandSchematic schematic) { + try { + Files.delete(Paths.get(directory.getPath(), schematic.getFileName())); + schematics.remove(schematic); + return true; + } catch (Exception e) { + plugin.getLogger().error("Error deleting schematic: {}\n{}", schematic.getName(), e.getStackTrace()); + return false; + } + } + + public void load() { + plugin.getLogger().debug("Started loading schematics."); + schematics.clear(); + unpackDefaultSchematics(); + try { + //noinspection ConstantConditions - exception will be caught + for (File file : directory.listFiles()) { + final String fileName = file.getName(); + if (fileName.endsWith(SCHEMATIC_FILE_EXT)) { + try { + DataContainer schematicData = DataFormats.NBT.readFrom(new GZIPInputStream(new FileInputStream(file))); + Schematic schematic = DataTranslators.SCHEMATIC.translate(schematicData); + schematics.add(new IslandSchematic(schematic, fileName.replace(SCHEMATIC_FILE_EXT, "").toLowerCase())); + } catch (Exception e) { + plugin.getLogger().error("Error loading schematic: " + fileName, e); + continue; + } + plugin.getLogger().debug("Successfully loaded schematic: {}.", fileName); + } else { + plugin.getLogger().debug("Found non-schematic file {}. Ignoring.", fileName); + } + } + } catch (Exception e) { + plugin.getLogger().error("Failed to read schematics directory!", e); + } + plugin.getLogger().debug("Finished loading {} schematics.", schematics.size()); + } + + public boolean save(IslandSchematic schematic) { + try { + DataContainer schematicData = DataTranslators.SCHEMATIC.translate(schematic.getSchematic()); + DataFormats.NBT.writeTo(new GZIPOutputStream(new FileOutputStream( + new File(directory, schematic.getFileName()) + )), schematicData); + } catch (Exception e) { + plugin.getLogger().error("Error saving schematic: " + schematic.getName(), e); + return false; + } + return true; + } + + private void unpackDefaultSchematics() { + String[] defaultSchematics = {"grass", "sand", "skyfactory", "skyfactory4", "snow", "stoneblock2", "wood"}; + if (!directory.exists() || !directory.isDirectory()) { + try { + boolean success = directory.mkdir(); + if (!success) { + throw new IOException(); + } + } catch (SecurityException | IOException e) { + plugin.getLogger().error("Failed to create schematics directory.", e); + } + } + try { + String[] list = directory.list(); + ClassLoader classLoader = getClass().getClassLoader(); + if (classLoader != null && (list == null || list.length == 0)) { + for (String name : defaultSchematics) { + InputStream schematic = classLoader.getResourceAsStream(name + SCHEMATIC_FILE_EXT); + Path target = Paths.get(String.format("%s%s%s.schematic", directory.toPath(), File.separator, name)); + if (schematic != null) { + Files.copy(schematic, target); + } + } + } + } catch (SecurityException | IOException e) { + plugin.getLogger().error("Failed to create default schematic.", e); + } + } +} diff --git a/src/main/java/net/mohron/skyclaims/schematic/SchematicUI.java b/src/main/java/net/mohron/skyclaims/schematic/SchematicUI.java new file mode 100644 index 00000000..1f2aa734 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/schematic/SchematicUI.java @@ -0,0 +1,77 @@ +package net.mohron.skyclaims.schematic; + +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; +import net.mohron.skyclaims.SkyClaims; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.data.key.Keys; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.event.item.inventory.ClickInventoryEvent; +import org.spongepowered.api.item.ItemTypes; +import org.spongepowered.api.item.inventory.Inventory; +import org.spongepowered.api.item.inventory.InventoryArchetypes; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.inventory.property.InventoryDimension; +import org.spongepowered.api.item.inventory.property.InventoryTitle; +import org.spongepowered.api.item.inventory.property.SlotPos; +import org.spongepowered.api.item.inventory.query.QueryOperationTypes; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColors; + +public final class SchematicUI { + + private static final SkyClaims PLUGIN = SkyClaims.getInstance(); + + private SchematicUI() { + } + + public static Inventory of(List schematics, Function> mapper) { + Inventory inventory = Inventory.builder() + .of(InventoryArchetypes.CHEST) + .property(InventoryTitle.PROPERTY_NAME, InventoryTitle.of(Text.of(TextColors.AQUA, "Schematics"))) + .property(InventoryDimension.PROPERTY_NAME, InventoryDimension.of(9, schematics.size() / 9 + 1)) + .listener(ClickInventoryEvent.class, handleClick(mapper)) + .build(PLUGIN); + + for (int i = 0; i < schematics.size(); i++) { + IslandSchematic schematic = schematics.get(i); + ItemStack itemStack = ItemStack.builder() + .itemType(schematic.getIcon().orElse(ItemTypes.GOLDEN_SHOVEL)) + .add(Keys.DISPLAY_NAME, schematic.getText()) + .quantity(1) + .build(); + inventory.query(QueryOperationTypes.INVENTORY_PROPERTY.of(SlotPos.of(i % 9, i / 9))).first().set(itemStack); + } + + return inventory; + } + + private static Consumer handleClick(Function> mapper) { + return event -> { + if (event.getCause().first(Player.class).isPresent()) { + Player player = event.getCause().first(Player.class).get(); + getSchematic(event).ifPresent(s -> { + mapper.apply(s).accept(player); + player.closeInventory(); + }); + event.setCancelled(true); + } + }; + } + + private static Optional getSchematic(ClickInventoryEvent event) { + if (event.getCursorTransaction().isValid()) { + ItemStackSnapshot itemStack = event.getCursorTransaction().getFinal(); + if (itemStack.get(Keys.DISPLAY_NAME).isPresent()) { + Text name = itemStack.get(Keys.DISPLAY_NAME).get(); + return PLUGIN.getSchematicManager().getSchematics().stream() + .filter(s -> s.getText().equals(name)) + .findAny(); + } + } + return Optional.empty(); + } +} diff --git a/src/main/java/net/mohron/skyclaims/team/Invite.java b/src/main/java/net/mohron/skyclaims/team/Invite.java index 9dcfae6a..16e66e22 100644 --- a/src/main/java/net/mohron/skyclaims/team/Invite.java +++ b/src/main/java/net/mohron/skyclaims/team/Invite.java @@ -25,8 +25,10 @@ import javax.annotation.Nonnull; import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.spongepowered.api.Sponge; import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.action.TextActions; @@ -34,6 +36,8 @@ public class Invite { + public static final SkyClaims PLUGIN = SkyClaims.getInstance(); + private final Island island; private final User sender; private final User receiver; @@ -46,7 +50,7 @@ private Invite(Island island, User sender, User receiver, PrivilegeType privileg this.receiver = receiver; this.privilegeType = privilegeType; this.sent = Instant.now(); - SkyClaims.getInstance().getInviteService().addInvite(this); + PLUGIN.getInviteService().addInvite(this); } public Island getIsland() { @@ -81,22 +85,13 @@ public void send() { Text.builder("ACCEPT") .color(TextColors.GREEN) .onHover(TextActions.showText(Text.of(TextColors.GREEN, "Click to accept"))) - .onClick(TextActions.executeCallback(src -> { - if (SkyClaims.getInstance().getInviteService().inviteExists(this)) { - src.sendMessage(Text.of( - TextColors.GREEN, "You are now a ", privilegeType.toText(), TextColors.GREEN, - " on ", island.getName(), TextColors.GREEN, - "!" - )); - this.accept(); - } - })), + .onClick(TextActions.executeCallback(PLUGIN.getInviteService().acceptInvite(this))), TextColors.WHITE, "] [", Text.builder("DENY") .color(TextColors.RED) .onHover(TextActions.showText(Text.of(TextColors.RED, "Click to deny"))) .onClick(TextActions.executeCallback(src -> { - if (SkyClaims.getInstance().getInviteService().inviteExists(this)) { + if (PLUGIN.getInviteService().inviteExists(this)) { src.sendMessage(Text.of( TextColors.GREEN, "You have denied ", island.getPrivilegeType(sender).format(sender.getName()), @@ -109,13 +104,18 @@ public void send() { ))); } - public void accept() { + void accept() { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); island.addMember(receiver, privilegeType); - SkyClaims.getInstance().getInviteService().removeInvite(this); + Sponge.getCauseStackManager().popCause(); + Sponge.getScheduler().createTaskBuilder() + .execute(IslandManager.processCommands(receiver.getName(), null)) + .submit(PLUGIN); + PLUGIN.getInviteService().removeInvite(this); } - public void deny() { - SkyClaims.getInstance().getInviteService().removeInvite(this); + void deny() { + PLUGIN.getInviteService().removeInvite(this); } public static Invite.Builder builder() { diff --git a/src/main/java/net/mohron/skyclaims/team/InviteService.java b/src/main/java/net/mohron/skyclaims/team/InviteService.java index 6941486e..636341c1 100644 --- a/src/main/java/net/mohron/skyclaims/team/InviteService.java +++ b/src/main/java/net/mohron/skyclaims/team/InviteService.java @@ -28,7 +28,7 @@ import java.util.stream.Collectors; import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.permissions.Options; -import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.entity.living.player.User; @@ -49,7 +49,7 @@ public InviteService() { } private enum Type { - INCOMING, OUTGOING; + INCOMING, OUTGOING } void addInvite(Invite invite) { @@ -78,14 +78,13 @@ public Consumer listOutgoingInvites() { private List getIncomingInviteText(User user) { SimpleDateFormat sdf = PLUGIN.getConfig().getMiscConfig().getDateFormat(); - boolean canJoin = Options.getMaxIslands(user.getUniqueId()) < 1 || Options.getMaxIslands(user.getUniqueId()) - Island.getTotalIslands(user) > 0; return invites.row(user).values().stream() .map(invite -> Text.of( TextColors.WHITE, "[", Text.builder("✓") .color(TextColors.GREEN) .onHover(TextActions.showText(Text.of(TextColors.GREEN, "Accept"))) - .onClick(TextActions.executeCallback(acceptInvite(invite, canJoin))), + .onClick(TextActions.executeCallback(acceptInvite(invite))), TextColors.WHITE, "] [", Text.builder("✗") .color(TextColors.RED) @@ -105,12 +104,26 @@ private List getIncomingInviteText(User user) { .collect(Collectors.toList()); } - private Consumer acceptInvite(Invite invite, boolean canJoin) { + Consumer acceptInvite(Invite invite) { return src -> { - if (canJoin) { - invite.accept(); - } else { + int maxIslands = Options.getMaxIslands(invite.getReceiver().getUniqueId()); + int maxTeammates = Options.getMaxTeammates(invite.getIsland().getOwnerUniqueId()); + + // Check if the receiver can accept this invite + if (!inviteExists(invite)) { + src.sendMessage(Text.of(TextColors.RED, "This invite has expired!")); + } else if (maxIslands > 0 && maxIslands - IslandManager.getTotalIslands(invite.getReceiver()) < 1) { src.sendMessage(Text.of(TextColors.RED, "You have reached your maximum number of islands!")); + } else if (maxTeammates > 0 && invite.getIsland().getTotalMembers() >= maxTeammates) { + src.sendMessage(Text.of(invite.getIsland().getName(), TextColors.RED, " has reached its maximum team size!")); + } else { + invite.accept(); + src.sendMessage(Text.of( + TextColors.GREEN, "You are now a ", + invite.getPrivilegeType().toText(), + TextColors.GREEN, " on ", + invite.getIsland().getName(), TextColors.GREEN, "!" + )); } }; } @@ -151,16 +164,12 @@ private Consumer listInvites(Type type) { TextColors.AQUA, (type == Type.INCOMING) ? "[" : Text.EMPTY, Text.builder("Incoming") .color((type == Type.INCOMING) ? TextColors.GREEN : TextColors.GRAY) - .onHover(TextActions.showText( - Text.of("Click here to show ", TextColors.GREEN, "incoming", TextColors.RESET, - " invites"))) + .onHover(TextActions.showText(Text.of("Click here to show ", TextColors.GREEN, "incoming", TextColors.RESET, " invites"))) .onClick(TextActions.executeCallback(listIncomingInvites())), TextColors.AQUA, (type == Type.INCOMING) ? "] " : " [", Text.builder("Outgoing") .color((type == Type.OUTGOING) ? TextColors.YELLOW : TextColors.GRAY) - .onHover(TextActions.showText( - Text.of("Click here to show ", TextColors.YELLOW, "outgoing", TextColors.RESET, - " invites"))) + .onHover(TextActions.showText(Text.of("Click here to show ", TextColors.YELLOW, "outgoing", TextColors.RESET, " invites"))) .onClick(TextActions.executeCallback(listOutgoingInvites())), TextColors.AQUA, (type == Type.OUTGOING) ? "]" : Text.EMPTY ); @@ -169,19 +178,22 @@ private Consumer listInvites(Type type) { ? PLUGIN.getInviteService().getIncomingInviteText(player) : PLUGIN.getInviteService().getOutgoingInviteText(player); if (contents.isEmpty()) { - contents = ImmutableList.of(Text - .of(TextColors.RED, "You have no ", type.toString().toLowerCase(), " invites!")); + contents = ImmutableList.of(Text.of(TextColors.RED, "You have no ", type.toString().toLowerCase(), " invites!")); } int limit = Options.getMaxIslands(player.getUniqueId()); - Text header = limit < 1 - ? null - : Text.of(TextColors.GRAY, "You currently have ", TextColors.LIGHT_PURPLE, Island.getTotalIslands(player), TextColors.GRAY, " of ", - TextColors.LIGHT_PURPLE, limit, TextColors.GRAY, " maximum island", limit > 1 ? "s" : Text.EMPTY, "."); + Text header = Text.of( + TextColors.GRAY, "You currently have ", + TextColors.LIGHT_PURPLE, IslandManager.getTotalIslands(player), + TextColors.GRAY, " of ", + TextColors.LIGHT_PURPLE, limit, + TextColors.GRAY, " maximum island", + limit > 1 ? "s" : Text.EMPTY, "." + ); PaginationList.builder() .title(title) - .header(header) + .header(limit < 1 ? null : header) .padding(Text.of(TextColors.AQUA, TextStyles.STRIKETHROUGH, "-")) .contents(contents) .sendTo(player); diff --git a/src/main/java/net/mohron/skyclaims/util/ClaimUtil.java b/src/main/java/net/mohron/skyclaims/util/ClaimUtil.java index 7ca81df6..f7973cf7 100644 --- a/src/main/java/net/mohron/skyclaims/util/ClaimUtil.java +++ b/src/main/java/net/mohron/skyclaims/util/ClaimUtil.java @@ -35,21 +35,24 @@ import net.mohron.skyclaims.exception.CreateIslandException; import net.mohron.skyclaims.permissions.Options; import net.mohron.skyclaims.world.region.Region; +import org.spongepowered.api.Sponge; import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.service.user.UserStorageService; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.world.World; -public class ClaimUtil { +public final class ClaimUtil { private static final SkyClaims PLUGIN = SkyClaims.getInstance(); + private ClaimUtil() { + } + @SuppressWarnings("OptionalGetWithoutIsPresent") - public static Claim createIslandClaim(@Nonnull UUID ownerUniqueId, @Nonnull Region region) - throws CreateIslandException { - ClaimManager claimManager = PLUGIN.getGriefPrevention() - .getClaimManager(PLUGIN.getConfig().getWorldConfig().getWorld()); + public static Claim createIslandClaim(@Nonnull UUID ownerUniqueId, @Nonnull Region region) throws CreateIslandException { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); + ClaimManager claimManager = PLUGIN.getGriefPrevention().getClaimManager(PLUGIN.getConfig().getWorldConfig().getWorld()); Claim claim = null; ClaimResult claimResult; @@ -69,39 +72,47 @@ public static Claim createIslandClaim(@Nonnull UUID ownerUniqueId, @Nonnull Regi ); break; case OVERLAPPING_CLAIM: - for (Claim claim1 : claimResult.getClaims()) { - claimManager.deleteClaim(claim1); + for (Claim overlappedClaim : claimResult.getClaims()) { + ClaimResult delete = claimManager.deleteClaim(overlappedClaim); + if (!delete.successful()) { + PLUGIN.getLogger().error("{}: {}", delete.getResultType(), delete.getMessage()); + throw new CreateIslandException(Text.of( + TextColors.RED, "Failed to delete overlapping claim: ", overlappedClaim.getUniqueId() + )); + } + PLUGIN.getLogger().info( + "Removed claim overlapping {}'s island (Owner: {}, ID: {}).", + getName(ownerUniqueId), + overlappedClaim.getOwnerName().toPlain(), + overlappedClaim.getUniqueId() + ); } - PLUGIN.getLogger().info( - "Removing claim overlapping {}'s island (Owner: {}, ID: {}).", - getName(ownerUniqueId), - claimResult.getClaim().get().getOwnerName().toPlain(), - claimResult.getClaim().get().getUniqueId() - ); break; default: - throw new CreateIslandException( - Text.of(TextColors.RED, "Failed to create claim: ", claimResult.getResultType())); + throw new CreateIslandException(Text.of( + TextColors.RED, "Failed to create claim: ", claimResult.getResultType(), + Text.NEW_LINE, claimResult.getMessage().orElse(Text.of("No message provided")) + )); } } while (claim == null); + Sponge.getCauseStackManager().popCause(); return claim; } - private static ClaimResult createIslandClaimResult(@Nonnull UUID ownerUniqueId, - @Nonnull Region region) throws CreateIslandException { + private static ClaimResult createIslandClaimResult(@Nonnull UUID ownerUniqueId, @Nonnull Region region) throws CreateIslandException { int initialSpacing = 256 - Options.getMinSize(ownerUniqueId); World world = PLUGIN.getConfig().getWorldConfig().getWorld(); checkNotNull(world, "Error Creating Claim: World (%s) is null", world.getName()); - checkArgument(world.isLoaded(), "Error Creating Claim: World (%s) is not loaded", - world.getName()); + checkArgument(world.isLoaded(), "Error Creating Claim: World (%s) is not loaded", world.getName()); checkNotNull(ownerUniqueId, "Error Creating Claim: Owner is null"); checkNotNull(region, "Error Creating Claim: Region is null"); PlayerData playerData = PLUGIN.getGriefPrevention() .getWorldPlayerData(world.getProperties(), ownerUniqueId) - .orElseThrow(() -> new CreateIslandException( - Text.of(TextColors.RED, "Unable to load GriefPrevention player data!"))); + .orElseThrow(() -> new CreateIslandException(Text.of( + TextColors.RED, "Unable to load GriefPrevention player data!" + ))); return Claim.builder() .type(ClaimType.TOWN) @@ -129,16 +140,14 @@ private static ClaimResult createIslandClaimResult(@Nonnull UUID ownerUniqueId, public static void createSpawnClaim(List regions) { ClaimResult claimResult = ClaimUtil.createSpawnClaimResult(regions); if (claimResult.successful()) { - PLUGIN.getLogger().debug("Reserved {} regions for spawn. Admin Claim: {}", regions.size(), - claimResult.getClaim().get().getUniqueId()); + PLUGIN.getLogger().debug("Reserved {} regions for spawn. Admin Claim: {}", regions.size(), claimResult.getClaim().get().getUniqueId()); } } private static ClaimResult createSpawnClaimResult(List regions) { World world = PLUGIN.getConfig().getWorldConfig().getWorld(); checkNotNull(world, "Error Creating Claim: World (%s) is null", world.getName()); - checkArgument(world.isLoaded(), "Error Creating Claim: World (%s) is not loaded", - world.getName()); + checkArgument(world.isLoaded(), "Error Creating Claim: World (%s) is not loaded", world.getName()); Region lesserRegion = new Region(0, 0); Region greaterRegion = new Region(0, 0); for (Region region : regions) { @@ -156,23 +165,19 @@ private static ClaimResult createSpawnClaimResult(List regions) { .type(ClaimType.ADMIN) .world(world) .bounds( - new Vector3i(lesserRegion.getLesserBoundary().getX(), 0, - lesserRegion.getLesserBoundary().getZ()), - new Vector3i(greaterRegion.getGreaterBoundary().getX(), 255, - greaterRegion.getGreaterBoundary().getZ()) + new Vector3i(lesserRegion.getLesserBoundary().getX(), 0, lesserRegion.getLesserBoundary().getZ()), + new Vector3i(greaterRegion.getGreaterBoundary().getX(), 255, greaterRegion.getGreaterBoundary().getZ()) ) .build(); } private static String getName(UUID uuid) { - Optional user = PLUGIN.getGame().getServiceManager() - .provideUnchecked(UserStorageService.class).get(uuid); + Optional user = PLUGIN.getGame().getServiceManager().provideUnchecked(UserStorageService.class).get(uuid); if (user.isPresent()) { return user.get().getName(); } else { try { - return PLUGIN.getGame().getServer().getGameProfileManager().get(uuid).get().getName() - .orElse("somebody"); + return PLUGIN.getGame().getServer().getGameProfileManager().get(uuid).get().getName().orElse("somebody"); } catch (Exception e) { return "somebody"; } diff --git a/src/main/java/net/mohron/skyclaims/util/FlatWorldUtil.java b/src/main/java/net/mohron/skyclaims/util/FlatWorldUtil.java new file mode 100644 index 00000000..d531a0fb --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/util/FlatWorldUtil.java @@ -0,0 +1,98 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.util; + +import java.util.Arrays; +import net.mohron.skyclaims.SkyClaims; +import net.mohron.skyclaims.exception.SkyClaimsException; +import org.apache.commons.lang3.StringUtils; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.block.BlockTypes; +import org.spongepowered.api.text.Text; + +public final class FlatWorldUtil { + + private static final BlockState[] voidWorld = new BlockState[256]; + + static { + Arrays.fill(voidWorld, BlockTypes.AIR.getDefaultState()); + } + + private FlatWorldUtil() { + } + + public static BlockState[] getBlocks(String code) throws SkyClaimsException { + BlockState[] list = new BlockState[256]; + int l = 0; + + // Bank code is void + if (StringUtils.isBlank(code)) { + return voidWorld; + } + + // Only the first part is used + if (code.contains(";")) { + code = code.split(";")[0]; + } + + String[] blockIds = code.split(","); + + for (String layer : blockIds) { + int count = 1; + String blockId; + // If the block id has a quantity set, split the quantity and block id + if (layer.contains("*")) { + String[] s = layer.split("\\*"); + count = Integer.valueOf(s[0]); + blockId = s[1]; + } else { + blockId = layer; + } + + BlockType type = Sponge.getRegistry().getType(BlockType.class, blockId) + .orElseThrow(() -> new SkyClaimsException(Text.of("Unable to parse flat world preset code. Unknown Block ID: ", blockId))); + for (int i = 0; i < count; i++) { + list[l] = BlockState.builder().blockType(type).build(); + l++; + } + } + + // Fill the remaining layers with air + for (; l < 255; l++) { + list[l] = BlockTypes.AIR.getDefaultState(); + } + + return list; + } + + public static BlockState[] getBlocksSafely(String code) { + try { + return getBlocks(code); + } catch (SkyClaimsException e) { + SkyClaims.getInstance().getLogger().error(e.getMessage(), e); + return voidWorld; + } + } + + public static BlockState[] getVoidWorld() { + return voidWorld; + } +} diff --git a/src/main/java/net/mohron/skyclaims/util/WorldUtil.java b/src/main/java/net/mohron/skyclaims/util/WorldUtil.java index fb6132eb..ef197aa6 100644 --- a/src/main/java/net/mohron/skyclaims/util/WorldUtil.java +++ b/src/main/java/net/mohron/skyclaims/util/WorldUtil.java @@ -18,6 +18,8 @@ package net.mohron.skyclaims.util; +import java.util.NoSuchElementException; +import java.util.Optional; import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.world.Island; import net.mohron.skyclaims.world.region.Region; @@ -31,7 +33,11 @@ public class WorldUtil { public static World getDefaultWorld() { String defaultWorldName = PLUGIN.getGame().getServer().getDefaultWorldName(); - return PLUGIN.getGame().getServer().getWorld(defaultWorldName).get(); + final Optional world = PLUGIN.getGame().getServer().getWorld(defaultWorldName); + if (world.isPresent()) { + return world.get(); + } + throw new NoSuchElementException("Failed to locate default world '" + defaultWorldName + "'!"); } public static void setBlockBiome(Location location, BiomeType biomeType) { diff --git a/src/main/java/net/mohron/skyclaims/world/GenerateIslandTask.java b/src/main/java/net/mohron/skyclaims/world/GenerateIslandTask.java index 2f8e2345..cfae3050 100644 --- a/src/main/java/net/mohron/skyclaims/world/GenerateIslandTask.java +++ b/src/main/java/net/mohron/skyclaims/world/GenerateIslandTask.java @@ -18,19 +18,14 @@ package net.mohron.skyclaims.world; -import java.io.File; -import java.io.FileInputStream; import java.util.UUID; -import java.util.zip.GZIPInputStream; import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.SkyClaimsTimings; import net.mohron.skyclaims.permissions.Options; +import net.mohron.skyclaims.schematic.IslandSchematic; import net.mohron.skyclaims.util.CommandUtil; import net.mohron.skyclaims.util.WorldUtil; import org.spongepowered.api.Sponge; -import org.spongepowered.api.data.DataContainer; -import org.spongepowered.api.data.persistence.DataFormats; -import org.spongepowered.api.data.persistence.DataTranslators; import org.spongepowered.api.entity.Transform; import org.spongepowered.api.world.BlockChangeFlags; import org.spongepowered.api.world.Location; @@ -43,9 +38,9 @@ public class GenerateIslandTask implements Runnable { private UUID owner; private Island island; - private String schematic; + private IslandSchematic schematic; - public GenerateIslandTask(UUID owner, Island island, String schematic) { + public GenerateIslandTask(UUID owner, Island island, IslandSchematic schematic) { this.owner = owner; this.island = island; this.schematic = schematic; @@ -55,32 +50,8 @@ public GenerateIslandTask(UUID owner, Island island, String schematic) { public void run() { SkyClaimsTimings.GENERATE_ISLAND.startTimingIfSync(); World world = PLUGIN.getConfig().getWorldConfig().getWorld(); - File inputFile = new File(PLUGIN.getConfigDir().toString(), - String.format("schematics%s%s.schematic", File.separator, schematic)); - DataContainer schematicData; - try { - schematicData = DataFormats.NBT.readFrom(new GZIPInputStream(new FileInputStream(inputFile))); - } catch (Exception e) { - e.printStackTrace(); - PLUGIN.getLogger().error("Error loading schematic: " + e.getMessage()); - SkyClaimsTimings.GENERATE_ISLAND.abort(); - return; - } - - ArchetypeVolume volume; - try { - volume = DataTranslators.SCHEMATIC.translate(schematicData); - } catch (Exception e) { - try { - volume = DataTranslators.LEGACY_SCHEMATIC.translate(schematicData); - PLUGIN.getLogger().warn("Loaded legacy schematic: {}", e.getMessage()); - } catch (Exception e2) { - PLUGIN.getLogger().error("Invalid schematic file ({})!\n{}", schematic, e2); - SkyClaimsTimings.GENERATE_ISLAND.abort(); - return; - } - } + ArchetypeVolume volume = schematic.getSchematic(); Location centerBlock = island.getRegion().getCenter(); // Loads center chunks @@ -95,28 +66,29 @@ public void run() { } } + int height = schematic.getHeight().orElse(PLUGIN.getConfig().getWorldConfig().getIslandHeight()); Location spawn = new Location<>( island.getWorld(), centerBlock.getX(), - centerBlock.getY() + volume.getBlockSize().getY() - 1, + height + volume.getRelativeBlockView().getBlockMax().getY() - volume.getBlockMax().getY() - 1, centerBlock.getZ() ); island.setSpawn(new Transform<>(spawn.getExtent(), spawn.getPosition())); volume.apply(spawn, BlockChangeFlags.NONE); - // Set the region's BiomeType using the default biome option if set - Options.getDefaultBiome(owner).ifPresent(biomeType -> { - WorldUtil.setRegionBiome(island, biomeType); - }); + // Set the region's BiomeType using the schematic default biome or player option if set + if (schematic.getBiomeType().isPresent()) { + WorldUtil.setRegionBiome(island, schematic.getBiomeType().get()); + } else if (Options.getDefaultBiome(owner).isPresent()) { + WorldUtil.setRegionBiome(island, Options.getDefaultBiome(owner).get()); + } if (PLUGIN.getConfig().getMiscConfig().isTeleportOnCreate()) { - Sponge.getServer().getPlayer(owner).ifPresent(p1 -> { - PLUGIN.getGame().getScheduler().createTaskBuilder() - .delayTicks(20) - .execute(CommandUtil.createTeleportConsumer(p1, spawn)) - .submit(PLUGIN); - }); + Sponge.getServer().getPlayer(owner).ifPresent(p -> PLUGIN.getGame().getScheduler().createTaskBuilder() + .delayTicks(20) + .execute(CommandUtil.createTeleportConsumer(p, spawn)) + .submit(PLUGIN)); } SkyClaimsTimings.GENERATE_ISLAND.stopTimingIfSync(); diff --git a/src/main/java/net/mohron/skyclaims/world/Island.java b/src/main/java/net/mohron/skyclaims/world/Island.java index e62f678f..ee1033e3 100644 --- a/src/main/java/net/mohron/skyclaims/world/Island.java +++ b/src/main/java/net/mohron/skyclaims/world/Island.java @@ -21,15 +21,19 @@ import com.flowpowered.math.vector.Vector3d; import com.flowpowered.math.vector.Vector3i; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import java.time.Instant; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import me.ryanhamshire.griefprevention.api.claim.Claim; import me.ryanhamshire.griefprevention.api.claim.ClaimManager; import me.ryanhamshire.griefprevention.api.claim.ClaimResult; @@ -40,11 +44,13 @@ import net.mohron.skyclaims.exception.CreateIslandException; import net.mohron.skyclaims.exception.InvalidRegionException; import net.mohron.skyclaims.permissions.Options; +import net.mohron.skyclaims.schematic.IslandSchematic; import net.mohron.skyclaims.team.PrivilegeType; import net.mohron.skyclaims.util.ClaimUtil; import net.mohron.skyclaims.world.region.IRegionPattern; import net.mohron.skyclaims.world.region.Region; import net.mohron.skyclaims.world.region.SpiralRegionPattern; +import org.spongepowered.api.Sponge; import org.spongepowered.api.block.tileentity.TileEntity; import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.Item; @@ -55,6 +61,7 @@ import org.spongepowered.api.entity.living.monster.Monster; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.entity.living.player.User; +import org.spongepowered.api.scheduler.SpongeExecutorService; import org.spongepowered.api.service.context.Context; import org.spongepowered.api.service.context.ContextSource; import org.spongepowered.api.service.user.UserStorageService; @@ -76,7 +83,7 @@ public class Island implements ContextSource { private Transform spawn; private boolean locked; - public Island(User owner, String schematic) throws CreateIslandException { + public Island(User owner, IslandSchematic schematic) throws CreateIslandException { this.id = UUID.randomUUID(); this.context = new Context("island", this.id.toString()); this.owner = owner.getUniqueId(); @@ -95,14 +102,20 @@ public Island(User owner, String schematic) throws CreateIslandException { claim.getData().save(); this.claim = claim.getUniqueId(); - // Run commands defined in config on creation - for (String command : PLUGIN.getConfig().getMiscConfig().getCreateCommands()) { - PLUGIN.getGame().getCommandManager().process(PLUGIN.getGame().getServer().getConsole(), command.replace("@p", owner.getName())); - } + Sponge.getScheduler().createTaskBuilder() + .execute(IslandManager.processCommands(owner.getName(), schematic)) + .submit(PLUGIN); // Generate the island using the specified schematic GenerateIslandTask generateIsland = new GenerateIslandTask(owner.getUniqueId(), this, schematic); - PLUGIN.getGame().getScheduler().createTaskBuilder().execute(generateIsland).submit(PLUGIN); + SpongeExecutorService syncExecutor = Sponge.getScheduler().createSyncExecutor(PLUGIN); + if (PLUGIN.getConfig().getWorldConfig().isRegenOnCreate()) { + CompletableFuture + .runAsync(RegenerateRegionTask.clear(region, getWorld()), Sponge.getScheduler().createAsyncExecutor(PLUGIN)) + .thenRunAsync(generateIsland, syncExecutor); + } else { + CompletableFuture.runAsync(generateIsland, syncExecutor); + } save(); } @@ -113,7 +126,6 @@ public Island(UUID id, UUID owner, UUID claimId, Vector3d spawnLocation, boolean this.owner = owner; this.spawn = new Transform<>(PLUGIN.getConfig().getWorldConfig().getWorld(), spawnLocation); this.locked = locked; - this.claim = claimId; ClaimManager claimManager = PLUGIN.getGriefPrevention().getClaimManager(spawn.getExtent()); Claim claim = claimManager.getClaimByUUID(claimId).orElse(null); @@ -132,71 +144,16 @@ public Island(UUID id, UUID owner, UUID claimId, Vector3d spawnLocation, boolean this.claim = ClaimUtil.createIslandClaim(owner, getRegion()).getUniqueId(); PLUGIN.queueForSaving(this); } catch (CreateIslandException e) { - PLUGIN.getLogger().error( - String.format("Failed to create claim while loading %s (%s).", getName().toPlain(), id), - e); - } - } - } - - public static Optional get(UUID islandUniqueId) { - return Optional.ofNullable(SkyClaims.islands.get(islandUniqueId)); - } - - public static Optional get(Location location) { - return SkyClaims.islands.entrySet().stream() - .filter(i -> i.getValue().contains(location)) - .map(Map.Entry::getValue) - .findFirst(); - } - - public static Optional get(Claim claim) { - for (Island island : SkyClaims.islands.values()) { - if (island.getClaim().isPresent() && island.getClaim().get().equals(claim)) { - return Optional.of(island); - } - } - return Optional.empty(); - } - - @Deprecated - public static Optional getByOwner(UUID owner) { - for (Island island : SkyClaims.islands.values()) { - if (island.getOwnerUniqueId().equals(owner)) { - return Optional.of(island); - } - } - return Optional.empty(); - } - - public static boolean hasIsland(UUID owner) { - if (SkyClaims.islands.isEmpty()) { - return false; - } - for (Island island : SkyClaims.islands.values()) { - if (island.getOwnerUniqueId().equals(owner)) { - return true; + PLUGIN.getLogger().error(String.format("Failed to create claim while loading %s (%s).", getName().toPlain(), id), e); } } - return false; - } - - public static int getTotalIslandsOwned(UUID owner) { - return (int) SkyClaims.islands.values().stream() - .filter(i -> i.getOwnerUniqueId().equals(owner)) - .count(); - } - - public static int getTotalIslands(User user) { - return (int) SkyClaims.islands.values().stream() - .filter(i -> i.isMember(user)) - .count(); } public UUID getUniqueId() { return id; } + @Nonnull @Override public Context getContext() { return this.context; @@ -246,6 +203,14 @@ public Text getName() { : Text.of(TextColors.AQUA, getOwnerName(), "'s Island"); } + public void setName(@Nullable Text name) { + getClaim().ifPresent(claim -> { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); + claim.getData().setName(name); + Sponge.getCauseStackManager().popCause(); + }); + } + public String getSortableName() { return getName().toPlain().toLowerCase(); } @@ -264,14 +229,14 @@ public World getWorld() { } public Transform getSpawn() { - return spawn; + return spawn.setExtent(getWorld()); } public void setSpawn(Transform transform) { if (contains(transform.getLocation())) { Transform spawn = new Transform<>(getWorld(), transform.getPosition(), transform.getRotation()); if (transform.getLocation().getY() < 0 || transform.getLocation().getY() > 256) { - spawn = spawn.setPosition(new Vector3d( + spawn = spawn.setPosition(new Vector3d( spawn.getLocation().getX(), PLUGIN.getConfig().getWorldConfig().getIslandHeight(), spawn.getLocation().getZ() @@ -303,12 +268,13 @@ public int getWidth() { return getClaim().isPresent() ? getClaim().get().getWidth() : 512; } - private boolean setWidth(int width) { + public boolean setWidth(int width) { if (width < 0 || width > 512) { return false; } PLUGIN.getGriefPrevention().getWorldPlayerData(getWorld().getProperties(), owner) .ifPresent(data -> getClaim().ifPresent(claim -> { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); int spacing = (512 - width) / 2; claim.resize(new Vector3i( getRegion().getLesserBoundary().getX() + spacing, @@ -319,6 +285,7 @@ private boolean setWidth(int width) { data.getMaxClaimLevel(), getRegion().getGreaterBoundary().getZ() - spacing )); + Sponge.getCauseStackManager().popCause(); })); return getWidth() == width; } @@ -328,20 +295,29 @@ public void addMember(User user, PrivilegeType type) { case OWNER: UUID existingOwner = owner; transfer(user); - getClaim().ifPresent(c -> c.addUserTrust(existingOwner, TrustType.MANAGER)); + getClaim().ifPresent(c -> { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); + c.addUserTrust(existingOwner, TrustType.MANAGER); + Sponge.getCauseStackManager().popCause(); + }); break; case MANAGER: case MEMBER: - getClaim().ifPresent(c -> c.addUserTrust(user.getUniqueId(), type.getTrustType())); + getClaim().ifPresent(c -> { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); + c.addUserTrust(user.getUniqueId(), type.getTrustType()); + Sponge.getCauseStackManager().popCause(); + }); break; case NONE: - getClaim().ifPresent(c -> c.removeUserTrust(user.getUniqueId(), type.getTrustType())); + removeMember(user); break; } } public void promote(User user) { getClaim().ifPresent(c -> { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); if (c.isUserTrusted(user, TrustType.BUILDER)) { c.removeUserTrust(user.getUniqueId(), TrustType.NONE); c.addUserTrust(user.getUniqueId(), TrustType.MANAGER); @@ -351,23 +327,43 @@ public void promote(User user) { transfer(user); c.addUserTrust(existingOwner, TrustType.MANAGER); } + Sponge.getCauseStackManager().popCause(); }); } public void demote(User user) { getClaim().ifPresent(c -> { if (c.isUserTrusted(user, TrustType.MANAGER)) { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); c.removeUserTrust(user.getUniqueId(), TrustType.NONE); c.addUserTrust(user.getUniqueId(), TrustType.BUILDER); + Sponge.getCauseStackManager().popCause(); } }); } public void removeMember(User user) { - getClaim().ifPresent(c -> c.removeUserTrust(user.getUniqueId(), TrustType.NONE)); + getClaim().ifPresent(c -> { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); + c.removeUserTrust(user.getUniqueId(), TrustType.NONE); + Sponge.getCauseStackManager().popCause(); + }); } - public List getMembers() { + public Collection getMembers() { + Set users = Sets.newHashSet(); + UserStorageService uss = Sponge.getServiceManager().provideUnchecked(UserStorageService.class); + uss.get(owner).ifPresent(users::add); + if(getClaim().isPresent()) { + for (UUID uuid : getClaim().get().getUserTrusts()) { + uss.get(uuid).ifPresent(users::add); + } + } + + return users; + } + + public List getMemberNames() { List members = Lists.newArrayList(); if (!getClaim().isPresent()) { return members; @@ -378,7 +374,7 @@ public List getMembers() { return members; } - public List getManagers() { + public List getManagerNames() { List members = Lists.newArrayList(); if (!getClaim().isPresent()) { return members; @@ -444,9 +440,9 @@ public Collection getHostileEntities() { } public Collection getPassiveEntities() { - return getWorld().getEntities( - e -> contains(e.getLocation()) && e instanceof Animal || e instanceof Aquatic - || e instanceof Ambient); + return getWorld().getEntities(e -> contains( + e.getLocation()) && e instanceof Animal || e instanceof Aquatic || e instanceof Ambient + ); } public Collection getItemEntities() { @@ -463,6 +459,7 @@ public Region getRegion() { public void transfer(User user) { getClaim().ifPresent(claim -> { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); ClaimResult result = claim.transferOwner(user.getUniqueId()); if (result.getResultType() != ClaimResultType.SUCCESS) { PLUGIN.getLogger().error(String.format( @@ -470,6 +467,7 @@ public void transfer(User user) { claim.getUniqueId(), getOwnerName(), user.getName(), result.getResultType() )); } + Sponge.getCauseStackManager().popCause(); }); this.owner = user.getUniqueId(); save(); @@ -482,25 +480,34 @@ public void expand(int blocks) { setWidth(getWidth() + blocks * 2); } + public void shrink(int blocks) { + if (blocks < 1) { + return; + } + setWidth(getWidth() - blocks * 2); + } + private void save() { - SkyClaims.islands.put(id, this); + IslandManager.ISLANDS.put(id, this); PLUGIN.getDatabase().saveIsland(this); } public void clear() { - RegenerateRegionTask regenerateRegionTask = new RegenerateRegionTask(getRegion()); - PLUGIN.getGame().getScheduler().createTaskBuilder().execute(regenerateRegionTask).submit(PLUGIN); + RegenerateRegionTask regenerateRegionTask = RegenerateRegionTask.clear(getRegion(), getWorld()); + PLUGIN.getGame().getScheduler().createTaskBuilder().async().execute(regenerateRegionTask).submit(PLUGIN); } - public void reset(String schematic, boolean runCommands) { - RegenerateRegionTask regenerateRegionTask = new RegenerateRegionTask(this, schematic, runCommands); - PLUGIN.getGame().getScheduler().createTaskBuilder().execute(regenerateRegionTask).submit(PLUGIN); + public void reset(IslandSchematic schematic, boolean runCommands) { + RegenerateRegionTask regenerateRegionTask = RegenerateRegionTask.regen(this, schematic, runCommands); + PLUGIN.getGame().getScheduler().createTaskBuilder().async().execute(regenerateRegionTask).submit(PLUGIN); } public void delete() { + Sponge.getCauseStackManager().pushCause(PLUGIN.getPluginContainer()); ClaimManager claimManager = PLUGIN.getGriefPrevention().getClaimManager(getWorld()); getClaim().ifPresent(claimManager::deleteClaim); - SkyClaims.islands.remove(id); + IslandManager.ISLANDS.remove(id); PLUGIN.getDatabase().removeIsland(this); + Sponge.getCauseStackManager().popCause(); } } diff --git a/src/main/java/net/mohron/skyclaims/world/IslandCleanupTask.java b/src/main/java/net/mohron/skyclaims/world/IslandCleanupTask.java index d9a180e0..7f47619a 100644 --- a/src/main/java/net/mohron/skyclaims/world/IslandCleanupTask.java +++ b/src/main/java/net/mohron/skyclaims/world/IslandCleanupTask.java @@ -23,11 +23,13 @@ import java.time.Duration; import java.time.Instant; import java.util.Collection; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.SkyClaimsTimings; import net.mohron.skyclaims.permissions.Options; import org.spongepowered.api.Sponge; +import org.spongepowered.api.scheduler.SpongeExecutorService; public class IslandCleanupTask implements Runnable { @@ -42,24 +44,28 @@ public IslandCleanupTask(Collection islands) { public void run() { SkyClaimsTimings.ISLAND_CLEANUP.startTimingIfSync(); - PLUGIN.getLogger().info("Starting Island Cleanup."); + PLUGIN.getLogger().info("Starting island cleanup check."); Stopwatch sw = Stopwatch.createStarted(); + SpongeExecutorService asyncExecutor = Sponge.getScheduler().createAsyncExecutor(PLUGIN); + SpongeExecutorService syncExecutor = Sponge.getScheduler().createSyncExecutor(PLUGIN); + islands.forEach(i -> { int age = (int) Duration.between(i.getDateLastActive().toInstant(), Instant.now()).toDays(); int threshold = Options.getExpiration(i.getOwnerUniqueId()); if (threshold <= 0 || age < threshold) { return; } - Sponge.getScheduler().createTaskBuilder().execute(i::clear).submit(PLUGIN); - Sponge.getScheduler().createTaskBuilder().execute(i::delete).submit(PLUGIN); - PLUGIN.getLogger() - .info(String.format("%s (%d,%d) was inactive for %d days and has been removed.", - i.getName().toPlain(), i.getRegion().getX(), i.getRegion().getZ(), age) - ); + PLUGIN.getLogger().info("{} ({},{}) was inactive for {} days and is being removed.", + i.getName().toPlain(), i.getRegion().getX(), i.getRegion().getZ(), age + ); + CompletableFuture + .runAsync(RegenerateRegionTask.clear(i.getRegion(), i.getWorld()), asyncExecutor) + .thenRunAsync(i::delete, syncExecutor) + .thenRun(() -> PLUGIN.getLogger().info("{} has been successfully removed.", i.getName().toPlain())); }); + sw.stop(); - PLUGIN.getLogger() - .info(String.format("Finished Island Cleanup in %dms.", sw.elapsed(TimeUnit.MILLISECONDS))); + PLUGIN.getLogger().info("Finished island cleanup check in {}ms.", sw.elapsed(TimeUnit.MILLISECONDS)); SkyClaimsTimings.ISLAND_CLEANUP.stopTimingIfSync(); } diff --git a/src/main/java/net/mohron/skyclaims/world/IslandManager.java b/src/main/java/net/mohron/skyclaims/world/IslandManager.java new file mode 100644 index 00000000..b5e148d9 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/world/IslandManager.java @@ -0,0 +1,138 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.world; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import javax.annotation.Nullable; +import me.ryanhamshire.griefprevention.api.claim.Claim; +import net.mohron.skyclaims.SkyClaims; +import net.mohron.skyclaims.schematic.IslandSchematic; +import net.mohron.skyclaims.world.region.Region; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.entity.Transform; +import org.spongepowered.api.entity.living.player.User; +import org.spongepowered.api.scheduler.Task; +import org.spongepowered.api.world.Location; +import org.spongepowered.api.world.World; + +public class IslandManager { + + private static final SkyClaims PLUGIN = SkyClaims.getInstance(); + + public static Map ISLANDS = Maps.newHashMap(); + public static Set saveQueue = Sets.newHashSet(); + + public static Optional get(UUID islandUniqueId) { + return Optional.ofNullable(ISLANDS.get(islandUniqueId)); + } + + public static Optional get(Location location) { + return get(Region.get(location)); + } + + public static Optional get(Transform transform) { + return get(Region.get(transform.getLocation())); + } + + public static Optional get(Region region) { + return ISLANDS.values().stream() + .filter(i -> i.getRegion().equals(region)) + .findAny(); + } + + public static Optional get(Claim claim) { + for (Island island : ISLANDS.values()) { + if (island.getClaim().isPresent() && island.getClaim().get().equals(claim)) { + return Optional.of(island); + } + } + return Optional.empty(); + } + + public static List get(User user) { + return ISLANDS.values().stream() + .filter(i -> i.isMember(user)) + .collect(Collectors.toList()); + } + + @Deprecated + public static Optional getByOwner(UUID owner) { + for (Island island : ISLANDS.values()) { + if (island.getOwnerUniqueId().equals(owner)) { + return Optional.of(island); + } + } + return Optional.empty(); + } + + public static boolean hasIsland(UUID owner) { + if (ISLANDS.isEmpty()) { + return false; + } + for (Island island : ISLANDS.values()) { + if (island.getOwnerUniqueId().equals(owner)) { + return true; + } + } + return false; + } + + public static int getTotalIslandsOwned(UUID owner) { + return (int) ISLANDS.values().stream() + .filter(i -> i.getOwnerUniqueId().equals(owner)) + .count(); + } + + public static int getTotalIslands(User user) { + return (int) ISLANDS.values().stream() + .filter(i -> i.isMember(user)) + .count(); + } + + public Map getIslands() { + return ISLANDS; + } + + public static Consumer processCommands(String playerName, @Nullable IslandSchematic schematic) { + return task -> { + // Run island commands defined in config + for (String command : PLUGIN.getConfig().getMiscConfig().getIslandCommands()) { + command = command.replace("@p", playerName); + Sponge.getCommandManager().process(Sponge.getServer().getConsole(), command); + PLUGIN.getLogger().debug("Ran island command: {}", command); + } + // Run schematic commands + if (schematic != null) { + for (String command : schematic.getCommands()) { + command = command.replace("@p", playerName); + Sponge.getCommandManager().process(Sponge.getServer().getConsole(), command); + PLUGIN.getLogger().debug("Ran schematic command: {}", command); + } + } + }; + } +} diff --git a/src/main/java/net/mohron/skyclaims/world/RegenerateChunkTask.java b/src/main/java/net/mohron/skyclaims/world/RegenerateChunkTask.java new file mode 100644 index 00000000..b1fbb923 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/world/RegenerateChunkTask.java @@ -0,0 +1,65 @@ +package net.mohron.skyclaims.world; + +import com.flowpowered.math.vector.Vector3i; +import net.mohron.skyclaims.SkyClaims; +import net.mohron.skyclaims.SkyClaimsTimings; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.tileentity.carrier.TileEntityCarrier; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.world.BlockChangeFlags; +import org.spongepowered.api.world.Chunk; +import org.spongepowered.api.world.Location; +import org.spongepowered.api.world.World; + +public class RegenerateChunkTask implements Runnable { + + private static final SkyClaims PLUGIN = SkyClaims.getInstance(); + + private final World world; + private final Vector3i position; + private final BlockState[] blocks; + private final Location spawn; + + public RegenerateChunkTask(World world, Vector3i position, BlockState[] blocks, Location spawn) { + this.world = world; + this.position = position; + this.blocks = blocks; + this.spawn = spawn; + } + + + @Override + public void run() { + SkyClaimsTimings.CLEAR_ISLAND.startTimingIfSync(); + + final Chunk chunk = world.loadChunk(position, true).orElse(null); + + if (chunk == null) { + PLUGIN.getLogger().error("Failed to load chunk {}", position.toString()); + return; + } + + PLUGIN.getLogger().debug("Began regenerating chunk {}", position.toString()); + // Teleport any players to world spawn + chunk.getEntities(e -> e instanceof Player).forEach(e -> e.setLocationSafely(spawn)); + // Clear the contents of an tile entity with an inventory + chunk.getTileEntities(e -> e instanceof TileEntityCarrier).forEach(e -> ((TileEntityCarrier) e).getInventory().clear()); + // Set the blocks + for (int bx = chunk.getBlockMin().getX(); bx <= chunk.getBlockMax().getX(); bx++) { + for (int bz = chunk.getBlockMin().getZ(); bz <= chunk.getBlockMax().getZ(); bz++) { + for (int by = chunk.getBlockMin().getY(); by <= chunk.getBlockMax().getY(); by++) { + if (!chunk.getBlock(bx, by, bz).equals(blocks[by])) { + chunk.getLocation(bx, by, bz).setBlock(blocks[by], BlockChangeFlags.NONE); + } + } + } + } + // Remove any remaining entities. + chunk.getEntities(e -> !(e instanceof Player)).forEach(Entity::remove); + chunk.unloadChunk(); + PLUGIN.getLogger().debug("Finished regenerating chunk {}", position.toString()); + + SkyClaimsTimings.CLEAR_ISLAND.stopTimingIfSync(); + } +} diff --git a/src/main/java/net/mohron/skyclaims/world/RegenerateRegionTask.java b/src/main/java/net/mohron/skyclaims/world/RegenerateRegionTask.java index 03d5a2ca..7c72a42e 100644 --- a/src/main/java/net/mohron/skyclaims/world/RegenerateRegionTask.java +++ b/src/main/java/net/mohron/skyclaims/world/RegenerateRegionTask.java @@ -18,15 +18,22 @@ package net.mohron.skyclaims.world; +import com.flowpowered.math.vector.Vector3i; import com.google.common.base.Stopwatch; +import com.google.common.collect.Lists; +import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import net.mohron.skyclaims.SkyClaims; -import net.mohron.skyclaims.SkyClaimsTimings; +import net.mohron.skyclaims.config.type.WorldConfig; +import net.mohron.skyclaims.schematic.IslandSchematic; +import net.mohron.skyclaims.util.FlatWorldUtil; import net.mohron.skyclaims.world.region.Region; -import org.spongepowered.api.block.BlockTypes; -import org.spongepowered.api.block.tileentity.carrier.TileEntityCarrier; -import org.spongepowered.api.entity.Entity; -import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.entity.living.player.User; +import org.spongepowered.api.scheduler.SpongeExecutorService; +import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; public class RegenerateRegionTask implements Runnable { @@ -34,75 +41,85 @@ public class RegenerateRegionTask implements Runnable { private static final SkyClaims PLUGIN = SkyClaims.getInstance(); private Region region; + private World world; private Island island; - private String schematic; + private IslandSchematic schematic; private boolean commands; - public RegenerateRegionTask(Region region) { + private RegenerateRegionTask(Region region, World world) { this.region = region; + this.world = world; this.island = null; this.commands = false; } - public RegenerateRegionTask(Island island, String schematic, boolean commands) { + private RegenerateRegionTask(Island island, IslandSchematic schematic, boolean commands) { this.region = island.getRegion(); + this.world = island.getWorld(); this.island = island; this.schematic = schematic; this.commands = commands; } + public static RegenerateRegionTask regen(Island island, IslandSchematic schematic, boolean commands) { + return new RegenerateRegionTask(island, schematic, commands); + } + + public static RegenerateRegionTask clear(Region region, World world) { + return new RegenerateRegionTask(region, world); + } + @Override public void run() { - SkyClaimsTimings.CLEAR_ISLAND.startTimingIfSync(); - World world = PLUGIN.getConfig().getWorldConfig().getWorld(); + WorldConfig config = PLUGIN.getConfig().getWorldConfig(); - PLUGIN.getLogger().info("Begin clearing region ({}, {})", region.getX(), region.getZ()); + PLUGIN.getLogger().info("Begin regenerating region ({}, {})", region.getX(), region.getZ()); Stopwatch sw = Stopwatch.createStarted(); - for (int x = region.getLesserBoundary().getX(); x < region.getGreaterBoundary().getX(); x += 16) { - for (int z = region.getLesserBoundary().getZ(); z < region.getGreaterBoundary().getZ(); z += 16) { - world.getChunkAtBlock(x, 0, z).ifPresent(chunk -> { - chunk.loadChunk(false); - // Teleport any players to world spawn - chunk.getEntities(e -> e instanceof Player).forEach(e -> e.setLocationSafely(PLUGIN.getConfig().getWorldConfig().getSpawn())); - // Clear the contents of an tile entity with an inventory - chunk.getTileEntities(e -> e instanceof TileEntityCarrier).forEach(e -> ((TileEntityCarrier) e).getInventory().clear()); - for (int bx = chunk.getBlockMin().getX(); bx <= chunk.getBlockMax().getX(); bx++) { - for (int bz = chunk.getBlockMin().getZ(); bz <= chunk.getBlockMax().getZ(); bz++) { - for (int by = chunk.getBlockMin().getY(); by <= chunk.getBlockMax().getY(); by++) { - if (chunk.getBlockType(bx, by, bz) != BlockTypes.AIR) { - chunk.getLocation(bx, by, bz).setBlock(BlockTypes.AIR.getDefaultState()); - } - } - } - } - // Remove any remaining entities. - chunk.getEntities(e -> !(e instanceof Player)).forEach(Entity::remove); - chunk.unloadChunk(); - }); - } - } + String preset = schematic != null && schematic.getPreset().isPresent() + ? schematic.getPreset().get() + : config.getPresetCode(); + PLUGIN.getLogger().info("Using preset code '{}' to regenerate region.", preset); + + regenerateChunks(preset, config.getSpawn()); sw.stop(); - PLUGIN.getLogger().info(String - .format("Finished clearing region (%s, %s) in %dms.", region.getX(), region.getZ(), sw.elapsed(TimeUnit.MILLISECONDS))); + PLUGIN.getLogger().info("Finished regenerating region ({}, {}) in {}s.", region.getX(), region.getZ(), sw.elapsed(TimeUnit.SECONDS)); if (island != null) { if (commands) { - // Run reset commands - for (String command : PLUGIN.getConfig().getMiscConfig().getResetCommands()) { - PLUGIN.getGame().getCommandManager().process(PLUGIN.getGame().getServer().getConsole(), command.replace("@p", island.getOwnerName())); + for (User member : island.getMembers()) { + Sponge.getScheduler().createTaskBuilder() + .execute(IslandManager.processCommands(member.getName(), schematic)) + .submit(PLUGIN); } } - PLUGIN.getGame().getScheduler().createTaskBuilder() - .delayTicks(1) + Sponge.getScheduler().createTaskBuilder() + .delay(1, TimeUnit.SECONDS) .execute(new GenerateIslandTask(island.getOwnerUniqueId(), island, schematic)) .submit(PLUGIN); } + } - SkyClaimsTimings.CLEAR_ISLAND.stopTimingIfSync(); + private void regenerateChunks(String preset, Location spawn) { + SpongeExecutorService executor = Sponge.getScheduler().createSyncExecutor(PLUGIN); + BlockState[] blocks = FlatWorldUtil.getBlocksSafely(preset); + int progress = 0; + for (int x = region.getLesserBoundary().getX(); x < region.getGreaterBoundary().getX(); x += 16) { + List> tasks = Lists.newArrayListWithCapacity(32); + for (int z = region.getLesserBoundary().getZ(); z < region.getGreaterBoundary().getZ(); z += 16) { + Vector3i position = Sponge.getServer().getChunkLayout().forceToChunk(x, 0, z); + tasks.add(CompletableFuture.runAsync(new RegenerateChunkTask(world, position, blocks, spawn), executor)); + } + try { + CompletableFuture.allOf(tasks.toArray(new CompletableFuture[32])).join(); + PLUGIN.getLogger().info("Regenerating region {}, {} {}% complete", region.getX(), region.getZ(), Math.round(++progress / 32f * 100)); + } catch (RuntimeException e) { + PLUGIN.getLogger().error("Could not regenerate chunk.", e); + } + } } } diff --git a/src/main/java/net/mohron/skyclaims/world/gen/EndPortalFixPopulator.java b/src/main/java/net/mohron/skyclaims/world/gen/EndPortalFixPopulator.java new file mode 100644 index 00000000..189f7fa5 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/world/gen/EndPortalFixPopulator.java @@ -0,0 +1,81 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.world.gen; + +import java.util.Locale; +import java.util.Random; +import javax.annotation.Nonnull; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockTypes; +import org.spongepowered.api.text.translation.Translation; +import org.spongepowered.api.world.World; +import org.spongepowered.api.world.extent.Extent; +import org.spongepowered.api.world.gen.Populator; +import org.spongepowered.api.world.gen.PopulatorType; + +public class EndPortalFixPopulator implements Populator { + + @Nonnull + @Override + public PopulatorType getType() { + return new PopulatorType() { + @Nonnull + @Override + public String getId() { + return "endportalfix"; + } + + @Override + public String getName() { + return "End Portal Fix"; + } + + @Nonnull + @Override + public Translation getTranslation() { + return new Translation() { + @Nonnull + @Override + public String getId() { + return getType().getId(); + } + + @Nonnull + @Override + public String get(@Nonnull Locale locale) { + return getName(); + } + + @Nonnull + @Override + public String get(@Nonnull Locale locale, @Nonnull Object... args) { + return getName(); + } + }; + } + }; + } + + @Override + public void populate(@Nonnull World world, @Nonnull Extent volume, @Nonnull Random random) { + if (volume.containsBlock(0, 64, 0) && volume.getBlockType(0, 64, 0).equals(BlockTypes.AIR)) { + world.setBlock(0, 64, 0, BlockState.builder().blockType(BlockTypes.END_STONE).build()); + } + } +} diff --git a/src/main/java/net/mohron/skyclaims/world/gen/VoidWorldGeneratorModifier.java b/src/main/java/net/mohron/skyclaims/world/gen/VoidWorldGeneratorModifier.java new file mode 100644 index 00000000..46b61ca4 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/world/gen/VoidWorldGeneratorModifier.java @@ -0,0 +1,93 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ + +package net.mohron.skyclaims.world.gen; + +import net.mohron.skyclaims.SkyClaims; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.data.DataContainer; +import org.spongepowered.api.world.DimensionTypes; +import org.spongepowered.api.world.World; +import org.spongepowered.api.world.biome.BiomeGenerationSettings; +import org.spongepowered.api.world.biome.BiomeType; +import org.spongepowered.api.world.biome.BiomeTypes; +import org.spongepowered.api.world.gen.PopulatorTypes; +import org.spongepowered.api.world.gen.WorldGenerator; +import org.spongepowered.api.world.gen.WorldGeneratorModifier; +import org.spongepowered.api.world.storage.WorldProperties; + +/** + * A modifier that causes a {@link World} to generate with empty chunks. + */ +public class VoidWorldGeneratorModifier implements WorldGeneratorModifier { + + @Override + public void modifyWorldGenerator(WorldProperties world, DataContainer settings, WorldGenerator worldGenerator) { + if (world.getDimensionType().equals(DimensionTypes.NETHER)) { + modifyNether(worldGenerator); + } else if (world.getDimensionType().equals(DimensionTypes.THE_END)) { + modifyEnd(worldGenerator); + } else { + modifySurface(worldGenerator); + } + worldGenerator.setBaseGenerationPopulator((world1, buffer, biomes) -> { + }); + } + + private void modifySurface(WorldGenerator worldGenerator) { + worldGenerator.getPopulators().clear(); + worldGenerator.getGenerationPopulators().clear(); + for (BiomeType biome : Sponge.getRegistry().getAllOf(BiomeType.class)) { + BiomeGenerationSettings biomeSettings = worldGenerator.getBiomeSettings(biome); + biomeSettings.getPopulators().clear(); + biomeSettings.getGenerationPopulators().clear(); + biomeSettings.getGroundCoverLayers().clear(); + } + } + + private void modifyNether(WorldGenerator worldGenerator) { + BiomeGenerationSettings biomeSettings = worldGenerator.getBiomeSettings(BiomeTypes.HELL); + try { + worldGenerator.getGenerationPopulators().remove(Class.forName("net.minecraft.world.gen.MapGenCavesHell")); + } catch (ClassNotFoundException e) { + SkyClaims.getInstance().getLogger().error("Error modifying nether generation:", e); + } + biomeSettings.getPopulators().remove(PopulatorTypes.NETHER_FIRE); + biomeSettings.getPopulators().remove(PopulatorTypes.GLOWSTONE); + biomeSettings.getPopulators().remove(PopulatorTypes.ORE); + biomeSettings.getPopulators().remove(PopulatorTypes.MUSHROOM); + } + + private void modifyEnd(WorldGenerator worldGenerator) { + worldGenerator.getPopulators().add(new EndPortalFixPopulator()); + BiomeGenerationSettings biomeSettings = worldGenerator.getBiomeSettings(BiomeTypes.SKY); + biomeSettings.getPopulators().remove(PopulatorTypes.END_ISLAND); + biomeSettings.getPopulators().remove(PopulatorTypes.CHORUS_FLOWER); + biomeSettings.getGenerationPopulators().clear(); + } + + @Override + public String getId() { + return "skyclaims:void"; + } + + @Override + public String getName() { + return "Enhanced Void Modifier"; + } +} diff --git a/src/main/java/net/mohron/skyclaims/world/gen/package-info.java b/src/main/java/net/mohron/skyclaims/world/gen/package-info.java new file mode 100644 index 00000000..53f3c801 --- /dev/null +++ b/src/main/java/net/mohron/skyclaims/world/gen/package-info.java @@ -0,0 +1,21 @@ +/* + * SkyClaims - A Skyblock plugin made for Sponge + * Copyright (C) 2017 Mohron + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SkyClaims is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SkyClaims. If not, see . + */ +@NonnullByDefault +package net.mohron.skyclaims.world.gen; + +import org.spongepowered.api.util.annotation.NonnullByDefault; \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/world/region/Region.java b/src/main/java/net/mohron/skyclaims/world/region/Region.java index b7bba516..aec972e8 100644 --- a/src/main/java/net/mohron/skyclaims/world/region/Region.java +++ b/src/main/java/net/mohron/skyclaims/world/region/Region.java @@ -18,12 +18,15 @@ package net.mohron.skyclaims.world.region; +import lombok.EqualsAndHashCode; import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.world.Coordinate; import net.mohron.skyclaims.world.Island; +import net.mohron.skyclaims.world.IslandManager; import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; +@EqualsAndHashCode public class Region { private int x; @@ -35,11 +38,11 @@ public Region(int x, int z) { } public static boolean isOccupied(Region region) { - if (SkyClaims.islands.isEmpty()) { + if (IslandManager.ISLANDS.isEmpty()) { return false; } - for (Island island : SkyClaims.islands.values()) { + for (Island island : IslandManager.ISLANDS.values()) { if (region.equals(island.getRegion())) { return true; } @@ -76,25 +79,4 @@ public Location getCenter() { (getGreaterBoundary().getZ() + getLesserBoundary().getZ()) / 2.0 ); } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Region region = (Region) o; - - return x == region.x && z == region.z; - } - - @Override - public int hashCode() { - int result = x; - result = 31 * result + z; - return result; - } } \ No newline at end of file diff --git a/src/main/java/net/mohron/skyclaims/world/region/SpiralRegionPattern.java b/src/main/java/net/mohron/skyclaims/world/region/SpiralRegionPattern.java index 1548c212..112cfd6c 100644 --- a/src/main/java/net/mohron/skyclaims/world/region/SpiralRegionPattern.java +++ b/src/main/java/net/mohron/skyclaims/world/region/SpiralRegionPattern.java @@ -22,6 +22,7 @@ import net.mohron.skyclaims.SkyClaims; import net.mohron.skyclaims.exception.InvalidRegionException; import net.mohron.skyclaims.util.ClaimUtil; +import net.mohron.skyclaims.world.IslandManager; import org.apache.commons.lang3.text.StrBuilder; import org.spongepowered.api.text.Text; @@ -37,7 +38,7 @@ public class SpiralRegionPattern implements IRegionPattern { */ public ArrayList generateRegionPattern() { spawnRegions = PLUGIN.getConfig().getWorldConfig().getSpawnRegions(); - int islandCount = SkyClaims.islands.size(); + int islandCount = IslandManager.ISLANDS.size(); int generationSize = (int) Math.sqrt((double) islandCount + spawnRegions) + 1; StrBuilder log = new StrBuilder("Region Pattern: ["); @@ -83,7 +84,7 @@ public Region nextRegion() throws InvalidRegionException { PLUGIN.getLogger().debug("Skipping ({}, {}) for spawn", region.getX(), region.getZ()); iterator++; continue; - } else if (SkyClaims.islands.isEmpty()) { + } else if (IslandManager.ISLANDS.isEmpty()) { ClaimUtil.createSpawnClaim(spawn); } diff --git a/src/main/resources/gardenofglass.schematic b/src/main/resources/gardenofglass.schematic deleted file mode 100644 index 9536c868..00000000 Binary files a/src/main/resources/gardenofglass.schematic and /dev/null differ diff --git a/src/main/resources/skyfactory4.schematic b/src/main/resources/skyfactory4.schematic new file mode 100644 index 00000000..fde98a05 Binary files /dev/null and b/src/main/resources/skyfactory4.schematic differ diff --git a/src/main/resources/skyresources.schematic b/src/main/resources/skyresources.schematic deleted file mode 100644 index ac1d0990..00000000 Binary files a/src/main/resources/skyresources.schematic and /dev/null differ diff --git a/src/main/resources/stoneblock2.schematic b/src/main/resources/stoneblock2.schematic new file mode 100644 index 00000000..e0b25077 Binary files /dev/null and b/src/main/resources/stoneblock2.schematic differ