├── .gitignore ├── docs └── img │ ├── Banner.pdn │ ├── Banner.png │ └── PhantomWorlds.png ├── src └── main │ ├── resources │ ├── advancedSettings.yml │ ├── data.yml │ ├── settings.yml │ ├── plugin.yml │ └── messages.yml │ └── java │ └── me │ └── lokka30 │ └── phantomworlds │ ├── misc │ ├── UpdateCheckerResult.java │ ├── WorldLoadResponse.java │ ├── CompatibilityChecker.java │ └── Utils.java │ ├── commandsredux │ ├── utils │ │ └── WorldFolder.java │ ├── sub │ │ ├── TeleportCommand.java │ │ ├── SpawnCommand.java │ │ ├── DebugCommand.java │ │ ├── InfoCommand.java │ │ ├── BackupCommand.java │ │ ├── set │ │ │ ├── SetWhitelistCommand.java │ │ │ ├── SetGamemodeCommand.java │ │ │ ├── SetPortalCommand.java │ │ │ └── SetEffectsCommand.java │ │ ├── UnloadCommand.java │ │ ├── ReloadCommand.java │ │ ├── DeleteCommand.java │ │ ├── ImportCommand.java │ │ ├── CompatibilityCommand.java │ │ ├── LoadCommand.java │ │ ├── SetSpawnCommand.java │ │ ├── ListCommand.java │ │ └── CreateCommand.java │ ├── handler │ │ └── PWInvalidUsageHandler.java │ ├── params │ │ ├── SettingParameter.java │ │ ├── AliasWorldParameter.java │ │ ├── PotionEffectParameter.java │ │ ├── PortalParameter.java │ │ ├── GamemodeParameter.java │ │ └── WorldFolderParameter.java │ └── PWCommand.java │ ├── listeners │ ├── world │ │ └── WorldInitListener.java │ └── player │ │ ├── PlayerDeathListener.java │ │ ├── PlayerJoinListener.java │ │ ├── PlayerTeleportListener.java │ │ ├── PlayerPortalListener.java │ │ └── PlayerChangeWorldListener.java │ ├── scheduler │ └── BackupScheduler.java │ ├── managers │ ├── FileManager.java │ └── WorldManager.java │ ├── world │ └── PhantomWorld.java │ └── PhantomWorlds.java ├── README.md ├── PW Code Style.xml └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliJ IDEA 2 | target/ 3 | .idea 4 | *.iml 5 | 6 | # macOS 7 | ._.git 8 | .DS_Store -------------------------------------------------------------------------------- /docs/img/Banner.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArcanePlugins/PhantomWorlds/HEAD/docs/img/Banner.pdn -------------------------------------------------------------------------------- /docs/img/Banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArcanePlugins/PhantomWorlds/HEAD/docs/img/Banner.png -------------------------------------------------------------------------------- /docs/img/PhantomWorlds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArcanePlugins/PhantomWorlds/HEAD/docs/img/PhantomWorlds.png -------------------------------------------------------------------------------- /src/main/resources/advancedSettings.yml: -------------------------------------------------------------------------------- 1 | # .___ _ . . __ . _ 2 | # / \ / ___ , __ _/_ __. , _ , _ / | __. .___ | ___/ ____ 3 | # |,_-' |,---. / ` |' `. | .' \ |' `|' `. | | .' \ / \ | / | ( 4 | # | |' ` | | | | | | | | | | | /\ / | | | ' | ,' | `--. 5 | # / / | `.__/| / | \__/ `._.' / ' / |,' \,' `._.' / /\__ `___,' \___.' 6 | 7 | # Do not touch anything here unless you know what you are doing. 8 | advanced: 9 | file-version: 1 10 | generated-with: '${project.version}' -------------------------------------------------------------------------------- /src/main/resources/data.yml: -------------------------------------------------------------------------------- 1 | # .___ _ . . __ . _ 2 | # / \ / ___ , __ _/_ __. , _ , _ / | __. .___ | ___/ ____ 3 | # |,_-' |,---. / ` |' `. | .' \ |' `|' `. | | .' \ / \ | / | ( 4 | # | |' ` | | | | | | | | | | | /\ / | | | ' | ,' | `--. 5 | # / / | `.__/| / | \__/ `._.' / ' / |,' \,' `._.' / /\__ `___,' \___.' 6 | 7 | worlds-to-load: 8 | 9 | # Do not touch anything here unless you know what you are doing. 10 | advanced: 11 | file-version: 2 12 | generated-with: '${project.version}' -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/misc/UpdateCheckerResult.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.misc; 2 | 3 | /** 4 | * @author lokka30 5 | * @since v2.0.0 6 | */ 7 | public class UpdateCheckerResult { 8 | 9 | private final boolean outdated; 10 | private final String currentVersion; 11 | private final String latestVersion; 12 | 13 | public UpdateCheckerResult(boolean outdated, String currentVersion, String latestVersion) { 14 | this.outdated = outdated; 15 | this.currentVersion = currentVersion; 16 | this.latestVersion = latestVersion; 17 | } 18 | 19 | public boolean isOutdated() { 20 | return outdated; 21 | } 22 | 23 | public String getCurrentVersion() { 24 | return currentVersion; 25 | } 26 | 27 | public String getLatestVersion() { 28 | return latestVersion; 29 | } 30 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PhantomWorlds 2 | 3 | ## About 4 | 5 | * A [SpigotMC](https://www.spigotmc.org/) plugin which allows administrators to create, manage and 6 | teleport to whatever worlds they wish. 7 | 8 | ## Learn more 9 | 10 | * Click [here](https://www.spigotmc.org/resources/phantomworlds.84099/) to visit the SpigotMC 11 | resource page for PhantomWorlds, where you can learn more and download the resource if you 12 | wish. :) 13 | * Click [here](https://github.com/TheNewEconomy/PhantomWorlds/wiki) to visit the Wiki. 14 | 15 | ## Contributors 16 | 17 | * Please see the [Credits](https://github.com/TheNewEconomy/PhantomWorlds/wiki/Credits) - thank you 18 | very 19 | much to all contributors to the resource! ❤ 20 | 21 | ## License 22 | 23 | * Licensed under `GNU AGPL v3.0` ( 24 | see [LICENSE.md](https://github.com/TheNewEconomy/PhantomWorlds/blob/master/LICENSE.md)). -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/misc/WorldLoadResponse.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.misc; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * WorldLoadResponse 22 | * 23 | * @author creatorfromhell 24 | * @since 2.0.5.0 25 | */ 26 | public enum WorldLoadResponse { 27 | LOADED, 28 | NOT_FOUND, 29 | ALREADY_LOADED, 30 | INVALID, 31 | CONFIG_SKIPPED 32 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/utils/WorldFolder.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.utils; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * WorldFolder 22 | * 23 | * @author creatorfromhell 24 | * @since 2.0.5.0 25 | */ 26 | public class WorldFolder { 27 | 28 | private final String folder; 29 | 30 | public WorldFolder(String folder) { 31 | this.folder = folder; 32 | } 33 | 34 | public String getFolder() { 35 | return folder; 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/resources/settings.yml: -------------------------------------------------------------------------------- 1 | # .___ _ . . __ . _ 2 | # / \ / ___ , __ _/_ __. , _ , _ / | __. .___ | ___/ ____ 3 | # |,_-' |,---. / ` |' `. | .' \ |' `|' `. | | .' \ / \ | / | ( 4 | # | |' ` | | | | | | | | | | | /\ / | | | ' | ,' | `--. 5 | # / / | `.__/| / | \__/ `._.' / ' / |,' \,' `._.' / /\__ `___,' \___.' 6 | 7 | # Should PW run an update check from the Spigot page on startup? 8 | run-update-checker: true 9 | 10 | #Configurations relating to spawn controls. 11 | spawning: 12 | 13 | #What is the spawn world for the server? If the player hasn't played before this is the world that 14 | #they will go to. 15 | default-world: world 16 | 17 | #Should players respawn at the world spawn if they don't have a bed? 18 | respawn-world: true 19 | 20 | #Should players be sent to the world spawn each time they change worlds? 21 | change: false 22 | 23 | #Should worlds deleted be moved to an archive folder in deletedworlds? 24 | delete-archive: true 25 | 26 | #Should worlds be automatically backed up to the backup folder? 27 | backup-scheduler: true 28 | 29 | #The time, in seconds, to back up every PhantomWorlds-managed world. 30 | backup-delay: 600 31 | 32 | # Do not touch anything here unless you know what you are doing. 33 | advanced: 34 | file-version: 2 35 | generated-with: '${project.version}' -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/TeleportCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.phantomworlds.misc.Utils; 21 | import org.bukkit.World; 22 | import org.bukkit.command.CommandSender; 23 | import org.bukkit.entity.Player; 24 | 25 | /** 26 | * TeleportCommand 27 | * 28 | * @author creatorfromhell 29 | * @since 2.0.5.0 30 | */ 31 | public class TeleportCommand { 32 | 33 | public static void onCommand(final CommandSender sender, final World world, final Player player) { 34 | if(!Utils.checkWorld(sender, "command.phantomworlds.subcommands.teleport.usage", world)) { 35 | return; 36 | } 37 | Utils.teleportToWorld(sender, "teleport", "teleport", (player == null)? sender.getName() : player.getName(), world.getName()); 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/SpawnCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.phantomworlds.misc.Utils; 21 | import org.bukkit.World; 22 | import org.bukkit.command.CommandSender; 23 | import org.bukkit.entity.Player; 24 | 25 | /** 26 | * SpawnCommand 27 | * 28 | * @author creatorfromhell 29 | * @since 2.0.5.0 30 | */ 31 | public class SpawnCommand { 32 | 33 | public static void onCommand(final CommandSender sender, final World world, final Player player) { 34 | if(!(sender instanceof Player) && !Utils.checkWorld(sender, "command.phantomworlds.subcommands.spawn.usage", world)) { 35 | return; 36 | } 37 | Utils.teleportToWorld(sender, "spawn", "spawn", (player == null)? sender.getName() : player.getName(), (sender instanceof Player && world == null)? ((Player)sender).getWorld().getName() : world.getName()); 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/listeners/world/WorldInitListener.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.listeners.world; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.phantomworlds.PhantomWorlds; 21 | import org.bukkit.event.EventHandler; 22 | import org.bukkit.event.Listener; 23 | import org.bukkit.event.world.WorldInitEvent; 24 | 25 | /** 26 | * WorldInitListener 27 | * 28 | * @author creatorfromhell 29 | * @since 2.0.5.0 30 | */ 31 | public class WorldInitListener implements Listener { 32 | 33 | final PhantomWorlds plugin; 34 | 35 | public WorldInitListener(PhantomWorlds plugin) { 36 | this.plugin = plugin; 37 | } 38 | 39 | @EventHandler 40 | public void onInit(WorldInitEvent event) { 41 | if(PhantomWorlds.instance().data.getConfig().contains("worlds-to-load." + event.getWorld().getName())) { 42 | 43 | } 44 | if(!plugin.isWorldLoaded()) { 45 | plugin.loadWorlds(); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/handler/PWInvalidUsageHandler.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.handler; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import dev.rollczi.litecommands.handler.result.ResultHandlerChain; 21 | import dev.rollczi.litecommands.invalidusage.InvalidUsage; 22 | import dev.rollczi.litecommands.invalidusage.InvalidUsageHandler; 23 | import dev.rollczi.litecommands.invocation.Invocation; 24 | import dev.rollczi.litecommands.schematic.Schematic; 25 | import org.bukkit.command.CommandSender; 26 | 27 | /** 28 | * InvalidUsageHandler 29 | * 30 | * @author creatorfromhell 31 | * @since 2.0.5.0 32 | */ 33 | public class PWInvalidUsageHandler implements InvalidUsageHandler { 34 | @Override 35 | public void handle(Invocation invocation, InvalidUsage result, ResultHandlerChain chain) { 36 | 37 | final CommandSender sender = invocation.sender(); 38 | final Schematic schematic = result.getSchematic(); 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/misc/CompatibilityChecker.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.misc; 2 | 3 | import java.util.LinkedList; 4 | 5 | /** 6 | * Handles various checks that attempt to warn administrators about potential compatibility issues 7 | * with their server configuration. 8 | * 9 | * @author lokka30 10 | * @since v2.0.0 11 | */ 12 | public class CompatibilityChecker { 13 | 14 | public final LinkedList incompatibilities = new LinkedList<>(); 15 | 16 | /** 17 | * Run all PW compatibility checks. 18 | * 19 | * @since v2.0.0 20 | */ 21 | public void checkAll() { 22 | incompatibilities.clear(); 23 | 24 | //checkPlugins(); 25 | } 26 | 27 | /** 28 | * Enum storing the different types of incompatibility detections. 29 | * 30 | * @author lokka30 31 | * @since v2.0.0 32 | */ 33 | @SuppressWarnings("unused") 34 | public enum IncompatibilityType { 35 | MISSING_DEPENDENCY, // A dependency required for an operation is missing. 36 | INCOMPATIBLE_PLUGIN, // Another plugin is installed on the server which may be incompatible. 37 | SERVER_SOFTWARE, // The server software (e.g. Paper/Spigot/Tuinity) is incompatible. 38 | JAVA_VERSION // The server's version of Java is outdated. 39 | } 40 | 41 | /** 42 | * This class is used as an object to store each incompatibility that is detected. 43 | * 44 | * @author lokka30 45 | * @since v2.0.0 46 | */ 47 | public static class Incompatibility { 48 | 49 | public final IncompatibilityType type; 50 | public final String reason; 51 | public final String recommendation; 52 | 53 | public Incompatibility(IncompatibilityType type, String reason, String recommendation) { 54 | this.type = type; 55 | this.reason = reason; 56 | this.recommendation = recommendation; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/listeners/player/PlayerDeathListener.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.listeners.player; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.phantomworlds.PhantomWorlds; 21 | import me.lokka30.phantomworlds.misc.Utils; 22 | import org.bukkit.event.EventHandler; 23 | import org.bukkit.event.Listener; 24 | import org.bukkit.event.entity.PlayerDeathEvent; 25 | 26 | /** 27 | * PlayerDeathListener 28 | * 29 | * @author creatorfromhell 30 | * @since 2.0.5.0 31 | */ 32 | public class PlayerDeathListener implements Listener { 33 | 34 | final PhantomWorlds plugin; 35 | 36 | public PlayerDeathListener(PhantomWorlds plugin) { 37 | this.plugin = plugin; 38 | } 39 | 40 | @EventHandler 41 | public void onDeath(PlayerDeathEvent event) { 42 | if(!PhantomWorlds.instance().settings.getConfig().getBoolean("spawning.respawn-world", false)) { 43 | return; 44 | } 45 | 46 | if(event.getEntity().getBedSpawnLocation() == null) { 47 | 48 | event.getEntity().teleport(Utils.parseSpawn(event.getEntity().getWorld())); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/params/SettingParameter.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.params; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import dev.rollczi.litecommands.argument.Argument; 21 | import dev.rollczi.litecommands.argument.parser.ParseResult; 22 | import dev.rollczi.litecommands.argument.resolver.ArgumentResolver; 23 | import dev.rollczi.litecommands.invocation.Invocation; 24 | import dev.rollczi.litecommands.suggestion.SuggestionContext; 25 | import dev.rollczi.litecommands.suggestion.SuggestionResult; 26 | import me.lokka30.phantomworlds.PhantomWorlds; 27 | import org.bukkit.command.CommandSender; 28 | 29 | /** 30 | * SettingParameterRedux 31 | * 32 | * @author creatorfromhell 33 | * @since 2.0.5.0 34 | */ 35 | public class SettingParameter extends ArgumentResolver { 36 | @Override 37 | protected ParseResult parse(Invocation invocation, Argument context, String argument) { 38 | return ParseResult.success(argument); 39 | } 40 | 41 | @Override 42 | public SuggestionResult suggest(Invocation invocation, Argument argument, SuggestionContext context) { 43 | return SuggestionResult.of(PhantomWorlds.createTabs); 44 | } 45 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/scheduler/BackupScheduler.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.scheduler; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.phantomworlds.PhantomWorlds; 21 | import org.bukkit.Bukkit; 22 | import org.bukkit.World; 23 | import org.bukkit.scheduler.BukkitRunnable; 24 | 25 | /** 26 | * BackupScheduler 27 | * 28 | * @author creatorfromhell 29 | * @since 2.0.5.0 30 | */ 31 | public class BackupScheduler extends BukkitRunnable { 32 | /** 33 | * When an object implementing interface {@code Runnable} is used to create a thread, starting the 34 | * thread causes the object's {@code run} method to be called in that separately executing 35 | * thread. 36 | *

37 | * The general contract of the method {@code run} is that it may take any action whatsoever. 38 | * 39 | * @see Thread#run() 40 | */ 41 | @Override 42 | public void run() { 43 | PhantomWorlds.logger().info("Running World Backup Task..."); 44 | 45 | for(final World world : Bukkit.getWorlds()) { 46 | PhantomWorlds.logger().info("Backing up world '" + world.getName() + "'..."); 47 | PhantomWorlds.worldManager().backupWorld(world.getName()); 48 | } 49 | PhantomWorlds.logger().info("World Backup Task has completed!"); 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/DebugCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MessageUtils; 21 | import org.bukkit.command.CommandSender; 22 | 23 | import java.util.Locale; 24 | 25 | /** 26 | * DebugCommand 27 | * 28 | * @author creatorfromhell 29 | * @since 2.0.5.0 30 | */ 31 | public class DebugCommand { 32 | 33 | public static void onCommand(final CommandSender sender, final String level) { 34 | 35 | final String parsed = (level == null)? "nothing" : level; 36 | switch(parsed.toLowerCase(Locale.ROOT)) { 37 | case "dump": 38 | sender.sendMessage( 39 | MessageUtils.colorizeStandardCodes("&b&lPhantomWorlds: &7Incomplete.")); 40 | break; 41 | default: 42 | sender.sendMessage(MessageUtils.colorizeStandardCodes( 43 | "&b&lPhantomWorlds: &7Invalid debug method '%method%'.") 44 | .replace("%method%", parsed) 45 | ); 46 | 47 | sender.sendMessage(MessageUtils.colorizeStandardCodes( 48 | "&b&lPhantomWorlds: &7Note: Please do not run this subcommand unless you are sure you are meant to be doing so.")); 49 | break; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/listeners/player/PlayerJoinListener.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.listeners.player; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.phantomworlds.PhantomWorlds; 21 | import me.lokka30.phantomworlds.misc.Utils; 22 | import org.bukkit.Bukkit; 23 | import org.bukkit.World; 24 | import org.bukkit.event.EventHandler; 25 | import org.bukkit.event.Listener; 26 | import org.bukkit.event.player.PlayerJoinEvent; 27 | 28 | /** 29 | * PlayerLoginListener 30 | * 31 | * @author creatorfromhell 32 | * @since 2.0.5.0 33 | */ 34 | public class PlayerJoinListener implements Listener { 35 | 36 | final PhantomWorlds plugin; 37 | 38 | public PlayerJoinListener(PhantomWorlds plugin) { 39 | this.plugin = plugin; 40 | } 41 | 42 | @EventHandler 43 | public void onJoin(PlayerJoinEvent event) { 44 | final String spawnWorld = PhantomWorlds.instance().settings.getConfig().getString("spawning.default-world", "world"); 45 | final World sWorld = Bukkit.getWorld(spawnWorld); 46 | if(sWorld == null) { 47 | plugin.getLogger().warning("Configured spawn world doesn't exist! Not changing player spawn location."); 48 | return; 49 | } 50 | 51 | //We don't manage so send the player to the spawn world 52 | if(!event.getPlayer().hasPlayedBefore()) { 53 | event.getPlayer().teleport(Utils.parseSpawn(sWorld)); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/listeners/player/PlayerTeleportListener.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.listeners.player; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.phantomworlds.PhantomWorlds; 21 | import org.bukkit.event.EventHandler; 22 | import org.bukkit.event.Listener; 23 | import org.bukkit.event.player.PlayerTeleportEvent; 24 | 25 | /** 26 | * PlayerTeleportEvent 27 | * 28 | * @author creatorfromhell 29 | * @since 2.0.5.0 30 | */ 31 | public class PlayerTeleportListener implements Listener { 32 | 33 | final PhantomWorlds plugin; 34 | 35 | public PlayerTeleportListener(PhantomWorlds plugin) { 36 | this.plugin = plugin; 37 | } 38 | 39 | @EventHandler 40 | public void onPortal(PlayerTeleportEvent event) { 41 | if(event.getTo() == null || event.getTo().getWorld() == null || event.getFrom().getWorld() == null) { 42 | return; 43 | } 44 | 45 | if(event.getFrom().getWorld().getUID().equals(event.getTo().getWorld().getUID())) { 46 | return; 47 | } 48 | 49 | final String cfgPath = "worlds-to-load." + event.getTo().getWorld().getName(); 50 | 51 | if(PhantomWorlds.instance().data.getConfig().getBoolean(cfgPath + ".whitelist", false) 52 | && !event.getPlayer().hasPermission("phantomworlds.world.access." + event.getTo().getWorld().getName())) { 53 | event.setCancelled(true); 54 | return; 55 | } 56 | 57 | if(!event.getPlayer().isOp() && event.getPlayer().hasPermission("phantomworlds.world.deny." + event.getTo().getWorld().getName())) { 58 | event.setCancelled(true); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/params/AliasWorldParameter.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.params; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import dev.rollczi.litecommands.argument.Argument; 21 | import dev.rollczi.litecommands.argument.parser.ParseResult; 22 | import dev.rollczi.litecommands.argument.resolver.ArgumentResolver; 23 | import dev.rollczi.litecommands.invocation.Invocation; 24 | import dev.rollczi.litecommands.suggestion.SuggestionContext; 25 | import dev.rollczi.litecommands.suggestion.SuggestionResult; 26 | import me.lokka30.phantomworlds.PhantomWorlds; 27 | import org.bukkit.Bukkit; 28 | import org.bukkit.World; 29 | import org.bukkit.command.CommandSender; 30 | 31 | import java.util.ArrayList; 32 | import java.util.List; 33 | 34 | /** 35 | * AliasWorldParameter 36 | * 37 | * @author creatorfromhell 38 | * @since 2.0.5.0 39 | */ 40 | public class AliasWorldParameter extends ArgumentResolver { 41 | @Override 42 | protected ParseResult parse(Invocation invocation, Argument context, String argument) { 43 | return ParseResult.success(PhantomWorlds.worldManager().findWorld(argument)); 44 | } 45 | 46 | @Override 47 | public SuggestionResult suggest(Invocation invocation, Argument argument, SuggestionContext context) { 48 | 49 | final List worlds = new ArrayList<>(PhantomWorlds.worldManager().aliases.keySet()); 50 | 51 | for(final World world : Bukkit.getWorlds()) { 52 | worlds.add(world.getName()); 53 | } 54 | return SuggestionResult.of(worlds); 55 | } 56 | } -------------------------------------------------------------------------------- /PW Code Style.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/params/PotionEffectParameter.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.params; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import dev.rollczi.litecommands.argument.Argument; 21 | import dev.rollczi.litecommands.argument.parser.ParseResult; 22 | import dev.rollczi.litecommands.argument.resolver.ArgumentResolver; 23 | import dev.rollczi.litecommands.invocation.Invocation; 24 | import dev.rollczi.litecommands.suggestion.SuggestionContext; 25 | import dev.rollczi.litecommands.suggestion.SuggestionResult; 26 | import org.bukkit.command.CommandSender; 27 | import org.bukkit.potion.PotionEffectType; 28 | 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | 32 | /** 33 | * PotionEffectParameter 34 | * 35 | * @author creatorfromhell 36 | * @since 2.0.5.0 37 | */ 38 | public class PotionEffectParameter extends ArgumentResolver { 39 | 40 | private static final List POTION_EFFECTS = new ArrayList<>(); 41 | 42 | static { 43 | for(PotionEffectType value : PotionEffectType.values()) { 44 | POTION_EFFECTS.add(value.getKey() + ",duration,amplifier"); 45 | POTION_EFFECTS.add(value.getKey() + ",-1,1"); 46 | } 47 | } 48 | 49 | @Override 50 | protected ParseResult parse(Invocation invocation, Argument context, String argument) { 51 | return ParseResult.success(argument); 52 | } 53 | 54 | @Override 55 | public SuggestionResult suggest(Invocation invocation, Argument argument, SuggestionContext context) { 56 | return SuggestionResult.of(POTION_EFFECTS); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/params/PortalParameter.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.params; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import dev.rollczi.litecommands.argument.Argument; 21 | import dev.rollczi.litecommands.argument.parser.ParseResult; 22 | import dev.rollczi.litecommands.argument.resolver.ArgumentResolver; 23 | import dev.rollczi.litecommands.invocation.Invocation; 24 | import dev.rollczi.litecommands.suggestion.SuggestionContext; 25 | import dev.rollczi.litecommands.suggestion.SuggestionResult; 26 | import org.bukkit.PortalType; 27 | import org.bukkit.command.CommandSender; 28 | 29 | import java.util.HashMap; 30 | import java.util.Map; 31 | 32 | /** 33 | * PotionEffectParameter 34 | * 35 | * @author creatorfromhell 36 | * @since 2.0.5.0 37 | */ 38 | public class PortalParameter extends ArgumentResolver { 39 | 40 | private static final Map PORTAL_ARGUMENTS = new HashMap<>(); 41 | 42 | static { 43 | PORTAL_ARGUMENTS.put("end", PortalType.ENDER); 44 | PORTAL_ARGUMENTS.put("nether", PortalType.NETHER); 45 | } 46 | 47 | @Override 48 | protected ParseResult parse(Invocation invocation, Argument context, String argument) { 49 | PortalType gameMode = PORTAL_ARGUMENTS.get(argument.toLowerCase()); 50 | 51 | if (gameMode == null) { 52 | return ParseResult.failure("Invalid portal type argument!"); 53 | } 54 | 55 | return ParseResult.success(gameMode); 56 | } 57 | 58 | @Override 59 | public SuggestionResult suggest(Invocation invocation, Argument argument, SuggestionContext context) { 60 | return SuggestionResult.of(PORTAL_ARGUMENTS.keySet()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/InfoCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import org.bukkit.command.CommandSender; 23 | 24 | import java.util.Arrays; 25 | 26 | /** 27 | * InfoCommand 28 | * 29 | * @author creatorfromhell 30 | * @since 2.0.5.0 31 | */ 32 | public class InfoCommand { 33 | 34 | public static void onCommand(final CommandSender sender) { 35 | 36 | (new MultiMessage( 37 | PhantomWorlds.instance().messages.getConfig() 38 | .getStringList("command.phantomworlds.subcommands.info.success"), Arrays.asList( 39 | new MultiMessage.Placeholder("prefix", 40 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 41 | true), 42 | new MultiMessage.Placeholder("version", PhantomWorlds.instance().getDescription().getVersion(), false), 43 | new MultiMessage.Placeholder("authors", 44 | String.join(PhantomWorlds.instance().messages.getConfig().getString("common.list-delimiter", "&7, &b"), 45 | PhantomWorlds.instance().getDescription().getAuthors()), false), 46 | new MultiMessage.Placeholder("contributors", 47 | String.join(PhantomWorlds.instance().messages.getConfig().getString("common.list-delimiter", "&7, &b"), 48 | PhantomWorlds.CONTRIBUTORS), false), 49 | new MultiMessage.Placeholder("supportedServerVersions", PhantomWorlds.instance().supportedServerVersions, 50 | false) 51 | ))).send(sender); 52 | } 53 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/listeners/player/PlayerPortalListener.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.listeners.player; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.phantomworlds.PhantomWorlds; 21 | import org.bukkit.Bukkit; 22 | import org.bukkit.Location; 23 | import org.bukkit.event.EventHandler; 24 | import org.bukkit.event.Listener; 25 | import org.bukkit.event.player.PlayerPortalEvent; 26 | 27 | import static org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL; 28 | 29 | /** 30 | * EntityPortalListener 31 | * 32 | * @author creatorfromhell 33 | * @since 2.0.5.0 34 | */ 35 | public class PlayerPortalListener implements Listener { 36 | 37 | final PhantomWorlds plugin; 38 | 39 | public PlayerPortalListener(PhantomWorlds plugin) { 40 | this.plugin = plugin; 41 | } 42 | 43 | @EventHandler 44 | public void onPortal(PlayerPortalEvent event) { 45 | if(event.getFrom().getWorld() == null) return; 46 | 47 | final String cfgPath = "worlds-to-load." + event.getFrom().getWorld().getName(); 48 | 49 | final boolean end = event.getCause().equals(END_PORTAL); 50 | final String config = (end)? ".end" : ".nether"; 51 | 52 | if(PhantomWorlds.instance().data.getConfig().contains(cfgPath + config)) { 53 | final String to = PhantomWorlds.instance().data.getConfig().getString(cfgPath + config); 54 | 55 | if(to == null || Bukkit.getWorld(to) == null) { 56 | plugin.getLogger().warning("Configured portal world doesn't exist! Not changing player portal location."); 57 | return; 58 | } 59 | 60 | final Location toLocation = event.getTo(); 61 | if(toLocation == null) { 62 | plugin.getLogger().warning("Configured portal world doesn't exist! Not changing player portal location."); 63 | return; 64 | } 65 | toLocation.setWorld(Bukkit.getWorld(to)); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/params/GamemodeParameter.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.params; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import dev.rollczi.litecommands.argument.Argument; 21 | import dev.rollczi.litecommands.argument.parser.ParseResult; 22 | import dev.rollczi.litecommands.argument.resolver.ArgumentResolver; 23 | import dev.rollczi.litecommands.invocation.Invocation; 24 | import dev.rollczi.litecommands.suggestion.SuggestionContext; 25 | import dev.rollczi.litecommands.suggestion.SuggestionResult; 26 | import org.bukkit.GameMode; 27 | import org.bukkit.command.CommandSender; 28 | 29 | import java.util.HashMap; 30 | import java.util.Map; 31 | 32 | /** 33 | * PotionEffectParameter 34 | * 35 | * @author creatorfromhell 36 | * @since 2.0.5.0 37 | */ 38 | public class GamemodeParameter extends ArgumentResolver { 39 | 40 | private static final Map GAME_MODE_ARGUMENTS = new HashMap<>(); 41 | 42 | static { 43 | for (GameMode value : GameMode.values()) { 44 | GAME_MODE_ARGUMENTS.put(value.name().toLowerCase(), value); 45 | 46 | //noinspection deprecation 47 | GAME_MODE_ARGUMENTS.put(String.valueOf(value.getValue()), value); 48 | } 49 | } 50 | 51 | @Override 52 | protected ParseResult parse(Invocation invocation, Argument context, String argument) { 53 | GameMode gameMode = GAME_MODE_ARGUMENTS.get(argument.toLowerCase()); 54 | 55 | if (gameMode == null) { 56 | return ParseResult.failure("Invalid gamemode argument!"); 57 | } 58 | 59 | return ParseResult.success(gameMode); 60 | } 61 | 62 | @Override 63 | public SuggestionResult suggest(Invocation invocation, Argument argument, SuggestionContext context) { 64 | return SuggestionResult.of(GAME_MODE_ARGUMENTS.keySet()); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/BackupCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | 3 | /* 4 | * Phantom Worlds 5 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU Affero General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU Affero General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Affero General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | import me.lokka30.microlib.messaging.MultiMessage; 22 | import me.lokka30.phantomworlds.PhantomWorlds; 23 | import me.lokka30.phantomworlds.misc.Utils; 24 | import org.bukkit.World; 25 | import org.bukkit.command.CommandSender; 26 | 27 | import java.util.Arrays; 28 | 29 | /** 30 | * BackupCommand 31 | * 32 | * @author creatorfromhell 33 | * @since 2.0.5.0 34 | */ 35 | public class BackupCommand { 36 | 37 | public static void onCommand(final CommandSender sender, final World world) { 38 | 39 | if(!Utils.checkWorld(sender, "command.phantomworlds.subcommands.backup.usage", world)) { 40 | return; 41 | } 42 | 43 | if(!PhantomWorlds.worldManager().backupWorld(world.getName())) { 44 | (new MultiMessage( 45 | PhantomWorlds.instance().messages.getConfig() 46 | .getStringList("command.phantomworlds.subcommands.backup.failure"), Arrays.asList( 47 | new MultiMessage.Placeholder("prefix", 48 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 49 | true), 50 | new MultiMessage.Placeholder("world", world.getName(), false) 51 | ))).send(sender); 52 | } 53 | 54 | (new MultiMessage( 55 | PhantomWorlds.instance().messages.getConfig() 56 | .getStringList("command.phantomworlds.subcommands.backup.success"), Arrays.asList( 57 | new MultiMessage.Placeholder("prefix", 58 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 59 | true), 60 | new MultiMessage.Placeholder("world", world.getName(), false) 61 | ))).send(sender); 62 | } 63 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/params/WorldFolderParameter.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.params; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import dev.rollczi.litecommands.argument.Argument; 21 | import dev.rollczi.litecommands.argument.parser.ParseResult; 22 | import dev.rollczi.litecommands.argument.resolver.ArgumentResolver; 23 | import dev.rollczi.litecommands.invocation.Invocation; 24 | import dev.rollczi.litecommands.suggestion.SuggestionContext; 25 | import dev.rollczi.litecommands.suggestion.SuggestionResult; 26 | import me.lokka30.phantomworlds.commandsredux.utils.WorldFolder; 27 | import org.bukkit.Bukkit; 28 | import org.bukkit.command.CommandSender; 29 | 30 | import java.io.File; 31 | import java.util.ArrayList; 32 | import java.util.List; 33 | 34 | /** 35 | * WorldFolderParameter 36 | * 37 | * @author creatorfromhell 38 | * @since 2.0.5.0 39 | */ 40 | public class WorldFolderParameter extends ArgumentResolver { 41 | @Override 42 | protected ParseResult parse(Invocation invocation, Argument context, String argument) { 43 | final File directory = Bukkit.getWorldContainer(); 44 | final File worldDir = new File(directory, argument); 45 | 46 | if(!worldDir.exists()) { 47 | return ParseResult.failure("Invalid world directory specified!"); 48 | } 49 | return ParseResult.success(new WorldFolder(argument)); 50 | } 51 | 52 | @Override 53 | public SuggestionResult suggest(Invocation invocation, Argument argument, SuggestionContext context) { 54 | final List folders = new ArrayList<>(); 55 | final File directory = Bukkit.getWorldContainer(); 56 | 57 | if(directory.exists()) { 58 | for(File file : directory.listFiles()) { 59 | final File levelDat = new File(file, "level.dat"); 60 | if(file.isDirectory() && levelDat.exists()) { 61 | folders.add(file.getName()); 62 | } 63 | } 64 | } 65 | return SuggestionResult.of(folders); 66 | } 67 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/set/SetWhitelistCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub.set; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import me.lokka30.phantomworlds.misc.Utils; 23 | import org.bukkit.World; 24 | import org.bukkit.command.CommandSender; 25 | import org.bukkit.entity.Player; 26 | 27 | import java.io.IOException; 28 | import java.util.Arrays; 29 | 30 | /** 31 | * SetWhitelistCommand 32 | * 33 | * @author creatorfromhell 34 | * @since 2.0.5.0 35 | */ 36 | public class SetWhitelistCommand { 37 | 38 | public static void onCommand(final CommandSender sender, final World world, final boolean whitelist) { 39 | if(!Utils.checkWorld(sender, "command.phantomworlds.subcommands.setwhitelist.usage", world)) { 40 | return; 41 | } 42 | 43 | final World finalWorld = (world == null)? ((Player)sender).getWorld() : world; 44 | 45 | final String cfgPath = "worlds-to-load." + finalWorld.getName(); 46 | if(PhantomWorlds.instance().data.getConfig().contains(cfgPath)) { 47 | //PhantomWorlds manages this world so let's set the spawn here for better accuracy. 48 | PhantomWorlds.instance().data.getConfig().set(cfgPath + ".whitelist", whitelist); 49 | 50 | try { 51 | PhantomWorlds.instance().data.save(); 52 | } catch(final IOException ex) { 53 | throw new RuntimeException(ex); 54 | } 55 | 56 | } 57 | 58 | (new MultiMessage( 59 | PhantomWorlds.instance().messages.getConfig() 60 | .getStringList("command.phantomworlds.subcommands.setwhitelist.success"), Arrays.asList( 61 | new MultiMessage.Placeholder("prefix", 62 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 63 | true), 64 | new MultiMessage.Placeholder("world", finalWorld.getName(), false), 65 | new MultiMessage.Placeholder("whitelist", whitelist + "", false) 66 | ))).send(sender); 67 | } 68 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/UnloadCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import me.lokka30.phantomworlds.misc.Utils; 23 | import org.bukkit.World; 24 | import org.bukkit.command.CommandSender; 25 | import org.bukkit.entity.Player; 26 | 27 | import java.util.Arrays; 28 | 29 | /** 30 | * UnloadCommand 31 | * 32 | * @author creatorfromhell 33 | * @since 2.0.5.0 34 | */ 35 | public class UnloadCommand { 36 | 37 | public static void onCommand(final CommandSender sender, final World world) { 38 | if(!Utils.checkWorld(sender, "command.phantomworlds.subcommands.unload.usage", world)) { 39 | return; 40 | } 41 | 42 | if(sender instanceof Player) { 43 | 44 | if(world.getPlayers().contains((Player)sender)) { 45 | (new MultiMessage( 46 | PhantomWorlds.instance().messages.getConfig().getStringList( 47 | "command.phantomworlds.subcommands.unload.in-specified-world"), 48 | Arrays.asList( 49 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 50 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 51 | new MultiMessage.Placeholder("world", world.getName(), false) 52 | ))).send(sender); 53 | return; 54 | } 55 | } 56 | 57 | //noinspection ConstantConditions 58 | Utils.unloadWorld(world); 59 | 60 | (new MultiMessage( 61 | PhantomWorlds.instance().messages.getConfig() 62 | .getStringList("command.phantomworlds.subcommands.unload.success"), Arrays.asList( 63 | new MultiMessage.Placeholder("prefix", 64 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 65 | true), 66 | new MultiMessage.Placeholder("world", world.getName(), false) 67 | ))).send(sender); 68 | } 69 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/set/SetGamemodeCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub.set; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import me.lokka30.phantomworlds.misc.Utils; 23 | import org.bukkit.GameMode; 24 | import org.bukkit.World; 25 | import org.bukkit.command.CommandSender; 26 | import org.bukkit.entity.Player; 27 | 28 | import java.io.IOException; 29 | import java.util.Arrays; 30 | 31 | /** 32 | * SetGamemodeCommand 33 | * 34 | * @author creatorfromhell 35 | * @since 2.0.5.0 36 | */ 37 | public class SetGamemodeCommand { 38 | 39 | public static void onCommand(final CommandSender sender, final World world, final GameMode mode) { 40 | if(!Utils.checkWorld(sender, "command.phantomworlds.subcommands.setgamemode.usage", world)) { 41 | return; 42 | } 43 | 44 | final World finalWorld = (world == null)? ((Player)sender).getWorld() : world; 45 | 46 | final String cfgPath = "worlds-to-load." + finalWorld.getName(); 47 | if(PhantomWorlds.instance().data.getConfig().contains(cfgPath)) { 48 | //PhantomWorlds manages this world so let's set the spawn here for better accuracy. 49 | PhantomWorlds.instance().data.getConfig().set(cfgPath + ".gameMode", mode.name()); 50 | 51 | try { 52 | PhantomWorlds.instance().data.save(); 53 | } catch(final IOException ex) { 54 | throw new RuntimeException(ex); 55 | } 56 | 57 | } 58 | 59 | (new MultiMessage( 60 | PhantomWorlds.instance().messages.getConfig() 61 | .getStringList("command.phantomworlds.subcommands.setgamemode.success"), Arrays.asList( 62 | new MultiMessage.Placeholder("prefix", 63 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 64 | true), 65 | new MultiMessage.Placeholder("world", finalWorld.getName(), false), 66 | new MultiMessage.Placeholder("gamemode", mode.name(), false) 67 | ))).send(sender); 68 | } 69 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/ReloadCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import org.bukkit.command.CommandSender; 23 | 24 | import java.util.Collections; 25 | 26 | /** 27 | * ReloadCommand 28 | * 29 | * @author creatorfromhell 30 | * @since 2.0.5.0 31 | */ 32 | public class ReloadCommand { 33 | 34 | public static void onCommand(final CommandSender sender) { 35 | (new MultiMessage( 36 | PhantomWorlds.instance().messages.getConfig() 37 | .getStringList("command.phantomworlds.subcommands.reload.reloading-files"), 38 | Collections.singletonList( 39 | new MultiMessage.Placeholder("prefix", 40 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 41 | true) 42 | ))).send(sender); 43 | 44 | PhantomWorlds.instance().loadFiles(); 45 | 46 | (new MultiMessage( 47 | PhantomWorlds.instance().messages.getConfig() 48 | .getStringList("command.phantomworlds.subcommands.reload.reloading-worlds"), 49 | Collections.singletonList( 50 | new MultiMessage.Placeholder("prefix", 51 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 52 | true) 53 | ))).send(sender); 54 | 55 | PhantomWorlds.instance().loadWorlds(); 56 | 57 | (new MultiMessage( 58 | PhantomWorlds.instance().messages.getConfig() 59 | .getStringList("command.phantomworlds.subcommands.reload.reload-complete"), 60 | Collections.singletonList( 61 | new MultiMessage.Placeholder("prefix", 62 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 63 | true) 64 | ))).send(sender); 65 | } 66 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/set/SetPortalCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub.set; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import me.lokka30.phantomworlds.misc.Utils; 23 | import org.bukkit.PortalType; 24 | import org.bukkit.World; 25 | import org.bukkit.command.CommandSender; 26 | import org.bukkit.entity.Player; 27 | 28 | import java.io.IOException; 29 | import java.util.Arrays; 30 | 31 | /** 32 | * SetPortalCommand 33 | * 34 | * @author creatorfromhell 35 | * @since 2.0.5.0 36 | */ 37 | public class SetPortalCommand { 38 | 39 | public static void onCommand(final CommandSender sender, final World world, final PortalType portal, final World worldTo) { 40 | if(!Utils.checkWorld(sender, "command.phantomworlds.subcommands.setportal.usage", world)) { 41 | return; 42 | } 43 | 44 | final String type = (portal.equals(PortalType.ENDER))? "end" : "nether"; 45 | 46 | final World finalWorld = (world == null)? ((Player)sender).getWorld() : world; 47 | 48 | final String cfgPath = "worlds-to-load." + finalWorld.getName(); 49 | if(PhantomWorlds.instance().data.getConfig().contains(cfgPath)) { 50 | //PhantomWorlds manages this world so let's set the spawn here for better accuracy. 51 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "." + type, worldTo.getName()); 52 | 53 | try { 54 | PhantomWorlds.instance().data.save(); 55 | } catch(final IOException ex) { 56 | throw new RuntimeException(ex); 57 | } 58 | 59 | } 60 | 61 | (new MultiMessage( 62 | PhantomWorlds.instance().messages.getConfig() 63 | .getStringList("command.phantomworlds.subcommands.setportal.success"), Arrays.asList( 64 | new MultiMessage.Placeholder("prefix", 65 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 66 | true), 67 | new MultiMessage.Placeholder("world", finalWorld.getName(), false), 68 | new MultiMessage.Placeholder("portal", portal.name(), false), 69 | new MultiMessage.Placeholder("world_to", worldTo.getName(), false) 70 | ))).send(sender); 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/DeleteCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import me.lokka30.phantomworlds.misc.Utils; 23 | import org.bukkit.World; 24 | import org.bukkit.command.CommandSender; 25 | import org.bukkit.entity.Player; 26 | 27 | import java.util.Arrays; 28 | 29 | /** 30 | * DeleteCommand 31 | * 32 | * @author creatorfromhell 33 | * @since 2.0.5.0 34 | */ 35 | public class DeleteCommand { 36 | 37 | public static void onCommand(final CommandSender sender, final World world) { 38 | 39 | if(!Utils.checkWorld(sender, "command.phantomworlds.subcommands.delete.usage", world)) { 40 | return; 41 | } 42 | 43 | if(sender instanceof Player) { 44 | 45 | if(world.getPlayers().contains((Player)sender)) { 46 | (new MultiMessage( 47 | PhantomWorlds.instance().messages.getConfig().getStringList( 48 | "command.phantomworlds.subcommands.unload.in-specified-world"), 49 | Arrays.asList( 50 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 51 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 52 | new MultiMessage.Placeholder("world", world.getName(), false) 53 | ))).send(sender); 54 | return; 55 | } 56 | } 57 | 58 | if(!PhantomWorlds.worldManager().backupAndDeleteWorld(world.getName())) { 59 | (new MultiMessage( 60 | PhantomWorlds.instance().messages.getConfig() 61 | .getStringList("command.phantomworlds.subcommands.delete.failure"), Arrays.asList( 62 | new MultiMessage.Placeholder("prefix", 63 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 64 | true), 65 | new MultiMessage.Placeholder("world", world.getName(), false) 66 | ))).send(sender); 67 | } 68 | 69 | (new MultiMessage( 70 | PhantomWorlds.instance().messages.getConfig() 71 | .getStringList("command.phantomworlds.subcommands.delete.success"), Arrays.asList( 72 | new MultiMessage.Placeholder("prefix", 73 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 74 | true), 75 | new MultiMessage.Placeholder("world", world.getName(), false) 76 | ))).send(sender); 77 | } 78 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/set/SetEffectsCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub.set; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import me.lokka30.phantomworlds.misc.Utils; 23 | import org.bukkit.World; 24 | import org.bukkit.command.CommandSender; 25 | import org.bukkit.entity.Player; 26 | 27 | import java.io.IOException; 28 | import java.util.Arrays; 29 | import java.util.List; 30 | 31 | /** 32 | * SetEffectsCommand 33 | * 34 | * @author creatorfromhell 35 | * @since 2.0.5.0 36 | */ 37 | public class SetEffectsCommand { 38 | public static void onCommand(final CommandSender sender, final World world, final List effects) { 39 | if(!Utils.checkWorld(sender, "command.phantomworlds.subcommands.seteffects.usage", world)) { 40 | return; 41 | } 42 | 43 | final StringBuilder eff = new StringBuilder(); 44 | 45 | final World finalWorld = (world == null)? ((Player)sender).getWorld() : world; 46 | 47 | final String cfgPath = "worlds-to-load." + finalWorld.getName(); 48 | 49 | for(String effString : effects) { 50 | 51 | if(eff.length() > 0) { 52 | eff.append(", "); 53 | } 54 | 55 | final String[] effSettings = effString.split(","); 56 | 57 | int duration = -1; 58 | if(effSettings.length > 1) { 59 | try { 60 | duration = Integer.parseInt(effSettings[1]); 61 | } catch(NumberFormatException ignore) { 62 | } 63 | } 64 | 65 | 66 | int amplifier = 1; 67 | if(effSettings.length > 2) { 68 | try { 69 | amplifier = Integer.parseInt(effSettings[2]); 70 | } catch(NumberFormatException ignore) { 71 | } 72 | } 73 | 74 | eff.append(effSettings[0]); 75 | 76 | PhantomWorlds.instance().data.getConfig().set(cfgPath + ".effects." + effSettings[0] + ".duration", duration); 77 | PhantomWorlds.instance().data.getConfig().set(cfgPath + ".effects." + effSettings[0] + ".amplifier", amplifier); 78 | } 79 | 80 | try { 81 | PhantomWorlds.instance().data.save(); 82 | } catch(final IOException ex) { 83 | throw new RuntimeException(ex); 84 | } 85 | 86 | (new MultiMessage( 87 | PhantomWorlds.instance().messages.getConfig() 88 | .getStringList("command.phantomworlds.subcommands.seteffects.success"), Arrays.asList( 89 | new MultiMessage.Placeholder("prefix", 90 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 91 | true), 92 | new MultiMessage.Placeholder("world", finalWorld.getName(), false), 93 | new MultiMessage.Placeholder("effects", eff.toString(), false) 94 | ))).send(sender); 95 | } 96 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/ImportCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import me.lokka30.phantomworlds.world.PhantomWorld; 23 | import org.bukkit.GameMode; 24 | import org.bukkit.World; 25 | import org.bukkit.command.CommandSender; 26 | 27 | import java.util.Arrays; 28 | import java.util.Collections; 29 | 30 | /** 31 | * ImportCommand 32 | * 33 | * @author creatorfromhell 34 | * @since 2.0.5.0 35 | */ 36 | public class ImportCommand { 37 | 38 | public static void onCommand(final CommandSender sender, final World world) { 39 | 40 | if(world == null) { 41 | (new MultiMessage( 42 | PhantomWorlds.instance().messages.getConfig().getStringList( 43 | "command.phantomworlds.subcommands.import.failure-exist"), 44 | Collections.singletonList( 45 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 46 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true) 47 | ))).send(sender); 48 | return; 49 | } 50 | 51 | final String cfgPath = "worlds-to-load." + world.getName() + "."; 52 | if(PhantomWorlds.instance().data.getConfig().contains(cfgPath)) { 53 | (new MultiMessage( 54 | PhantomWorlds.instance().messages.getConfig().getStringList( 55 | "command.phantomworlds.subcommands.import.failure-already"), 56 | Arrays.asList( 57 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 58 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 59 | new MultiMessage.Placeholder("world", world.getName(), false) 60 | ))).send(sender); 61 | return; 62 | } 63 | 64 | final PhantomWorld pworld = new PhantomWorld( 65 | world.getName(), world.getEnvironment(), world.canGenerateStructures(), null, 66 | null, world.isHardcore(), world.getSeed(), world.getWorldType(), world.getAllowMonsters(), 67 | world.getAllowAnimals(), world.getKeepSpawnInMemory(), world.getPVP(), world.getDifficulty(), GameMode.SURVIVAL 68 | ); 69 | pworld.save(); 70 | (new MultiMessage( 71 | PhantomWorlds.instance().messages.getConfig().getStringList( 72 | "command.phantomworlds.subcommands.import.success"), 73 | Arrays.asList( 74 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 75 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 76 | new MultiMessage.Placeholder("world", world.getName(), false) 77 | ))).send(sender); 78 | } 79 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/CompatibilityCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import me.lokka30.phantomworlds.misc.CompatibilityChecker; 23 | import org.bukkit.command.CommandSender; 24 | 25 | import java.util.Arrays; 26 | import java.util.Collections; 27 | 28 | /** 29 | * CompatibilityCommand 30 | * 31 | * @author creatorfromhell 32 | * @since 2.0.5.0 33 | */ 34 | public class CompatibilityCommand { 35 | 36 | public static void onCommand(final CommandSender sender) { 37 | (new MultiMessage( 38 | PhantomWorlds.instance().messages.getConfig() 39 | .getStringList("command.phantomworlds.subcommands.compatibility.start"), 40 | Collections.singletonList( 41 | new MultiMessage.Placeholder("prefix", 42 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 43 | true) 44 | ))).send(sender); 45 | 46 | PhantomWorlds.instance().compatibilityChecker.checkAll(); 47 | 48 | if(PhantomWorlds.instance().compatibilityChecker.incompatibilities.isEmpty()) { 49 | (new MultiMessage( 50 | PhantomWorlds.instance().messages.getConfig() 51 | .getStringList("command.phantomworlds.subcommands.compatibility.found-none"), 52 | Collections.singletonList( 53 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 54 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true) 55 | ))).send(sender); 56 | return; 57 | } 58 | 59 | (new MultiMessage( 60 | PhantomWorlds.instance().messages.getConfig() 61 | .getStringList("command.phantomworlds.subcommands.compatibility.found"), 62 | Arrays.asList( 63 | new MultiMessage.Placeholder("prefix", 64 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 65 | true), 66 | new MultiMessage.Placeholder("amount", 67 | String.valueOf(PhantomWorlds.instance().compatibilityChecker.incompatibilities.size()), false) 68 | ))).send(sender); 69 | 70 | for(int i = 0; i < PhantomWorlds.instance().compatibilityChecker.incompatibilities.size(); i++) { 71 | CompatibilityChecker.Incompatibility incompatibility = PhantomWorlds.instance().compatibilityChecker.incompatibilities.get( 72 | i); 73 | 74 | (new MultiMessage( 75 | PhantomWorlds.instance().messages.getConfig() 76 | .getStringList("command.phantomworlds.subcommands.compatibility.entry"), 77 | Arrays.asList( 78 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 79 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 80 | new MultiMessage.Placeholder("index", String.valueOf(i + 1), false), 81 | new MultiMessage.Placeholder("type", incompatibility.type.toString(), false), 82 | new MultiMessage.Placeholder("reason", incompatibility.reason, true), 83 | new MultiMessage.Placeholder("recommendation", incompatibility.recommendation, 84 | true) 85 | ))).send(sender); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/listeners/player/PlayerChangeWorldListener.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.listeners.player; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.phantomworlds.PhantomWorlds; 21 | import org.bukkit.GameMode; 22 | import org.bukkit.Location; 23 | import org.bukkit.NamespacedKey; 24 | import org.bukkit.event.EventHandler; 25 | import org.bukkit.event.Listener; 26 | import org.bukkit.event.player.PlayerChangedWorldEvent; 27 | import org.bukkit.potion.PotionEffect; 28 | import org.bukkit.potion.PotionEffectType; 29 | 30 | /** 31 | * PlayerChangeWorldListener 32 | * 33 | * @author creatorfromhell 34 | * @since 2.0.5.0 35 | */ 36 | public class PlayerChangeWorldListener implements Listener { 37 | 38 | final PhantomWorlds plugin; 39 | 40 | public PlayerChangeWorldListener(PhantomWorlds plugin) { 41 | this.plugin = plugin; 42 | } 43 | 44 | @EventHandler 45 | public void onChangeWorld(PlayerChangedWorldEvent event) { 46 | 47 | //Check if this world has a PhantomWorlds managed spawn. If so, teleport the player there. 48 | final String spawnPath = "worlds-to-load." + event.getPlayer().getWorld().getName() + ".spawn"; 49 | if(PhantomWorlds.instance().settings.getConfig().getBoolean("spawning.change", false) && PhantomWorlds.instance().data.getConfig().contains(spawnPath)) { 50 | final double x = PhantomWorlds.instance().data.getConfig().getDouble(spawnPath + ".x", event.getPlayer().getWorld().getSpawnLocation().getX()); 51 | final double y = PhantomWorlds.instance().data.getConfig().getDouble(spawnPath + ".y", event.getPlayer().getWorld().getSpawnLocation().getY()); 52 | final double z = PhantomWorlds.instance().data.getConfig().getDouble(spawnPath + ".z", event.getPlayer().getWorld().getSpawnLocation().getZ()); 53 | final float yaw = (float)PhantomWorlds.instance().data.getConfig().getDouble(spawnPath + ".yaw", event.getPlayer().getWorld().getSpawnLocation().getYaw()); 54 | final float pitch = (float)PhantomWorlds.instance().data.getConfig().getDouble(spawnPath + ".pitch", event.getPlayer().getWorld().getSpawnLocation().getPitch()); 55 | 56 | event.getPlayer().teleport(new Location(event.getPlayer().getWorld(), x, y, z, yaw, pitch)); 57 | } 58 | 59 | final String cfgPath = "worlds-to-load." + event.getPlayer().getWorld().getName(); 60 | if(PhantomWorlds.instance().data.getConfig().contains(cfgPath + ".gameMode") && !event.getPlayer().hasPermission("phantomworlds.world.bypass.gamemode")) { 61 | final GameMode mode = GameMode.valueOf(PhantomWorlds.instance().data.getConfig().getString(cfgPath + ".gameMode")); 62 | event.getPlayer().setGameMode(mode); 63 | } 64 | 65 | final String cfgPrevPath = "worlds-to-load." + event.getFrom().getName(); 66 | if(PhantomWorlds.instance().data.getConfig().contains(cfgPrevPath + ".effects") && 67 | PhantomWorlds.instance().data.getConfig().isConfigurationSection(cfgPrevPath + ".effects")) { 68 | for(final String effName : PhantomWorlds.instance().data.getConfig().getConfigurationSection(cfgPrevPath + ".effects").getKeys(false)) { 69 | 70 | final PotionEffectType type = PotionEffectType.getByKey(NamespacedKey.fromString(effName)); 71 | if(type != null) { 72 | event.getPlayer().removePotionEffect(type); 73 | } 74 | } 75 | } 76 | 77 | if(PhantomWorlds.instance().data.getConfig().contains(cfgPath + ".effects") && 78 | PhantomWorlds.instance().data.getConfig().isConfigurationSection(cfgPath + ".effects") && !event.getPlayer().hasPermission("phantomworlds.world.bypass.effects")) { 79 | 80 | for(final String effName : PhantomWorlds.instance().data.getConfig().getConfigurationSection(cfgPath + ".effects").getKeys(false)) { 81 | final int duration = PhantomWorlds.instance().data.getConfig().getInt(cfgPath + ".effects." + effName + ".duration", -1); 82 | final int amplifier = PhantomWorlds.instance().data.getConfig().getInt(cfgPath + ".effects." + effName + ".amplifier", 1); 83 | 84 | final PotionEffectType type = PotionEffectType.getByKey(NamespacedKey.fromString(effName)); 85 | if(type != null) { 86 | final PotionEffect effect = new PotionEffect(type, duration, amplifier); 87 | event.getPlayer().addPotionEffect(effect); 88 | } 89 | } 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/LoadCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import me.lokka30.phantomworlds.commandsredux.utils.WorldFolder; 23 | import me.lokka30.phantomworlds.misc.WorldLoadResponse; 24 | import org.bukkit.command.CommandSender; 25 | 26 | import java.util.Arrays; 27 | 28 | import static me.lokka30.phantomworlds.misc.WorldLoadResponse.ALREADY_LOADED; 29 | import static me.lokka30.phantomworlds.misc.WorldLoadResponse.INVALID; 30 | import static me.lokka30.phantomworlds.misc.WorldLoadResponse.LOADED; 31 | 32 | /** 33 | * LoadCommand 34 | * 35 | * @author creatorfromhell 36 | * @since 2.0.5.0 37 | */ 38 | public class LoadCommand { 39 | 40 | public static void onCommand(final CommandSender sender, final WorldFolder world) { 41 | 42 | if(world == null || world.getFolder() == null) { 43 | (new MultiMessage( 44 | PhantomWorlds.instance().messages.getConfig() 45 | .getStringList("command.phantomworlds.usages.load"), Arrays.asList( 46 | new MultiMessage.Placeholder("prefix", 47 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 48 | true), 49 | new MultiMessage.Placeholder("label", "pw", false) 50 | ))).send(sender); 51 | return; 52 | } 53 | 54 | final WorldLoadResponse response = PhantomWorlds.worldManager().loadWorld(world.getFolder()); 55 | 56 | if(response == ALREADY_LOADED) { 57 | (new MultiMessage( 58 | PhantomWorlds.instance().messages.getConfig() 59 | .getStringList("command.phantomworlds.subcommands.create.already-loaded"), 60 | Arrays.asList( 61 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 62 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 63 | new MultiMessage.Placeholder("world", world.getFolder(), false), 64 | new MultiMessage.Placeholder("label", "pw", false) 65 | ))).send(sender); 66 | return; 67 | } 68 | 69 | if(response == INVALID) { 70 | (new MultiMessage( 71 | PhantomWorlds.instance().messages.getConfig() 72 | .getStringList("command.phantomworlds.subcommands.create.failure-folder"), 73 | Arrays.asList( 74 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 75 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 76 | new MultiMessage.Placeholder("world", world.getFolder(), false), 77 | new MultiMessage.Placeholder("label", "pw", false) 78 | ))).send(sender); 79 | return; 80 | } 81 | 82 | if(response != LOADED) { 83 | 84 | (new MultiMessage( 85 | PhantomWorlds.instance().messages.getConfig() 86 | .getStringList("command.phantomworlds.subcommands.create.failure-loading"), 87 | Arrays.asList( 88 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 89 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 90 | new MultiMessage.Placeholder("world", world.getFolder(), false), 91 | new MultiMessage.Placeholder("label", "pw", false) 92 | ))).send(sender); 93 | return; 94 | } 95 | 96 | (new MultiMessage( 97 | PhantomWorlds.instance().messages.getConfig().getStringList( 98 | "command.phantomworlds.subcommands.load.success"), 99 | Arrays.asList( 100 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 101 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 102 | new MultiMessage.Placeholder("world", world.getFolder(), false) 103 | ))).send(sender); 104 | } 105 | } -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | # .___ _ . . __ . _ 2 | # / \ / ___ , __ _/_ __. , _ , _ / | __. .___ | ___/ ____ 3 | # |,_-' |,---. / ` |' `. | .' \ |' `|' `. | | .' \ / \ | / | ( 4 | # | |' ` | | | | | | | | | | | /\ / | | | ' | ,' | `--. 5 | # / / | `.__/| / | \__/ `._.' / ' / |,' \,' `._.' / /\__ `___,' \___.' 6 | 7 | name: 'PhantomWorlds' 8 | version: '2.05' 9 | description: 'The Robust World Manager for Minecraft Servers' 10 | authors: [ 'creatorfromhell', 'lokka30' ] 11 | website: 'https://github.com/lokka30/PhantomWorlds' 12 | 13 | main: 'me.lokka30.phantomworlds.PhantomWorlds' 14 | api-version: '1.13' 15 | load: STARTUP 16 | 17 | commands: 18 | phantomworlds: 19 | description: 'Create, manage or teleport to worlds.' 20 | aliases: [ 'pw', 'world' ] 21 | usage: '/' 22 | 23 | permissions: 24 | phantomworlds.*: 25 | default: op 26 | description: 'All PhantomWorlds permissions, ideally given to administrators.' 27 | children: 28 | phantomworlds.knows-vanished-users: true 29 | phantomworlds.command.phantomworlds.*: true 30 | 31 | 32 | phantomworlds.world.bypass.gamemode: 33 | default: op 34 | description: 'Used to bypass the gamemode setting for worlds.' 35 | 36 | 37 | phantomworlds.world.bypass.effects: 38 | default: op 39 | description: 'Used to bypass the effects setting for worlds.' 40 | 41 | phantomworlds.knows-vanished-users: 42 | default: op 43 | description: 'Users with this permission will ignore the status of vanished players when using commands from PhantomWorlds, such as in tab-completion suggestions.' 44 | 45 | phantomworlds.command.phantomworlds.*: 46 | default: op 47 | description: 'Ability to run all /pw commands.' 48 | children: 49 | phantomworlds.command.phantomworlds: true 50 | phantomworlds.command.phantomworlds.backup: true 51 | phantomworlds.command.phantomworlds.compatibility: true 52 | phantomworlds.command.phantomworlds.create: true 53 | phantomworlds.command.phantomworlds.debug: true 54 | phantomworlds.command.phantomworlds.import: true 55 | phantomworlds.command.phantomworlds.info: true 56 | phantomworlds.command.phantomworlds.list: true 57 | phantomworlds.command.phantomworlds.load: true 58 | phantomworlds.command.phantomworlds.setspawn: true 59 | phantomworlds.command.phantomworlds.set.effects: true 60 | phantomworlds.command.phantomworlds.set.gamemode: true 61 | phantomworlds.command.phantomworlds.set.portal: true 62 | phantomworlds.command.phantomworlds.set.whitelist: true 63 | phantomworlds.command.phantomworlds.teleport: true 64 | phantomworlds.command.phantomworlds.spawn: true 65 | phantomworlds.command.phantomworlds.unload: true 66 | phantomworlds.command.phantomworlds.reload: true 67 | 68 | phantomworlds.command.phantomworlds: 69 | default: op 70 | description: 'Ability to run /pw' 71 | 72 | phantomworlds.command.phantomworlds.backup: 73 | default: op 74 | description: 'Ability to run /pw backup' 75 | 76 | phantomworlds.command.phantomworlds.compatibility: 77 | default: op 78 | description: 'Ability to run /pw compatibility' 79 | 80 | phantomworlds.command.phantomworlds.debug: 81 | default: op 82 | description: 'Ability to run /pw debug' 83 | 84 | phantomworlds.command.phantomworlds.create: 85 | default: op 86 | description: 'Ability to run /pw create' 87 | 88 | phantomworlds.command.phantomworlds.import: 89 | default: op 90 | description: 'Ability to run /pw import' 91 | 92 | phantomworlds.command.phantomworlds.info: 93 | default: true 94 | description: 'Ability to run /pw info' 95 | 96 | phantomworlds.command.phantomworlds.list: 97 | default: op 98 | description: 'Ability to run /pw list' 99 | 100 | phantomworlds.command.phantomworlds.load: 101 | default: op 102 | description: 'Ability to run /pw load' 103 | 104 | phantomworlds.command.phantomworlds.setspawn: 105 | default: op 106 | description: 'Ability to run /pw setspawn' 107 | 108 | phantomworlds.command.phantomworlds.set.effects: 109 | default: op 110 | description: 'Ability to run /pw set effects' 111 | 112 | phantomworlds.command.phantomworlds.set.gamemode: 113 | default: op 114 | description: 'Ability to run /pw set gamemode' 115 | 116 | phantomworlds.command.phantomworlds.set.portal: 117 | default: op 118 | description: 'Ability to run /pw set portal' 119 | 120 | phantomworlds.command.phantomworlds.set.whitelist: 121 | default: op 122 | description: 'Ability to run /pw set whitelist' 123 | 124 | phantomworlds.command.phantomworlds.teleport: 125 | default: op 126 | description: 'Ability to run /pw teleport' 127 | 128 | phantomworlds.command.phantomworlds.spawn: 129 | default: op 130 | description: 'Ability to run /pw spawn' 131 | 132 | phantomworlds.command.phantomworlds.unload: 133 | default: op 134 | description: 'Ability to run /pw unload' 135 | 136 | phantomworlds.command.phantomworlds.reload: 137 | default: op 138 | description: 'Ability to run /pw reload' 139 | -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/SetSpawnCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import me.lokka30.phantomworlds.misc.Utils; 23 | import org.bukkit.Location; 24 | import org.bukkit.World; 25 | import org.bukkit.command.CommandSender; 26 | import org.bukkit.entity.Player; 27 | 28 | import java.io.IOException; 29 | import java.util.Arrays; 30 | 31 | /** 32 | * SetSpawnCommand 33 | * 34 | * @author creatorfromhell 35 | * @since 2.0.5.0 36 | */ 37 | public class SetSpawnCommand { 38 | 39 | public static void onCommand(final CommandSender sender, Double x, Double y, Double z, World world, Float yaw, Float pitch) { 40 | 41 | if(!(sender instanceof Player)) { 42 | if(x == null || y == null || z == null || world == null) { 43 | (new MultiMessage( 44 | PhantomWorlds.instance().messages.getConfig() 45 | .getStringList("command.phantomworlds.subcommands.setspawn.usage-console"), 46 | Arrays.asList( 47 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 48 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 49 | new MultiMessage.Placeholder("label", "setspawn", false) 50 | ))).send(sender); 51 | return; 52 | } 53 | } 54 | 55 | final Player player = (Player)sender; 56 | 57 | final World finalWorld = (world == null)? ((Player)sender).getWorld() : world; 58 | final double finalX = (x == null)? ((Player)sender).getLocation().getX() : x; 59 | final double finalY = (y == null)? ((Player)sender).getLocation().getY() : y; 60 | final double finalZ = (z == null)? ((Player)sender).getLocation().getZ() : z; 61 | float finalYaw = (yaw == null)? 0 : yaw; 62 | float finalPitch = (pitch == null)? 0 : pitch; 63 | 64 | if(yaw == null && sender instanceof Player) { 65 | finalYaw = ((Player)sender).getLocation().getYaw(); 66 | } 67 | 68 | if(pitch == null && sender instanceof Player) { 69 | finalPitch = ((Player)sender).getLocation().getPitch(); 70 | } 71 | 72 | final String cfgPath = "worlds-to-load." + finalWorld.getName(); 73 | if(PhantomWorlds.instance().data.getConfig().contains(cfgPath)) { 74 | //PhantomWorlds manages this world so let's set the spawn here for better accuracy. 75 | PhantomWorlds.instance().data.getConfig().set(cfgPath + ".spawn.x", finalX); 76 | PhantomWorlds.instance().data.getConfig().set(cfgPath + ".spawn.y", finalY); 77 | PhantomWorlds.instance().data.getConfig().set(cfgPath + ".spawn.z", finalZ); 78 | PhantomWorlds.instance().data.getConfig().set(cfgPath + ".spawn.yaw", finalYaw); 79 | PhantomWorlds.instance().data.getConfig().set(cfgPath + ".spawn.pitch", finalPitch); 80 | 81 | try { 82 | PhantomWorlds.instance().data.save(); 83 | } catch(final IOException ex) { 84 | throw new RuntimeException(ex); 85 | } 86 | 87 | } else { 88 | //PhantomWorlds doesn't manage the spawn here so let Mojang deal with it. 89 | try { 90 | finalWorld.setSpawnLocation(new Location(finalWorld, finalX, finalY, finalZ, finalYaw, finalPitch)); 91 | } catch(NoSuchMethodError err) { 92 | //This is dumb that the setSpawn method in spigot uses integers... great design. 93 | finalWorld.setSpawnLocation((int)finalX, (int)finalY, (int)finalZ); 94 | // 1.8 doesn't let us set pitch and yaw ... yawn 95 | } 96 | } 97 | 98 | (new MultiMessage( 99 | PhantomWorlds.instance().messages.getConfig() 100 | .getStringList("command.phantomworlds.subcommands.setspawn.success"), Arrays.asList( 101 | new MultiMessage.Placeholder("prefix", 102 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 103 | true), 104 | new MultiMessage.Placeholder("world", finalWorld.getName(), false), 105 | new MultiMessage.Placeholder("x", String.valueOf(Utils.roundTwoDecimalPlaces(finalX)), false), 106 | new MultiMessage.Placeholder("y", String.valueOf(Utils.roundTwoDecimalPlaces(finalY)), false), 107 | new MultiMessage.Placeholder("z", String.valueOf(Utils.roundTwoDecimalPlaces(finalZ)), false), 108 | new MultiMessage.Placeholder("yaw", String.valueOf(Utils.roundTwoDecimalPlaces(finalYaw)), false), 109 | new MultiMessage.Placeholder("pitch", String.valueOf(Utils.roundTwoDecimalPlaces(finalPitch)), false) 110 | ))).send(sender); 111 | } 112 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/ListCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.messaging.MultiMessage; 21 | import me.lokka30.phantomworlds.PhantomWorlds; 22 | import org.bukkit.Bukkit; 23 | import org.bukkit.World; 24 | import org.bukkit.command.CommandSender; 25 | 26 | import java.io.File; 27 | import java.util.Arrays; 28 | import java.util.HashSet; 29 | 30 | /** 31 | * ListCommand 32 | * 33 | * @author creatorfromhell 34 | * @since 2.0.5.0 35 | */ 36 | public class ListCommand { 37 | 38 | public static void onCommand(final CommandSender sender) { 39 | (new MultiMessage( 40 | PhantomWorlds.instance().messages.getConfig() 41 | .getStringList("command.phantomworlds.subcommands.list.header-loaded"), Arrays.asList( 42 | new MultiMessage.Placeholder("prefix", 43 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 44 | true), 45 | new MultiMessage.Placeholder("amount", String.valueOf(Bukkit.getWorlds().size()), false) 46 | ))).send(sender); 47 | 48 | final HashSet loaded = new HashSet<>(); 49 | 50 | //TODO: archived, last backup times. 51 | for(final World world : Bukkit.getWorlds()) { 52 | loaded.add(world.getName()); 53 | } 54 | 55 | for(String world : loaded) { 56 | (new MultiMessage( 57 | PhantomWorlds.instance().messages.getConfig() 58 | .getStringList("command.phantomworlds.subcommands.list.entry"), Arrays.asList( 59 | new MultiMessage.Placeholder("prefix", 60 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 61 | true), 62 | new MultiMessage.Placeholder("world", world, false) 63 | ))).send(sender); 64 | } 65 | 66 | final HashSet unloaded = new HashSet<>(); 67 | final File directory = Bukkit.getWorldContainer(); 68 | 69 | for(File file : directory.listFiles()) { 70 | if(file.isDirectory() && !loaded.contains(file.getName())) { 71 | final File levelDat = new File(file, "level.dat"); 72 | if(levelDat.exists()) { 73 | unloaded.add(file.getName()); 74 | } 75 | } 76 | } 77 | 78 | (new MultiMessage( 79 | PhantomWorlds.instance().messages.getConfig() 80 | .getStringList("command.phantomworlds.subcommands.list.header-unloaded"), Arrays.asList( 81 | new MultiMessage.Placeholder("prefix", 82 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 83 | true), 84 | new MultiMessage.Placeholder("amount", String.valueOf(unloaded.size()), false) 85 | ))).send(sender); 86 | 87 | for(String world : unloaded) { 88 | (new MultiMessage( 89 | PhantomWorlds.instance().messages.getConfig() 90 | .getStringList("command.phantomworlds.subcommands.list.entry"), Arrays.asList( 91 | new MultiMessage.Placeholder("prefix", 92 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 93 | true), 94 | new MultiMessage.Placeholder("world", world, false) 95 | ))).send(sender); 96 | } 97 | 98 | final HashSet archived = new HashSet<>(); 99 | final File dir = new File(PhantomWorlds.instance().getDataFolder(), PhantomWorlds.BACKUP_FOLDER); 100 | for(File file : dir.listFiles()) { 101 | if(file.isDirectory() && !loaded.contains(file.getName()) && !unloaded.contains(file.getName())) { 102 | archived.add(file.getName()); 103 | } 104 | } 105 | 106 | (new MultiMessage( 107 | PhantomWorlds.instance().messages.getConfig() 108 | .getStringList("command.phantomworlds.subcommands.list.header-archived"), Arrays.asList( 109 | new MultiMessage.Placeholder("prefix", 110 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 111 | true), 112 | new MultiMessage.Placeholder("amount", String.valueOf(archived.size()), false) 113 | ))).send(sender); 114 | 115 | for(String world : archived) { 116 | (new MultiMessage( 117 | PhantomWorlds.instance().messages.getConfig() 118 | .getStringList("command.phantomworlds.subcommands.list.entry"), Arrays.asList( 119 | new MultiMessage.Placeholder("prefix", 120 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 121 | true), 122 | new MultiMessage.Placeholder("world", world, false) 123 | ))).send(sender); 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/managers/FileManager.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.managers; 2 | 3 | import me.lokka30.phantomworlds.PhantomWorlds; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.World; 6 | 7 | import java.io.IOException; 8 | 9 | /** 10 | * Contains methods that concern the loading of PW's data/config files. 11 | * 12 | * @author lokka30 13 | * @since v2.0.0 14 | */ 15 | public class FileManager { 16 | 17 | /** 18 | * Run all loading sequences for a file from this method. 19 | * 20 | * @param pwFile file to load 21 | * 22 | * @since v2.0.0 23 | */ 24 | public void init(final PWFile pwFile) { 25 | PhantomWorlds.logger().info("Loading file " + pwFile + "..."); 26 | 27 | try { 28 | load(pwFile); 29 | 30 | switch(pwFile) { 31 | case SETTINGS: 32 | migrate(pwFile, PhantomWorlds.instance().settings.getConfig().getInt("advanced.file-version")); 33 | break; 34 | case ADVANCED_SETTINGS: 35 | migrate(pwFile, 36 | PhantomWorlds.instance().advancedSettings.getConfig().getInt("advanced.file-version")); 37 | break; 38 | case MESSAGES: 39 | migrate(pwFile, PhantomWorlds.instance().messages.getConfig().getInt("advanced.file-version")); 40 | break; 41 | case DATA: 42 | migrate(pwFile, PhantomWorlds.instance().data.getConfig().getInt("advanced.file-version")); 43 | break; 44 | default: 45 | break; 46 | } 47 | } catch(IOException ex) { 48 | PhantomWorlds.logger().severe("Unable to init file " + pwFile + ". Stack trace:"); 49 | ex.printStackTrace(); 50 | } 51 | } 52 | 53 | /** 54 | * Run MicroLib's YamlConfigFile load sequence for each file. 55 | * 56 | * @since v2.0.0 57 | */ 58 | private void load(final PWFile pwFile) throws IOException { 59 | switch(pwFile) { 60 | case SETTINGS: 61 | PhantomWorlds.instance().settings.load(); 62 | break; 63 | case ADVANCED_SETTINGS: 64 | PhantomWorlds.instance().advancedSettings.load(); 65 | break; 66 | case MESSAGES: 67 | PhantomWorlds.instance().messages.load(); 68 | break; 69 | case DATA: 70 | PhantomWorlds.instance().data.load(); 71 | break; 72 | default: 73 | throw new IllegalStateException("Unexpected value " + pwFile); 74 | } 75 | } 76 | 77 | /** 78 | * Attempt to update outdated files automatically. 79 | * 80 | * @since v2.0.0 81 | */ 82 | private void migrate(final PWFile pwFile, final int currentVersion) { 83 | // Values of -1 indicate that it is not to be migrated 84 | if(pwFile.latestFileVersion == -1) { 85 | return; 86 | } 87 | 88 | switch(pwFile) { 89 | case SETTINGS: 90 | if(currentVersion == PWFile.SETTINGS.latestFileVersion) { 91 | return; 92 | } 93 | alertIncorrectVersion(pwFile); 94 | break; 95 | case ADVANCED_SETTINGS: 96 | if(currentVersion == PWFile.ADVANCED_SETTINGS.latestFileVersion) { 97 | return; 98 | } 99 | alertIncorrectVersion(pwFile); 100 | break; 101 | case MESSAGES: 102 | if(currentVersion == PWFile.MESSAGES.latestFileVersion) { 103 | return; 104 | } 105 | alertIncorrectVersion(pwFile); 106 | break; 107 | case DATA: 108 | if(currentVersion == PWFile.DATA.latestFileVersion) { 109 | return; 110 | } 111 | 112 | //Switch below is for future-proofing the code, in case more data versions are added. 113 | //noinspection SwitchStatementWithTooFewBranches 114 | switch(currentVersion) { 115 | case 1: 116 | PhantomWorlds.logger().info("Automatically migrating the " + pwFile 117 | + " file to the latest format (it was outdated)."); 118 | 119 | if(!PhantomWorlds.instance().data.getConfig().contains("worlds")) { 120 | return; 121 | } 122 | 123 | for(String worldName : PhantomWorlds.instance().data.getConfig().getStringList("worlds")) { 124 | if(Bukkit.getWorld(worldName) != null) { 125 | continue; // Don't add worlds that are already loaded (most likely by Bukkit). 126 | } 127 | 128 | PhantomWorlds.instance().data.getConfig() 129 | .set("worlds-to-load." + worldName + ".environment", 130 | World.Environment.NORMAL.toString()); 131 | } 132 | 133 | PhantomWorlds.instance().data.getConfig().set("worlds", null); 134 | 135 | PhantomWorlds.instance().data.getConfig().set("advanced.file-version", 2); 136 | 137 | PhantomWorlds.logger().info("File '" + pwFile + "' has been migrated."); 138 | break; 139 | default: 140 | alertIncorrectVersion(pwFile); 141 | break; 142 | } 143 | break; 144 | default: 145 | throw new IllegalStateException("Unexpected value " + pwFile); 146 | } 147 | } 148 | 149 | void alertIncorrectVersion(final PWFile pwFile) { 150 | PhantomWorlds.logger().severe("You are running the incorrect version of the " + 151 | "file '" + pwFile + "'! Please back it up and allow the plugin to generate a new file, " 152 | + "or you will most likely experience errors."); 153 | } 154 | 155 | /** 156 | * Each data/config file and their latest (current) version are mapped here. 157 | * 158 | * @author lokka30 159 | * @since v2.0.0 160 | */ 161 | public enum PWFile { 162 | SETTINGS(2), 163 | ADVANCED_SETTINGS(1), 164 | MESSAGES(8), 165 | DATA(2); 166 | 167 | public final int latestFileVersion; // If == -1: 'do not migrate me!' 168 | 169 | PWFile(final int latestFileVersion) { 170 | this.latestFileVersion = latestFileVersion; 171 | } 172 | } 173 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.lokka30 8 | PhantomWorlds 9 | 2.0.5 10 | 11 | PhantomWorlds 12 | The Robust World Manager for Minecraft Servers 13 | 14 | 15 | phantomworlds.libs 16 | 1.8 17 | UTF-8 18 | 19 | 20 | 21 | 22 | spigot-repo 23 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 24 | 25 | 26 | CodeMC 27 | https://repo.codemc.org/repository/maven-public 28 | 29 | 30 | jitpack.io 31 | https://jitpack.io 32 | 33 | 34 | litecommands-repo 35 | https://repo.panda-lang.org/releases 36 | 37 | 38 | 39 | 40 | 41 | org.spigotmc 42 | spigot-api 43 | 1.20.1-R0.1-SNAPSHOT 44 | provided 45 | 46 | 47 | com.github.lokka30 48 | MicroLib 49 | 3.2.1 50 | compile 51 | 52 | 53 | org.bstats 54 | bstats-bukkit 55 | 3.0.2 56 | compile 57 | 58 | 59 | org.jetbrains 60 | annotations 61 | 24.0.1 62 | provided 63 | 64 | 65 | dev.dejvokep 66 | boosted-yaml 67 | 1.3.2 68 | compile 69 | 70 | 71 | dev.rollczi 72 | litecommands-core 73 | 3.3.4 74 | compile 75 | 76 | 77 | dev.rollczi 78 | litecommands-bukkit 79 | 3.3.4 80 | compile 81 | 82 | 83 | 84 | 85 | clean package 86 | 87 | 88 | org.apache.maven.plugins 89 | maven-compiler-plugin 90 | 3.11.0 91 | 92 | 1.8 93 | 1.8 94 | 95 | 96 | 97 | org.apache.maven.plugins 98 | maven-shade-plugin 99 | 3.5.0 100 | 101 | 102 | 103 | me.lokka30.microlib 104 | ${phantom.relocation}.microlib 105 | 106 | 107 | org.bstats 108 | ${phantom.relocation}.bstats 109 | 110 | 111 | revxrsal 112 | ${phantom.relocation}.lamp 113 | 114 | 115 | dev.rollczi 116 | ${phantom.relocation}.lc 117 | 118 | 119 | panda.std 120 | ${phantom.relocation}.panda 121 | 122 | 123 | org.panda-lang 124 | ${phantom.relocation}.panda 125 | 126 | 127 | dev.dejvokep.boostedyaml 128 | ${phantom.relocation}.yaml 129 | 130 | 131 | true 132 | 133 | 134 | 135 | package 136 | 137 | shade 138 | 139 | 140 | false 141 | 142 | 143 | dev.dejvokep.boostedyaml:* 144 | org.bstats:* 145 | com.github.lokka30:MicroLib 146 | com.github.Revxrsal.Lamp:* 147 | dev.rollczi:* 148 | panda.std:* 149 | org.panda-lang:* 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/world/PhantomWorld.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.world; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.phantomworlds.PhantomWorlds; 21 | import org.bukkit.Difficulty; 22 | import org.bukkit.GameMode; 23 | import org.bukkit.GameRule; 24 | import org.bukkit.World; 25 | import org.bukkit.WorldCreator; 26 | import org.bukkit.WorldType; 27 | import org.jetbrains.annotations.NotNull; 28 | import org.jetbrains.annotations.Nullable; 29 | 30 | import java.io.IOException; 31 | import java.util.HashMap; 32 | import java.util.Map; 33 | 34 | /** 35 | * PhantomWorld object to make it easier to work with PW-managed worlds. 36 | * 37 | * @author lokka30 38 | * @since v2.0.0 39 | */ 40 | public class PhantomWorld { 41 | 42 | private final Map gamerules = new HashMap<>(); 43 | 44 | private final String name; 45 | private final World.Environment environment; 46 | private final boolean generateStructures; 47 | private final String generator; 48 | private final String generatorSettings; 49 | private final boolean hardcore; 50 | private final Long seed; 51 | private final WorldType worldType; 52 | private final boolean spawnMobs; 53 | private final boolean spawnAnimals; 54 | private final boolean keepSpawnInMemory; 55 | private final boolean allowPvP; 56 | private final Difficulty difficulty; 57 | 58 | private final GameMode gameMode; 59 | 60 | public PhantomWorld( 61 | @NotNull String name, 62 | @NotNull World.Environment environment, 63 | boolean generateStructures, 64 | @Nullable String generator, 65 | @Nullable String generatorSettings, 66 | boolean hardcore, 67 | @Nullable Long seed, 68 | @NotNull WorldType worldType, 69 | boolean spawnMobs, 70 | boolean spawnAnimals, 71 | boolean keepSpawnInMemory, 72 | boolean allowPvP, 73 | @NotNull Difficulty difficulty, 74 | @NotNull GameMode gameMode 75 | ) { 76 | this.name = name; 77 | this.environment = environment; 78 | this.generateStructures = generateStructures; 79 | this.generator = generator; 80 | this.generatorSettings = generatorSettings; 81 | this.hardcore = hardcore; 82 | this.seed = seed; 83 | this.worldType = worldType; 84 | this.spawnMobs = spawnMobs; 85 | this.spawnAnimals = spawnAnimals; 86 | this.keepSpawnInMemory = keepSpawnInMemory; 87 | this.allowPvP = allowPvP; 88 | this.difficulty = difficulty; 89 | this.gameMode = gameMode; 90 | } 91 | 92 | /** 93 | * Create/import the world with specified settings. 94 | * 95 | * @since v2.0.0 96 | */ 97 | public void create() { 98 | final WorldCreator worldCreator = new WorldCreator(name); 99 | 100 | worldCreator.environment(environment); 101 | worldCreator.generateStructures(generateStructures); 102 | try { 103 | worldCreator.hardcore(hardcore); 104 | } catch(NoSuchMethodError ignored) { 105 | } 106 | worldCreator.type(worldType); 107 | 108 | if(generator != null) { 109 | worldCreator.generator(generator); 110 | } 111 | if(generatorSettings != null) { 112 | worldCreator.generatorSettings(generatorSettings); 113 | } 114 | if(seed != null) { 115 | worldCreator.seed(seed); 116 | } 117 | 118 | final World world = worldCreator.createWorld(); 119 | 120 | if(world == null) { 121 | PhantomWorlds.logger().severe("Unable to create/load world '" + name + "'!"); 122 | return; 123 | } 124 | 125 | world.setSpawnFlags(spawnMobs, spawnAnimals); 126 | world.setKeepSpawnInMemory(keepSpawnInMemory); 127 | world.setPVP(allowPvP); 128 | world.setDifficulty(difficulty); 129 | 130 | for(Map.Entry entry : gamerules.entrySet()) { 131 | final GameRule rule = GameRule.getByName(entry.getKey()); 132 | if(rule == null) continue; 133 | 134 | if(rule.getType() == Boolean.class) { 135 | try { 136 | world.setGameRule((GameRule)rule, Boolean.valueOf(entry.getValue())); 137 | } catch(Exception ignore) { 138 | PhantomWorlds.logger().warning("Error setting gamerule: " + entry.getKey() + " for world: " + name + "! Invalid boolean value!"); 139 | } 140 | } else if(rule.getType() == Integer.class) { 141 | try { 142 | world.setGameRule((GameRule)rule, Integer.valueOf(entry.getValue())); 143 | } catch(Exception ignore) { 144 | PhantomWorlds.logger().warning("Error setting gamerule: " + entry.getKey() + " for world: " + name + "! Invalid integer value!"); 145 | } 146 | } 147 | } 148 | } 149 | 150 | public void save() { 151 | 152 | final String cfgPath = "worlds-to-load." + name + "."; 153 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "environment", environment.toString()); 154 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "generateStructures", generateStructures); 155 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "generator", generator); 156 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "generatorSettings", generatorSettings); 157 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "hardcore", hardcore); 158 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "seed", seed); 159 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "worldType", worldType.toString()); 160 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "spawnMobs", spawnMobs); 161 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "spawnAnimals", spawnAnimals); 162 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "keepSpawnInMemory", keepSpawnInMemory); 163 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "allowPvP", allowPvP); 164 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "difficulty", difficulty.toString()); 165 | PhantomWorlds.instance().data.getConfig().set(cfgPath + "gameMode", gameMode.name()); 166 | 167 | try { 168 | PhantomWorlds.instance().data.save(); 169 | } catch(final IOException ex) { 170 | throw new RuntimeException(ex); 171 | } 172 | } 173 | 174 | public void loadGameRules() { 175 | 176 | } 177 | 178 | public Map getGamerules() { 179 | return gamerules; 180 | } 181 | 182 | public String name() { 183 | return name; 184 | } 185 | 186 | public World.Environment environment() { 187 | return environment; 188 | } 189 | 190 | public boolean generateStructures() { 191 | return generateStructures; 192 | } 193 | 194 | public String generator() { 195 | return generator; 196 | } 197 | 198 | public String generatorSettings() { 199 | return generatorSettings; 200 | } 201 | 202 | public boolean hardcore() { 203 | return hardcore; 204 | } 205 | 206 | public Long seed() { 207 | return seed; 208 | } 209 | 210 | public WorldType worldType() { 211 | return worldType; 212 | } 213 | 214 | public boolean spawnMobs() { 215 | return spawnMobs; 216 | } 217 | 218 | public boolean spawnAnimals() { 219 | return spawnAnimals; 220 | } 221 | 222 | public boolean keepSpawnInMemory() { 223 | return keepSpawnInMemory; 224 | } 225 | 226 | public boolean allowPvP() { 227 | return allowPvP; 228 | } 229 | 230 | public Difficulty difficulty() { 231 | return difficulty; 232 | } 233 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/managers/WorldManager.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.managers; 2 | 3 | import me.lokka30.phantomworlds.PhantomWorlds; 4 | import me.lokka30.phantomworlds.misc.Utils; 5 | import me.lokka30.phantomworlds.misc.WorldLoadResponse; 6 | import me.lokka30.phantomworlds.world.PhantomWorld; 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.Difficulty; 9 | import org.bukkit.GameMode; 10 | import org.bukkit.World; 11 | import org.bukkit.WorldType; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | import java.io.File; 15 | import java.io.IOException; 16 | import java.util.HashSet; 17 | import java.util.LinkedHashMap; 18 | import java.util.Map; 19 | 20 | import static me.lokka30.phantomworlds.misc.Utils.zipFolder; 21 | 22 | /** 23 | * Contains an assortment of methods to handle world management in PW. 24 | * 25 | * @author lokka30 26 | * @since v2.0.0 27 | */ 28 | public class WorldManager { 29 | 30 | public final Map aliases = new LinkedHashMap<>(); 31 | 32 | /** 33 | * For all worlds listed in PW's data file, if they aren't already loaded by Bukkit, then tell 34 | * Bukkit to load them 35 | * 36 | * @since v2.0.0 37 | */ 38 | public void loadManagedWorlds() { 39 | PhantomWorlds.logger().info("Loading managed worlds..."); 40 | 41 | if(!PhantomWorlds.instance().data.getConfig().contains("worlds-to-load")) { 42 | return; 43 | } 44 | 45 | final HashSet worldsToDiscardFromDataFile = new HashSet<>(); 46 | 47 | //This should be outside our for each 48 | if(!Bukkit.getWorldContainer().exists()) { 49 | PhantomWorlds.logger().severe("World container doesn't exist!"); 50 | return; 51 | } 52 | 53 | final String defaultWorld = Utils.defaultWorld(); 54 | 55 | //noinspection ConstantConditions 56 | for(final String worldName : PhantomWorlds.instance().data.getConfig().getConfigurationSection("worlds-to-load").getKeys(false)) { 57 | 58 | if(worldName.equalsIgnoreCase(defaultWorld) || worldName.startsWith(defaultWorld)) { 59 | continue; 60 | } 61 | 62 | final WorldLoadResponse response = loadWorld(worldName); 63 | 64 | if(response.equals(WorldLoadResponse.INVALID)) { 65 | worldsToDiscardFromDataFile.add(worldName); 66 | } 67 | 68 | } 69 | 70 | for(String worldName : worldsToDiscardFromDataFile) { 71 | PhantomWorlds.instance().data.getConfig().set("worlds-to-load." + worldName, null); 72 | } 73 | 74 | try { 75 | PhantomWorlds.instance().data.save(); 76 | } catch(IOException ex) { 77 | PhantomWorlds.logger().severe("Unable to save data file. Stack trace:"); 78 | ex.printStackTrace(); 79 | } 80 | } 81 | 82 | /** 83 | * Used to load a world based on the name. 84 | * @param worldName The name of the world. 85 | * @return The {@link WorldLoadResponse response} from the loading process. 86 | */ 87 | public WorldLoadResponse loadWorld(final String worldName) { 88 | 89 | if(Bukkit.getWorld(worldName) != null) { 90 | return WorldLoadResponse.NOT_FOUND; 91 | } 92 | 93 | final File worldFolder = new File(Bukkit.getWorldContainer(), worldName); 94 | final File levelDat = new File(worldFolder, "level.dat"); 95 | if(!worldFolder.exists() || !levelDat.exists()) { 96 | 97 | // The world was deleted/moved by the user so it must be re-imported. PW should no longer attempt to load that world. 98 | PhantomWorlds.logger().info("Discarding world '" + worldName + "' from PhantomWorlds' " 99 | + "data file as it no longer exists on the server."); 100 | return WorldLoadResponse.INVALID; 101 | } 102 | 103 | if(PhantomWorlds.instance().data.getConfig().getBoolean("worlds-to-load." + worldName + ".skip-autoload", false)) { 104 | PhantomWorlds.logger().info("Skipping autoload of world '" + worldName + "'."); 105 | return WorldLoadResponse.CONFIG_SKIPPED; 106 | } 107 | 108 | PhantomWorlds.logger().info("Loading world '" + worldName + "'..."); 109 | getPhantomWorldFromData(worldName).create(); 110 | return WorldLoadResponse.LOADED; 111 | } 112 | 113 | /** 114 | * This creates a PhantomWorld object by scanning the data file by the specified name. Developers 115 | * are expected to make sure the specified world exists prior to retrieving it. 116 | * 117 | * @since v2.0.0 118 | */ 119 | public PhantomWorld getPhantomWorldFromData(final String name) { 120 | final String cfgPath = "worlds-to-load." + name + "."; 121 | 122 | if(PhantomWorlds.instance().data.getConfig().contains(cfgPath + "alias")) { 123 | for(final String alias : PhantomWorlds.instance().data.getConfig().getConfigurationSection(cfgPath + "alias").getKeys(false)) { 124 | aliases.put(alias, name); 125 | } 126 | } 127 | 128 | final PhantomWorld world = new PhantomWorld( 129 | name, 130 | World.Environment.valueOf( 131 | PhantomWorlds.instance().data.getConfig().getString(cfgPath + "environment", "NORMAL") 132 | ), 133 | PhantomWorlds.instance().data.getConfig().getBoolean(cfgPath + "generateStructures", true), 134 | PhantomWorlds.instance().data.getConfig().getString(cfgPath + "generator", null), 135 | PhantomWorlds.instance().data.getConfig().getString(cfgPath + "generatorSettings", null), 136 | PhantomWorlds.instance().data.getConfig().getBoolean(cfgPath + "hardcore", false), 137 | PhantomWorlds.instance().data.getConfig().getLong(cfgPath + "seed", 0), 138 | WorldType.valueOf( 139 | PhantomWorlds.instance().data.getConfig().getString(cfgPath + "worldType", "NORMAL") 140 | ), 141 | PhantomWorlds.instance().data.getConfig().getBoolean(cfgPath + "spawnMobs", true), 142 | PhantomWorlds.instance().data.getConfig().getBoolean(cfgPath + "spawnAnimals", true), 143 | PhantomWorlds.instance().data.getConfig().getBoolean(cfgPath + "keepSpawnInMemory", false), 144 | PhantomWorlds.instance().data.getConfig().getBoolean(cfgPath + "allowPvP", true), 145 | Difficulty.valueOf( 146 | PhantomWorlds.instance().data.getConfig().getString(cfgPath + "difficulty", "NORMAL") 147 | ), 148 | GameMode.valueOf( 149 | PhantomWorlds.instance().data.getConfig().getString(cfgPath + "gameMode", "SURVIVAL") 150 | ) 151 | ); 152 | 153 | if(PhantomWorlds.instance().data.getConfig().contains(cfgPath + "rules") && 154 | PhantomWorlds.instance().data.getConfig().isConfigurationSection(cfgPath + "rules")) { 155 | for(final String rule : PhantomWorlds.instance().data.getConfig().getConfigurationSection(cfgPath + "rules").getKeys(false)) { 156 | world.getGamerules().put(rule, PhantomWorlds.instance().data.getConfig().getString(cfgPath + "rules." + rule)); 157 | } 158 | } 159 | return world; 160 | } 161 | 162 | @Nullable 163 | public World findWorld(final String name) { 164 | 165 | return Bukkit.getWorld(aliases.getOrDefault(name, name)); 166 | } 167 | 168 | public boolean backupWorld(final String world) { 169 | return backupWorld(world, new File(PhantomWorlds.instance().getDataFolder(), PhantomWorlds.BACKUP_FOLDER)); 170 | } 171 | 172 | public boolean backupWorld(final String world, final File backupFolder) { 173 | final File worldFolder = new File(Bukkit.getWorldContainer(), world); 174 | 175 | try { 176 | final File worldBackupFolder = new File(backupFolder, world); 177 | worldBackupFolder.mkdir(); 178 | 179 | final String timestamp = String.valueOf(System.currentTimeMillis()); 180 | final String zipFilePath = new File(worldBackupFolder, world + "-" + timestamp + ".zip").getPath(); 181 | zipFolder(worldFolder, zipFilePath); 182 | 183 | PhantomWorlds.logger().info("World '" + world + "' backed up to: " + worldBackupFolder.getPath()); 184 | return true; 185 | } catch (IOException e) { 186 | e.printStackTrace(); 187 | return false; 188 | } 189 | } 190 | 191 | public boolean backupAndDeleteWorld(final String worldName) { 192 | final World world = Bukkit.getWorld(worldName); 193 | 194 | if(world == null) { 195 | PhantomWorlds.logger().warning("Unable to locate world '" + worldName + "'! Halting deletion."); 196 | return false; 197 | } 198 | 199 | if(PhantomWorlds.instance().settings.getConfig().getBoolean("delete-archive", true)) { 200 | if(!backupWorld(world.getName(), new File(PhantomWorlds.instance().getDataFolder(), PhantomWorlds.ARCHIVE_FOLDER))) { 201 | PhantomWorlds.logger().warning("Unable to backup world '" + worldName + "'! Halting deletion."); 202 | return false; 203 | } 204 | } 205 | 206 | if(!Bukkit.unloadWorld(world, true)) { 207 | PhantomWorlds.logger().warning("Unable to unload world '" + worldName + "'! Halting deletion."); 208 | return false; 209 | } 210 | final File worldFolder = new File(Bukkit.getWorldContainer(), worldName); 211 | if(!worldFolder.exists()) { 212 | PhantomWorlds.logger().warning("Unable to locate folder for world '" + worldName + "'! Halting deletion."); 213 | return false; 214 | } 215 | 216 | if(!Utils.deleteFolder(worldFolder)) { 217 | PhantomWorlds.logger().warning("Unable to delete world '" + worldName + "'! Halting deletion."); 218 | return false; 219 | } 220 | return true; 221 | } 222 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/PWCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import dev.rollczi.litecommands.annotations.argument.Arg; 21 | import dev.rollczi.litecommands.annotations.command.Command; 22 | import dev.rollczi.litecommands.annotations.context.Context; 23 | import dev.rollczi.litecommands.annotations.description.Description; 24 | import dev.rollczi.litecommands.annotations.execute.Execute; 25 | import dev.rollczi.litecommands.annotations.optional.OptionalArg; 26 | import dev.rollczi.litecommands.annotations.permission.Permission; 27 | import me.lokka30.phantomworlds.commandsredux.sub.BackupCommand; 28 | import me.lokka30.phantomworlds.commandsredux.sub.CompatibilityCommand; 29 | import me.lokka30.phantomworlds.commandsredux.sub.CreateCommand; 30 | import me.lokka30.phantomworlds.commandsredux.sub.DebugCommand; 31 | import me.lokka30.phantomworlds.commandsredux.sub.DeleteCommand; 32 | import me.lokka30.phantomworlds.commandsredux.sub.ImportCommand; 33 | import me.lokka30.phantomworlds.commandsredux.sub.InfoCommand; 34 | import me.lokka30.phantomworlds.commandsredux.sub.ListCommand; 35 | import me.lokka30.phantomworlds.commandsredux.sub.LoadCommand; 36 | import me.lokka30.phantomworlds.commandsredux.sub.ReloadCommand; 37 | import me.lokka30.phantomworlds.commandsredux.sub.SetSpawnCommand; 38 | import me.lokka30.phantomworlds.commandsredux.sub.SpawnCommand; 39 | import me.lokka30.phantomworlds.commandsredux.sub.TeleportCommand; 40 | import me.lokka30.phantomworlds.commandsredux.sub.UnloadCommand; 41 | import me.lokka30.phantomworlds.commandsredux.sub.set.SetEffectsCommand; 42 | import me.lokka30.phantomworlds.commandsredux.sub.set.SetGamemodeCommand; 43 | import me.lokka30.phantomworlds.commandsredux.sub.set.SetPortalCommand; 44 | import me.lokka30.phantomworlds.commandsredux.sub.set.SetWhitelistCommand; 45 | import me.lokka30.phantomworlds.commandsredux.utils.WorldFolder; 46 | import org.bukkit.GameMode; 47 | import org.bukkit.PortalType; 48 | import org.bukkit.World; 49 | import org.bukkit.command.CommandSender; 50 | import org.bukkit.entity.Player; 51 | 52 | import java.util.List; 53 | 54 | /** 55 | * PWCommand 56 | * 57 | * @author creatorfromhell 58 | * @since 2.0.5.0 59 | */ 60 | @Command(name = "phantomworlds", aliases = {"pw"}) 61 | public class PWCommand { 62 | 63 | @Execute(name = "backup", aliases = {"archive", "bu"}) 64 | @Permission("phantomworlds.command.phantomworlds.backup") 65 | @Description("command.phantomworlds.help.backup") 66 | public void backup(@Context CommandSender commandSender, @OptionalArg("world") final World world) { 67 | BackupCommand.onCommand(commandSender, world); 68 | } 69 | 70 | @Execute(name = "create", aliases = {"+", "new"}) 71 | @Permission("phantomworlds.command.phantomworlds.create") 72 | @Description("command.phantomworlds.help.create") 73 | public void create(@Context CommandSender commandSender, @Arg("world name") final String name, @Arg("environment")World.Environment environment, @Arg("world-setting") List settings) { 74 | CreateCommand.onCommand(commandSender, name, environment, settings); 75 | } 76 | 77 | @Execute(name = "compatibility") 78 | @Permission("phantomworlds.command.phantomworlds.compatibility") 79 | @Description("command.phantomworlds.help.compatibility") 80 | public void compatibility(@Context CommandSender commandSender) { 81 | CompatibilityCommand.onCommand(commandSender); 82 | } 83 | 84 | @Execute(name = "debug") 85 | @Permission("phantomworlds.command.phantomworlds.debug") 86 | @Description("command.phantomworlds.help.debug") 87 | public void debug(@Context CommandSender commandSender, @OptionalArg("level") final String level) { 88 | DebugCommand.onCommand(commandSender, level); 89 | } 90 | 91 | @Execute(name = "delete", aliases = {"-", "remove", "del"}) 92 | @Permission("phantomworlds.command.phantomworlds.delete") 93 | @Description("command.phantomworlds.help.delete") 94 | public void delete(@Context CommandSender commandSender, @OptionalArg("world") final World world) { 95 | DeleteCommand.onCommand(commandSender, world); 96 | } 97 | 98 | @Execute(name = "list", aliases = {"l"}) 99 | @Permission("phantomworlds.command.phantomworlds.list") 100 | @Description("command.phantomworlds.help.list") 101 | public void list(@Context CommandSender commandSender) { 102 | ListCommand.onCommand(commandSender); 103 | } 104 | 105 | @Execute(name = "import", aliases = {"im"}) 106 | @Permission("phantomworlds.command.phantomworlds.import") 107 | @Description("command.phantomworlds.help.import") 108 | public void importCMD(@Context CommandSender commandSender, @OptionalArg("world") final World world) { 109 | ImportCommand.onCommand(commandSender, world); 110 | } 111 | 112 | @Execute(name = "info", aliases = {"i"}) 113 | @Permission("phantomworlds.command.phantomworlds.info") 114 | @Description("command.phantomworlds.help.info") 115 | public void info(@Context CommandSender commandSender) { 116 | InfoCommand.onCommand(commandSender); 117 | } 118 | 119 | @Execute(name = "load") 120 | @Permission("phantomworlds.command.phantomworlds.load") 121 | @Description("command.phantomworlds.help.load") 122 | public void load(@Context CommandSender commandSender, @OptionalArg("world folder") final WorldFolder world) { 123 | LoadCommand.onCommand(commandSender, world); 124 | } 125 | 126 | @Execute(name = "reload", aliases = {"r"}) 127 | @Permission("phantomworlds.command.phantomworlds.reload") 128 | @Description("command.phantomworlds.help.reload") 129 | public void reload(@Context CommandSender commandSender) { 130 | ReloadCommand.onCommand(commandSender); 131 | } 132 | 133 | @Execute(name = "set effects", aliases = {"set eff"}) 134 | @Permission("phantomworlds.command.phantomworlds.set.effects") 135 | @Description("command.phantomworlds.help.seteffects") 136 | public void setEffects(@Context CommandSender commandSender, @Arg("world") World world, @Arg("potion-effects") List effects) { 137 | SetEffectsCommand.onCommand(commandSender, world, effects); 138 | } 139 | 140 | @Execute(name = "set gamemode", aliases = {"set mode"}) 141 | @Permission("phantomworlds.command.phantomworlds.set.gamemode") 142 | @Description("command.phantomworlds.help.setgamemode") 143 | public void setGamemode(@Context CommandSender commandSender, @Arg("world") World world, @Arg("mode") GameMode mode) { 144 | SetGamemodeCommand.onCommand(commandSender, world, mode); 145 | } 146 | 147 | @Execute(name = "set portal") 148 | @Permission("phantomworlds.command.phantomworlds.set.portal") 149 | @Description("command.phantomworlds.help.setportal") 150 | public void setPortal(@Context CommandSender commandSender, @Arg("world") World world, @Arg("portal type") PortalType portal, @Arg("world to") World worldTo) { 151 | SetPortalCommand.onCommand(commandSender, world, portal, worldTo); 152 | } 153 | 154 | @Execute(name = "set whitelist") 155 | @Permission("phantomworlds.command.phantomworlds.set.whitelist") 156 | @Description("command.phantomworlds.help.setwhitelist") 157 | public void setWhitelist(@Context CommandSender commandSender, @Arg("world") World world, @Arg("whitelist") boolean whitelist) { 158 | SetWhitelistCommand.onCommand(commandSender, world, whitelist); 159 | } 160 | 161 | @Execute(name = "setspawn", aliases = {"ss"}) 162 | @Permission("phantomworlds.command.phantomworlds.setspawn") 163 | @Description("command.phantomworlds.help.setspawn") 164 | public void setspawn(@Context CommandSender commandSender, @OptionalArg("x") Double x, @OptionalArg("y") Double y, @OptionalArg("z") Double z, @OptionalArg("world") World world, @OptionalArg("yaw") Float yaw, @OptionalArg("pitch") Float pitch) { 165 | SetSpawnCommand.onCommand(commandSender, x, y, z, world, yaw, pitch); 166 | } 167 | 168 | @Execute(name = "spawn") 169 | @Permission("phantomworlds.command.phantomworlds.spawn") 170 | @Description("command.phantomworlds.help.spawn") 171 | public void spawn(@Context CommandSender commandSender, @OptionalArg("world") final World world, @OptionalArg("target") final Player player) { 172 | SpawnCommand.onCommand(commandSender, world, player); 173 | } 174 | 175 | @Execute(name = "teleport", aliases = {"tp"}) 176 | @Permission("phantomworlds.command.phantomworlds.teleport") 177 | @Description("command.phantomworlds.help.tp") 178 | public void tp(@Context CommandSender commandSender, @OptionalArg("world") final World world, @OptionalArg("target") final Player player) { 179 | TeleportCommand.onCommand(commandSender, world, player); 180 | } 181 | 182 | @Execute(name = "unload", aliases = {"u"}) 183 | @Permission("phantomworlds.command.phantomworlds.unload") 184 | @Description("command.phantomworlds.help.unload") 185 | public void unload(@Context CommandSender commandSender, @OptionalArg("world") final World world) { 186 | UnloadCommand.onCommand(commandSender, world); 187 | } 188 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/PhantomWorlds.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds; 2 | 3 | import dev.rollczi.litecommands.LiteCommands; 4 | import dev.rollczi.litecommands.argument.ArgumentKey; 5 | import dev.rollczi.litecommands.bukkit.LiteBukkitFactory; 6 | import me.lokka30.microlib.files.YamlConfigFile; 7 | import me.lokka30.microlib.maths.QuickTimer; 8 | import me.lokka30.microlib.other.UpdateChecker; 9 | import me.lokka30.phantomworlds.commandsredux.PWCommand; 10 | import me.lokka30.phantomworlds.commandsredux.params.AliasWorldParameter; 11 | import me.lokka30.phantomworlds.commandsredux.params.GamemodeParameter; 12 | import me.lokka30.phantomworlds.commandsredux.params.PortalParameter; 13 | import me.lokka30.phantomworlds.commandsredux.params.PotionEffectParameter; 14 | import me.lokka30.phantomworlds.commandsredux.params.SettingParameter; 15 | import me.lokka30.phantomworlds.commandsredux.params.WorldFolderParameter; 16 | import me.lokka30.phantomworlds.commandsredux.utils.WorldFolder; 17 | import me.lokka30.phantomworlds.listeners.player.PlayerChangeWorldListener; 18 | import me.lokka30.phantomworlds.listeners.player.PlayerDeathListener; 19 | import me.lokka30.phantomworlds.listeners.player.PlayerJoinListener; 20 | import me.lokka30.phantomworlds.listeners.player.PlayerPortalListener; 21 | import me.lokka30.phantomworlds.listeners.player.PlayerTeleportListener; 22 | import me.lokka30.phantomworlds.listeners.world.WorldInitListener; 23 | import me.lokka30.phantomworlds.managers.FileManager; 24 | import me.lokka30.phantomworlds.managers.WorldManager; 25 | import me.lokka30.phantomworlds.misc.CompatibilityChecker; 26 | import me.lokka30.phantomworlds.misc.UpdateCheckerResult; 27 | import me.lokka30.phantomworlds.scheduler.BackupScheduler; 28 | import org.bstats.bukkit.Metrics; 29 | import org.bukkit.GameMode; 30 | import org.bukkit.PortalType; 31 | import org.bukkit.World; 32 | import org.bukkit.WorldType; 33 | import org.bukkit.plugin.java.JavaPlugin; 34 | import org.bukkit.scheduler.BukkitTask; 35 | 36 | import java.io.File; 37 | import java.util.ArrayList; 38 | import java.util.LinkedList; 39 | import java.util.List; 40 | import java.util.concurrent.TimeUnit; 41 | import java.util.logging.Logger; 42 | 43 | /** 44 | * This is the main class of the PhantomWorlds plugin. 45 | * 46 | * @author lokka30 47 | * @since v2.0.0 48 | */ 49 | public class PhantomWorlds extends JavaPlugin { 50 | 51 | public static final List createTabs = new ArrayList<>(); 52 | 53 | /* 54 | *TODO: 55 | * - Translate backslash character in world names as a space so world names with a space can be used in the plugin 56 | * - Vanish compatibility 57 | * - don't send 'by' messages unless the sender is not a player / target can see the (player) sender 58 | * - add vanish compatibility to 'teleport' subcommand 59 | * - add ability to toggle vanish compatibility 60 | * - log in console (LogLevel:INFO) when a command is prevented due to a target player seemingly being vanished to the command sender. 61 | */ 62 | 63 | 64 | private static PhantomWorlds instance; 65 | 66 | protected LiteCommands command; 67 | 68 | private BukkitTask backupService = null; 69 | 70 | /** 71 | * If you have contributed code to the plugin, add your name to the end of this list! :) 72 | */ 73 | public static final String[] CONTRIBUTORS = new String[]{"madison-allen"}; 74 | 75 | public static final List COMMAND_HELP = new LinkedList<>(); 76 | 77 | public static final String BACKUP_FOLDER = "backups"; 78 | public static final String ARCHIVE_FOLDER = "archives"; 79 | 80 | /** 81 | * This is reported in the 'pw info' command to inform the command sender of what MC versions that 82 | * this version of PW is designed to run on, and is therefore supported. 83 | */ 84 | public final String supportedServerVersions = "1.7.x and newer"; 85 | 86 | /** 87 | * Frequently used vars. 88 | */ 89 | public final FileManager fileManager = new FileManager(); 90 | public final WorldManager worldManager = new WorldManager(); 91 | 92 | /** 93 | * Miscellaneous vars. 94 | */ 95 | public final CompatibilityChecker compatibilityChecker = new CompatibilityChecker(); 96 | public UpdateCheckerResult updateCheckerResult = null; 97 | 98 | /** 99 | * Data/configuration files. 100 | */ 101 | public final YamlConfigFile settings = new YamlConfigFile(this, 102 | new File(getDataFolder(), "settings.yml")); 103 | public final YamlConfigFile advancedSettings = new YamlConfigFile(this, 104 | new File(getDataFolder(), "advancedSettings.yml")); 105 | public final YamlConfigFile messages = new YamlConfigFile(this, 106 | new File(getDataFolder(), "messages.yml")); 107 | public final YamlConfigFile data = new YamlConfigFile(this, 108 | new File(getDataFolder(), "data.yml")); 109 | 110 | /* 111 | Used to check if world are loaded 112 | */ 113 | private boolean isWorldLoaded = false; 114 | 115 | /** 116 | * This method is called by Bukkit when it loads PhantomWorlds. 117 | * 118 | * @since v2.0.0 119 | */ 120 | @Override 121 | public void onEnable() { 122 | 123 | instance = this; 124 | 125 | createTabs.addAll(generateCreateSuggestions()); 126 | 127 | QuickTimer timer = new QuickTimer(TimeUnit.MILLISECONDS); 128 | checkCompatibility(); 129 | loadFiles(); 130 | 131 | registerCommands(); 132 | registerListeners(); 133 | miscStartupProcedures(); 134 | 135 | if(settings.getConfig().getBoolean("backup-scheduler", true)) { 136 | getLogger().info("Starting up Backup scheduler..."); 137 | backupService = new BackupScheduler().runTaskTimerAsynchronously(this, settings.getConfig().getInt("backup-delay") * 20L, settings.getConfig().getInt("backup-delay") * 20L); 138 | } 139 | 140 | getLogger().info("Start-up complete (took " + timer.getDuration() + "ms)"); 141 | } 142 | 143 | public boolean isWorldLoaded() { 144 | return isWorldLoaded; 145 | } 146 | 147 | /** 148 | * This method is called by Bukkit when it disables PhantomWorlds. 149 | * 150 | * @since v2.0.0 151 | */ 152 | @Override 153 | public void onDisable() { 154 | final QuickTimer timer = new QuickTimer(TimeUnit.MILLISECONDS); 155 | 156 | if(backupService != null) { 157 | getLogger().info("Shutting down backup scheduler..."); 158 | backupService.cancel(); 159 | } 160 | 161 | getLogger().info("Shut-down complete (took " + timer.getDuration() + "ms)"); 162 | } 163 | 164 | /** 165 | * Run the compatibility checkker. Reports in the console if it finds any possible issues. 166 | * 167 | * @since v2.0.0 168 | */ 169 | void checkCompatibility() { 170 | getLogger().info("Checking compatibility with server..."); 171 | 172 | compatibilityChecker.checkAll(); 173 | 174 | if(compatibilityChecker.incompatibilities.isEmpty()) { 175 | return; 176 | } 177 | 178 | for(int i = 0; i < compatibilityChecker.incompatibilities.size(); i++) { 179 | CompatibilityChecker.Incompatibility incompatibility = compatibilityChecker.incompatibilities.get( 180 | i); 181 | getLogger().warning( 182 | "Incompatibility #" + (i + 1) + " (Type: " + incompatibility.type + "):"); 183 | getLogger().info(" -> Reason: " + incompatibility.reason); 184 | getLogger().info(" -> Recommendation: " + incompatibility.recommendation); 185 | } 186 | } 187 | 188 | /** 189 | * (Re)load all data/configuration files. Creates them if they don't exist. Applies version 190 | * checking where suitable. 191 | * 192 | * @since v2.0.0 193 | */ 194 | public void loadFiles() { 195 | getLogger().info("Checking for backup directory..."); 196 | 197 | final File backup = new File(getDataFolder(), BACKUP_FOLDER); 198 | if(!backup.exists()) { 199 | backup.mkdirs(); 200 | } 201 | 202 | getLogger().info("Loading files..."); 203 | 204 | for(FileManager.PWFile pwFile : FileManager.PWFile.values()) { 205 | fileManager.init(pwFile); 206 | } 207 | } 208 | 209 | /** 210 | * Checks on the worlds that are created through PhantomWorlds. If they aren't already loaded, PW 211 | * loads them. 212 | * 213 | * @since v2.0.0 214 | */ 215 | public void loadWorlds() { 216 | getLogger().info("Loading worlds..."); 217 | worldManager.loadManagedWorlds(); 218 | isWorldLoaded = true; 219 | } 220 | 221 | /** 222 | * Registers the commands for the plugin. In this case, only one command is registered (with an 223 | * array of sub-commands of course). 224 | * 225 | * @since v2.0.0 226 | */ 227 | void registerCommands() { 228 | getLogger().info("Registering commands..."); 229 | 230 | this.command = LiteBukkitFactory.builder() 231 | .commands(new PWCommand()) 232 | .settings(settings -> settings 233 | .fallbackPrefix("phantomworlds") 234 | .nativePermissions(false) 235 | ) 236 | .argument(GameMode.class, new GamemodeParameter()) 237 | .argument(PortalType.class, new PortalParameter()) 238 | .argument(String.class, ArgumentKey.of("world-setting"), new SettingParameter()) 239 | .argument(String.class, ArgumentKey.of("potion-effects"), new PotionEffectParameter()) 240 | .argument(World.class, new AliasWorldParameter()) 241 | .argument(WorldFolder.class, new WorldFolderParameter()).build(); 242 | } 243 | 244 | /** 245 | * Registers the listeners for the plugin. These classes run code when Events happen on the 246 | * server, e.g. 'player joins server' or 'player changes world'. 247 | * 248 | * @since v2.0.0 249 | */ 250 | void registerListeners() { 251 | getLogger().info("Registering listeners..."); 252 | getServer().getPluginManager().registerEvents(new PlayerChangeWorldListener(this), this); 253 | getServer().getPluginManager().registerEvents(new PlayerDeathListener(this), this); 254 | getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this); 255 | getServer().getPluginManager().registerEvents(new PlayerPortalListener(this), this); 256 | getServer().getPluginManager().registerEvents(new PlayerTeleportListener(this), this); 257 | 258 | getServer().getPluginManager().registerEvents(new WorldInitListener(this), this); 259 | } 260 | 261 | /** 262 | * Miscellaneous startup procedures. 263 | * 264 | * @since v2.0.0 265 | */ 266 | void miscStartupProcedures() { 267 | getLogger().info("Running misc startup procedures..."); 268 | 269 | /* bStats Metrics */ 270 | new Metrics(this, 8916); 271 | 272 | /* Update Checker */ 273 | if(settings.getConfig().getBoolean("run-update-checker", true)) { 274 | try { 275 | final UpdateChecker updateChecker = new UpdateChecker(this, 84017); 276 | updateChecker.getLatestVersion(latestVersion->{ 277 | updateCheckerResult = new UpdateCheckerResult( 278 | !latestVersion.equals(updateChecker.getCurrentVersion()), 279 | updateChecker.getCurrentVersion(), 280 | latestVersion 281 | ); 282 | 283 | if(updateCheckerResult.isOutdated()) { 284 | if(!messages.getConfig() 285 | .getBoolean("update-checker.console.enabled", true)) { 286 | return; 287 | } 288 | 289 | messages.getConfig().getStringList("update-checker.console.text") 290 | .forEach(message->getLogger().info(message 291 | .replace("%currentVersion%", 292 | updateCheckerResult.getCurrentVersion()) 293 | .replace("%latestVersion%", updateCheckerResult.getLatestVersion()) 294 | )); 295 | } 296 | }); 297 | } catch(Exception ex) { 298 | getLogger().warning("Unable to check for updates - check your internet connection: " 299 | + ex.getMessage()); 300 | } 301 | } 302 | } 303 | 304 | public static PhantomWorlds instance() { 305 | return instance; 306 | } 307 | 308 | public static Logger logger() { 309 | return instance.getLogger(); 310 | } 311 | 312 | public static WorldManager worldManager() { 313 | return instance.worldManager; 314 | } 315 | 316 | private ArrayList generateCreateSuggestions() { 317 | final ArrayList suggestions = new ArrayList<>(); 318 | 319 | suggestions.addAll(addTrueFalseValues("generatestructures")); 320 | suggestions.addAll(addTrueFalseValues("genstructures")); 321 | suggestions.addAll(addTrueFalseValues("structures")); 322 | suggestions.addAll(addTrueFalseValues("spawnmobs")); 323 | suggestions.addAll(addTrueFalseValues("mobs")); 324 | suggestions.addAll(addTrueFalseValues("spawnanimals")); 325 | suggestions.addAll(addTrueFalseValues("animals")); 326 | suggestions.addAll(addTrueFalseValues("keepspawninmemory")); 327 | suggestions.addAll(addTrueFalseValues("spawninmemory")); 328 | suggestions.addAll(addTrueFalseValues("hardcore")); 329 | suggestions.addAll(addTrueFalseValues("allowpvp")); 330 | suggestions.addAll(addTrueFalseValues("pvp")); 331 | suggestions.addAll(addTrueFalseValues("difficulty")); 332 | suggestions.addAll(addTrueFalseValues("diff")); 333 | 334 | suggestions.add("generator:"); 335 | suggestions.add("gen:"); 336 | 337 | suggestions.add("generatorsettings:"); 338 | suggestions.add("gensettings:"); 339 | 340 | suggestions.add("gamemode:ADVENTURE"); 341 | suggestions.add("gamemode:CREATIVE"); 342 | suggestions.add("gamemode:HARDCORE"); 343 | suggestions.add("gamemode:SURVIVAL"); 344 | 345 | suggestions.add("seed:"); 346 | 347 | for(WorldType worldType : WorldType.values()) { 348 | suggestions.add("type:" + worldType.toString()); 349 | } 350 | 351 | return suggestions; 352 | } 353 | 354 | private ArrayList addTrueFalseValues(String option) { 355 | final ArrayList list = new ArrayList<>(); 356 | option = option + ":"; 357 | 358 | list.add(option + "true"); 359 | list.add(option + "false"); 360 | 361 | return list; 362 | } 363 | } -------------------------------------------------------------------------------- /src/main/resources/messages.yml: -------------------------------------------------------------------------------- 1 | # .___ _ . . __ . _ 2 | # / \ / ___ , __ _/_ __. , _ , _ / | __. .___ | ___/ ____ 3 | # |,_-' |,---. / ` |' `. | .' \ |' `|' `. | | .' \ / \ | / | ( 4 | # | |' ` | | | | | | | | | | | /\ / | | | ' | ,' | `--. 5 | # / / | `.__/| / | \__/ `._.' / ' / |,' \,' `._.' / /\__ `___,' \___.' 6 | 7 | common: 8 | 9 | prefix: '&b&lPhantomWorlds:&7' 10 | 11 | no-permission: '%prefix% You don''t have access to that. &8(%permission%)' 12 | 13 | list-delimiter: '&7, &b' 14 | 15 | command: 16 | 17 | phantomworlds: 18 | 19 | usage: 20 | - '%prefix% Available commands:' 21 | - '&8 &m->&b /%label% create &8- &7create a world' 22 | - '&8 &m->&b /%label% import &8- &7import a world' 23 | - '&8 &m->&b /%label% list &8- &7list loaded worlds' 24 | - '&8 &m->&b /%label% teleport &8- &7teleport to a loaded world''s spawnpoint' 25 | - '&8 &m->&b /%label% spawn [player] &8- &7teleport to the spawn of the current world' 26 | - '&8 &m->&b /%label% set effects [effects] &8- &7set the potion effects to be applied to players in this world.' 27 | - '&8 &m->&b /%label% set gamemode &8- &7set the gamemode for this world.' 28 | - '&8 &m->&b /%label% set portal &8- &7set where the specified portal type takes players in this world.' 29 | - '&8 &m->&b /%label% set whitelist &8- &7set whether there is a whitelist for this world or not.' 30 | - '&8 &m->&b /%label% setspawn &8- &7set the spawnpoint of a world' 31 | - '&8 &m->&b /%label% delete &8- &7delete a world' 32 | - '&8 &m->&b /%label% backup &8- &7Backup a world' 33 | - '&8 &m->&b /%label% unload &8- &7unload a loaded world' 34 | - '&8 &m->&b /%label% load &8- &7load an unloaded world' 35 | - '&8 &m->&b /%label% reload &8- &7reload all config & data files' 36 | - '&8 &m->&b /%label% info &8- &7view info about the plugin' 37 | - '&8 &m->&b /%label% compatibility &8- &7check for incompatibilities' 38 | 39 | help-header: '&7=== %prefix% &f[&7%page%&f/&b%max%&f] &7===' 40 | 41 | help: 42 | create: '&b/pw create [options...] &8- &7create a world' 43 | import: '&b/pw import &8- &7import a world' 44 | list: '&b/pw list &8- &7list worlds' 45 | tp: '&b/pw teleport [player] &8- &7teleport to a loaded world''s spawnpoint' 46 | spawn: '&b/pw spawn &8- &7teleport to the spawn of the current world' 47 | debug: '&b/pw debug &8- &7Change the debug mode for PhantomWorlds.' 48 | seteffects: '&b/pw set effects [effects] &8- &7set the potion effects to be applied to players in this world.' 49 | setgamemode: '&b/pw set gamemode &8- &7set the gamemode for this world.' 50 | setportal: '&b/pw set portal &8- &7set where the specified portal type takes players in this world.' 51 | setwhitelist: '&b/pw set whitelist &8- &7set whether there is a whitelist for this world or not.' 52 | setspawn: '&b/pw setspawn [x] [y] [z] [world] [yaw] [pitch] &8- &7set the spawnpoint of a world' 53 | delete: '&b/pw delete &8- &7delete a world' 54 | backup: '&b/pw backup &8- &7backup a world' 55 | unload: '&b/pw unload &8- &7unload a loaded world' 56 | load: '&b/pw load &8- &7load an unloaded world' 57 | reload: '&b/pw reload &8- &7reload all config & data files' 58 | info: '&b/pw info &8- &7view info about the plugin' 59 | compatibility: '&b/pw compatibility &8- &7check for incompatibilities' 60 | 61 | invalid-subcommand: 62 | - '%prefix% Invalid subcommand ''&b%arg%&7''.' 63 | 64 | subcommands: 65 | 66 | # Messages inside this 'common' branch are used 67 | # among multiple subcommands. 68 | common: 69 | 70 | invalid-world: 71 | - '%prefix% World ''&b%world%&7'' is not loaded.' 72 | 73 | player-offline: 74 | - '%prefix% Player ''&b%player%&7'' is offline.' 75 | 76 | backup: 77 | 78 | usage: 79 | - '%prefix% Invalid usage, try ''&b/%label% backup &7''.' 80 | 81 | success: 82 | - '%prefix% You have created a back up for the world ''&b%world%&7''.' 83 | 84 | failure: 85 | - '%prefix% Issue while creating a back up for the world ''&b%world%&7''.' 86 | 87 | compatibility: 88 | 89 | start: 90 | - '%prefix% Starting compatibility checker...' 91 | 92 | found-none: 93 | - '%prefix% Compatibility check finished with no incompatibilities detected.' 94 | 95 | found: 96 | - '%prefix% Compatibility check finished with &b%amount%&7 detections:' 97 | 98 | entry: 99 | - '&8| &3#%index% &8(&7Type: &b%type%&8)&7:' 100 | - '&8| &m->&f Reason: &7%reason%' 101 | - '&8| &m->&f Recommendation: &7%recommendation%' 102 | - ' ' 103 | 104 | usage: 105 | - '%prefix% Invalid usage, try ''&b/%label% compatibility&7''.' 106 | 107 | create: 108 | 109 | already-loaded: 110 | - '%prefix% World ''&b%world%&7'' is already loaded - you may teleport to it using ''&b/%label% tp %world%&7''.' 111 | 112 | creation: 113 | 114 | starting: 115 | - '%prefix% Starting creation of world ''&b%world%&7''...' 116 | 117 | saving-world-data: 118 | - '%prefix% &8[%world%: 1/2]: &7Saving world data...' 119 | 120 | constructing-world: 121 | - '%prefix% &8[%world%: 2/2]: &7Constructing the world...' 122 | - '%prefix% &8[%world%: 2/2]: &7(The server may briefly freeze)' 123 | 124 | complete: 125 | - '%prefix% World ''&b%world%&7'' created:' 126 | - '&8 &m->&7 Took &b%time%ms&7.' 127 | - '&8 &m->&7 You may teleport to it using ''&b/%label% tp %world%&7''.' 128 | 129 | options: 130 | 131 | invalid-option: 132 | - '%prefix% Invalid world option ''&b%option%&7''.' 133 | - '%prefix% Valid world options: &b%options%&7.' 134 | 135 | invalid-value: 136 | - '%prefix% Invalid world option value ''&b%value%&7'' for option ''&b%option%&7'', a &b%expected%&7 value was expected.' 137 | 138 | invalid-value-list: 139 | - '%prefix% Invalid world option value ''&b%value%&7'' for option ''&b%option%&7'', a valid &b%expected%&7 was expected.' 140 | - '%prefix% Valid values: &b%values%&7.' 141 | 142 | invalid-environment: 143 | - '%prefix% Environment ''&b%type%&7'' doesn''t exist.' 144 | - '%prefix% Valid environments: &b%types%&7.' 145 | 146 | usage: 147 | - '%prefix% Invalid usage, try ''&b/%label% create [options...]&7''.' 148 | 149 | debug: 150 | 151 | usage: 152 | - '%prefix% Invalid usage, try ''&b/%label% debug &7''.' 153 | 154 | success: 155 | - '%prefix%: &7Note: Please do not run this subcommand unless you are sure you are meant to be doing so' 156 | 157 | failure: 158 | - '%prefix%: &7Invalid debug method ''%method%''.' 159 | 160 | delete: 161 | 162 | usage: 163 | - '%prefix% Invalid usage, try ''&b/%label% delete &7''.' 164 | 165 | success: 166 | - '%prefix% You have deleted the world ''&b%world%&7''.' 167 | 168 | failure: 169 | - '%prefix% Issue while deleting the world ''&b%world%&7''.' 170 | 171 | import: 172 | 173 | usage: 174 | - '%prefix% Invalid usage, try ''&b/%label% import &7''.' 175 | 176 | success: 177 | - '%prefix% You have imported the world ''&b%world%&7''.' 178 | 179 | failure-exist: 180 | - '%prefix% Issue while importing the world. The world does not exist!' 181 | 182 | failure-already: 183 | - '%prefix% Issue while importing the world ''&b%world%&7''. The world is already managed by PhantomWorlds!' 184 | 185 | info: 186 | 187 | success: 188 | - '%prefix% Plugin information:' 189 | - '&8| &7Running &bPhantomWorlds v%version%' 190 | - '&8| &7Authors: &b%authors%' 191 | - '&8| &7Contributors: &b%contributors%' 192 | - '&8| &7Supported MC versions: &b%supportedServerVersions%' 193 | 194 | usage: 195 | - '%prefix% Invalid usage, try ''&b/%label% info&7''.' 196 | 197 | load: 198 | 199 | usage: 200 | - '%prefix% Invalid usage, try ''&b/%label% load &7''.' 201 | 202 | success: 203 | - '%prefix% You have loaded the world ''&b%world%&7''.' 204 | 205 | failure-folder: 206 | - '%prefix% Issue while loading the world. The world folder does not exist!' 207 | 208 | failure-loading: 209 | - '%prefix% Unknown issue while loading the world.' 210 | 211 | list: 212 | 213 | usage: 214 | - '%prefix% Invalid usage, try ''&b/%label% list&7''.' 215 | 216 | header-loaded: 217 | - '%prefix% Worlds loaded &8(&b%amount%&8)&7:' 218 | 219 | header-unloaded: 220 | - '%prefix% Worlds unloaded &8(&b%amount%&8)&7:' 221 | 222 | header-archived: 223 | - '%prefix% Worlds archived &8(&b%amount%&8)&7:' 224 | 225 | entry: 226 | - '&8 &m->&b %world%' 227 | 228 | reload: 229 | 230 | usage: 231 | - '%prefix% Invalid usage, try ''&b/%label% reload&7''.' 232 | 233 | reloading-files: 234 | - '%prefix% &8[1/2] &7Reloading files...' 235 | 236 | reloading-worlds: 237 | - '%prefix% &8[2/2] &7Reloading worlds...' 238 | 239 | reload-complete: 240 | - '%prefix% Reload complete.' 241 | 242 | seteffects: 243 | 244 | usage: 245 | - '%prefix% Invalid usage, try ''&b/%label% set effects [effects] &8- &7''.' 246 | 247 | success: 248 | - '%prefix% Successfully set the potion effects of world ''&b%world%&7'' to ''&b%effects%&7''.' 249 | 250 | setgamemode: 251 | 252 | usage: 253 | - '%prefix% Invalid usage, try ''&b/%label% set gamemode &8- &7''.' 254 | 255 | success: 256 | - '%prefix% Successfully set the gamemode of world ''&b%world%&7'' to ''&b%gamemode%&7''.' 257 | 258 | setportal: 259 | 260 | usage: 261 | - '%prefix% Invalid usage, try ''&b/%label% set portal &8- &7''.' 262 | 263 | success: 264 | - '%prefix% Successfully set the portal destination for portal ''&b%portal%&7'' of world ''&b%world%&7'' to world ''&b%world_to%&7''.' 265 | 266 | setwhitelist: 267 | 268 | usage: 269 | - '%prefix% Invalid usage, try ''&b/%label% set whitelist &8- &7''.' 270 | 271 | success: 272 | - '%prefix% Successfully set whitelist of world ''&b%world%&7'' to ''&b%whitelist%&7''.' 273 | 274 | setspawn: 275 | 276 | usage: 277 | - '%prefix% Invalid usage, try ''&b/%label% setspawn [x] [y] [z] [world] [yaw] [pitch]&7''.' 278 | 279 | usage-console: 280 | - '%prefix% Invalid usage for console, try ''&b/%label% setspawn [yaw] [pitch]&7''.' 281 | 282 | invalid-number: 283 | - '%prefix% ''&b%arg%&7'' isn''t a valid number.' 284 | 285 | success: 286 | - '%prefix% Spawn location set for world ''&b%world%&7''!' 287 | - '&8 &m->&7 Coordinates: &b%x%&7, &b%y%&7, &b%z%' 288 | - '&8 &m->&7 Yaw/Pitch: &b%yaw%&8/&b%pitch%' 289 | 290 | teleport: 291 | 292 | usage: 293 | - '%prefix% Invalid usage, try ''&b/%label% teleport [player]&7''.' 294 | 295 | usage-console: 296 | - '%prefix% Invalid usage for console, try ''&b/%label% teleport &7''.' 297 | 298 | success: 299 | - '%prefix% Teleported player ''&b%player%&7'' to the spawn point of world ''&b%world%&7''.' 300 | 301 | spawn: 302 | 303 | usage: 304 | - '%prefix% Invalid usage, try ''&b/%label% spawn [player]&7''.' 305 | 306 | usage-console: 307 | - '%prefix% Invalid usage for console, try ''&b/%label% spawn &7''.' 308 | 309 | success: 310 | - '%prefix% Teleported player ''&b%player%&7'' to the spawn point of world ''&b%world%&7''.' 311 | 312 | gamerule: 313 | 314 | rules: 315 | 316 | invalid-rule: 317 | - '%prefix% Invalid gamerule ''&b%rule%&7''.' 318 | - '%prefix% Valid world gamerules: &b%rules%&7.' 319 | 320 | invalid-value: 321 | - '%prefix% Invalid gamerule value ''&b%value%&7'' for gamerule ''&b%rule%&7'', a &b%expected%&7 value was expected.' 322 | 323 | usage: 324 | - '%prefix% Invalid usage, try ''&b/%label% gamerule [gamerules]&7''.' 325 | 326 | usage-console: 327 | - '%prefix% Invalid usage for console, try ''&b/%label% [gamerules]&7''.' 328 | 329 | success: 330 | - '%prefix% Set the gamerules of world ''&b%world%&7''.' 331 | 332 | unload: 333 | 334 | usage: 335 | - '%prefix% Invalid usage, try ''&b/%label% unload &7''.' 336 | 337 | in-specified-world: 338 | - '%prefix% You can''t unload world ''&b%world%&7'' as you are currently in it.' 339 | 340 | success: 341 | - '%prefix% You have unloaded the world ''&b%world%&7''.' 342 | - '%prefix% &eWarning: &7If the unloaded world''s folder is still present when you re-start your server, it will be loaded again. If you wish to prevent this, transfer the world''s directory elsewhere.' 343 | 344 | kick: 345 | - '%prefix% The world you were in was unloaded. Please re-join.' 346 | 347 | # Do not touch anything here unless you know what you are doing. 348 | advanced: 349 | file-version: 8 350 | generated-with: '${project.version}' -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/commandsredux/sub/CreateCommand.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.commandsredux.sub; 2 | /* 3 | * Phantom Worlds 4 | * Copyright (C) 2023 - 2024 Daniel "creatorfromhell" Vidmar 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | import me.lokka30.microlib.maths.QuickTimer; 21 | import me.lokka30.microlib.messaging.MultiMessage; 22 | import me.lokka30.phantomworlds.PhantomWorlds; 23 | import me.lokka30.phantomworlds.misc.Utils; 24 | import me.lokka30.phantomworlds.world.PhantomWorld; 25 | import org.bukkit.Bukkit; 26 | import org.bukkit.Difficulty; 27 | import org.bukkit.GameMode; 28 | import org.bukkit.World; 29 | import org.bukkit.WorldType; 30 | import org.bukkit.command.CommandSender; 31 | 32 | import java.util.Arrays; 33 | import java.util.List; 34 | import java.util.Locale; 35 | import java.util.Optional; 36 | import java.util.concurrent.TimeUnit; 37 | 38 | /** 39 | * CreateCommand 40 | * 41 | * @author creatorfromhell 42 | * @since 2.0.5.0 43 | */ 44 | public class CreateCommand { 45 | 46 | public static void onCommand(final CommandSender sender, final String worldName, final World.Environment environment, final List settings) { 47 | 48 | if(Bukkit.getWorld(worldName) != null) { 49 | (new MultiMessage( 50 | PhantomWorlds.instance().messages.getConfig() 51 | .getStringList("command.phantomworlds.subcommands.create.already-loaded"), 52 | Arrays.asList( 53 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 54 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 55 | new MultiMessage.Placeholder("world", worldName, false), 56 | new MultiMessage.Placeholder("label", "pw", false) 57 | ))).send(sender); 58 | return; 59 | } 60 | 61 | if(environment == null) { 62 | (new MultiMessage( 63 | PhantomWorlds.instance().messages.getConfig().getStringList( 64 | "command.phantomworlds.subcommands.create.options.invalid-environment"), 65 | Arrays.asList( 66 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 67 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 68 | new MultiMessage.Placeholder("type", "", false), 69 | new MultiMessage.Placeholder("types", String.join( 70 | PhantomWorlds.instance().messages.getConfig().getString("common.list-delimiter", "&7, &b"), 71 | Utils.enumValuesToStringList(World.Environment.values())), true) 72 | ))).send(sender); 73 | return; 74 | } 75 | 76 | /* Default options: */ 77 | boolean generateStructures = true; 78 | String generator = null; 79 | String generatorSettings = null; 80 | boolean hardcore = false; 81 | Long seed = null; 82 | WorldType worldType = WorldType.NORMAL; 83 | boolean spawnMobs = true; 84 | boolean spawnAnimals = true; 85 | boolean keepSpawnInMemory = false; 86 | boolean allowPvP = true; 87 | Difficulty difficulty = Difficulty.NORMAL; 88 | GameMode mode = GameMode.SURVIVAL; 89 | for(final String setting : settings) { 90 | 91 | final String[] split = setting.split(":", 2); 92 | if(split.length != 2) { 93 | (new MultiMessage( 94 | PhantomWorlds.instance().messages.getConfig().getStringList( 95 | "command.phantomworlds.subcommands.create.options.invalid-option"), 96 | Arrays.asList( 97 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 98 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 99 | new MultiMessage.Placeholder("option", setting, false), 100 | new MultiMessage.Placeholder("options", String.join( 101 | PhantomWorlds.instance().messages.getConfig() 102 | .getString("common.list-delimiter", "&7, &b"), 103 | Arrays.asList("genStructures", "gen", "genSettings", "hardcore", 104 | "seed", "type", "spawnMobs", "spawnAnimals", 105 | "keepSpawnInMemory", "allowPvP", "difficulty", "gamemode") 106 | ), true) 107 | ))).send(sender); 108 | return; 109 | } 110 | 111 | final String option = split[0].toLowerCase(Locale.ROOT); 112 | final StringBuilder value = new StringBuilder(split[1]); 113 | 114 | switch(option) { 115 | case "generatestructures": 116 | case "genstructures": 117 | case "structures": 118 | 119 | final Optional gen = Utils.parseFromString(sender, value, option); 120 | if(!gen.isPresent()) { 121 | return; 122 | } 123 | generateStructures = gen.get(); 124 | break; 125 | 126 | case "generator": 127 | case "gen": 128 | generator = value.toString(); 129 | break; 130 | 131 | case "generatorsettings": 132 | case "gensettings": 133 | generatorSettings = value.toString(); 134 | break; 135 | case "gamemode": 136 | mode = GameMode.valueOf(value.toString()); 137 | break; 138 | case "hardcore": 139 | 140 | final Optional hard = Utils.parseFromString(sender, value, option); 141 | if(!hard.isPresent()) { 142 | return; 143 | } 144 | hardcore = hard.get(); 145 | break; 146 | 147 | case "seed": 148 | try { 149 | seed = Long.valueOf(value.toString()); 150 | } catch(NumberFormatException ex) { 151 | (new MultiMessage( 152 | PhantomWorlds.instance().messages.getConfig().getStringList( 153 | "command.phantomworlds.subcommands.create.options.invalid-value"), 154 | Arrays.asList( 155 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 156 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 157 | new MultiMessage.Placeholder("value", value.toString(), false), 158 | new MultiMessage.Placeholder("option", option, false), 159 | new MultiMessage.Placeholder("expected", "Long (any number)", 160 | false) 161 | ))).send(sender); 162 | return; 163 | } 164 | break; 165 | case "type": 166 | case "worldtype": 167 | try { 168 | worldType = WorldType.valueOf( 169 | value.toString().toUpperCase(Locale.ROOT)); 170 | } catch(IllegalArgumentException ex) { 171 | (new MultiMessage( 172 | PhantomWorlds.instance().messages.getConfig().getStringList( 173 | "command.phantomworlds.subcommands.create.options.invalid-value-list"), 174 | Arrays.asList( 175 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 176 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 177 | new MultiMessage.Placeholder("value", value.toString(), false), 178 | new MultiMessage.Placeholder("option", option, false), 179 | new MultiMessage.Placeholder("expected", "WorldType", false), 180 | new MultiMessage.Placeholder("values", String.join( 181 | PhantomWorlds.instance().messages.getConfig() 182 | .getString("common.list-delimiter", "&7, &b"), 183 | Utils.enumValuesToStringList(WorldType.values())), true) 184 | ))).send(sender); 185 | return; 186 | } 187 | break; 188 | case "spawnmobs": 189 | case "mobs": 190 | 191 | final Optional mobs = Utils.parseFromString(sender, value, option); 192 | if(!mobs.isPresent()) { 193 | return; 194 | } 195 | spawnMobs = mobs.get(); 196 | break; 197 | 198 | case "spawnanimals": 199 | case "animals": 200 | 201 | final Optional animals = Utils.parseFromString(sender, value, option); 202 | if(!animals.isPresent()) { 203 | return; 204 | } 205 | spawnAnimals = animals.get(); 206 | break; 207 | 208 | case "keepspawninmemory": 209 | case "spawninmemory": 210 | 211 | final Optional spawn = Utils.parseFromString(sender, value, option); 212 | if(!spawn.isPresent()) { 213 | return; 214 | } 215 | keepSpawnInMemory = spawn.get(); 216 | break; 217 | 218 | case "allowpvp": 219 | case "pvp": 220 | 221 | final Optional pvp = Utils.parseFromString(sender, value, option); 222 | if(!pvp.isPresent()) { 223 | return; 224 | } 225 | allowPvP = pvp.get(); 226 | break; 227 | 228 | case "difficulty": 229 | case "diff": 230 | try { 231 | difficulty = Difficulty.valueOf( 232 | value.toString().toUpperCase(Locale.ROOT)); 233 | } catch(IllegalArgumentException ex) { 234 | (new MultiMessage( 235 | PhantomWorlds.instance().messages.getConfig().getStringList( 236 | "command.phantomworlds.subcommands.create.options.invalid-value-list"), 237 | Arrays.asList( 238 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 239 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 240 | new MultiMessage.Placeholder("value", value.toString(), false), 241 | new MultiMessage.Placeholder("option", option, false), 242 | new MultiMessage.Placeholder("expected", "Difficulty", false), 243 | new MultiMessage.Placeholder("values", String.join( 244 | PhantomWorlds.instance().messages.getConfig() 245 | .getString("common.list-delimiter", "&7, &b"), 246 | Utils.enumValuesToStringList(Difficulty.values())), true) 247 | ))).send(sender); 248 | return; 249 | } 250 | break; 251 | default: 252 | (new MultiMessage( 253 | PhantomWorlds.instance().messages.getConfig().getStringList( 254 | "command.phantomworlds.subcommands.create.options.invalid-option"), 255 | Arrays.asList( 256 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 257 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 258 | new MultiMessage.Placeholder("option", option, false), 259 | new MultiMessage.Placeholder("options", String.join( 260 | PhantomWorlds.instance().messages.getConfig() 261 | .getString("common.list-delimiter", "&7, &b"), 262 | Arrays.asList("genStructures", "gen", "genSettings", "hardcore", 263 | "seed", "type", "spawnMobs", "spawnAnimals", 264 | "keepSpawnInMemory", "allowPvP", "difficulty") 265 | ), true) 266 | ))).send(sender); 267 | return; 268 | } 269 | } 270 | 271 | final PhantomWorld pworld = new PhantomWorld( 272 | worldName, environment, generateStructures, generator, 273 | generatorSettings, hardcore, seed, worldType, spawnMobs, 274 | spawnAnimals, keepSpawnInMemory, allowPvP, difficulty, mode 275 | ); 276 | 277 | final QuickTimer quickTimer = new QuickTimer(TimeUnit.MILLISECONDS); 278 | 279 | (new MultiMessage( 280 | PhantomWorlds.instance().messages.getConfig() 281 | .getStringList("command.phantomworlds.subcommands.create.creation.starting"), 282 | Arrays.asList( 283 | new MultiMessage.Placeholder("prefix", 284 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 285 | true), 286 | new MultiMessage.Placeholder("world", worldName, false) 287 | ))).send(sender); 288 | 289 | (new MultiMessage( 290 | PhantomWorlds.instance().messages.getConfig().getStringList( 291 | "command.phantomworlds.subcommands.create.creation.saving-world-data"), 292 | Arrays.asList( 293 | new MultiMessage.Placeholder("prefix", 294 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 295 | true), 296 | new MultiMessage.Placeholder("world", worldName, false) 297 | ))).send(sender); 298 | 299 | pworld.save(); 300 | 301 | (new MultiMessage( 302 | PhantomWorlds.instance().messages.getConfig().getStringList( 303 | "command.phantomworlds.subcommands.create.creation.constructing-world"), 304 | Arrays.asList( 305 | new MultiMessage.Placeholder("prefix", 306 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 307 | true), 308 | new MultiMessage.Placeholder("world", worldName, false) 309 | ))).send(sender); 310 | 311 | pworld.create(); 312 | 313 | (new MultiMessage( 314 | PhantomWorlds.instance().messages.getConfig() 315 | .getStringList("command.phantomworlds.subcommands.create.creation.complete"), 316 | Arrays.asList( 317 | new MultiMessage.Placeholder("prefix", 318 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 319 | true), 320 | new MultiMessage.Placeholder("world", worldName, false), 321 | new MultiMessage.Placeholder("time", Long.toString(quickTimer.getDuration()), false), 322 | new MultiMessage.Placeholder("label", "pw", false) 323 | ))).send(sender); 324 | } 325 | } -------------------------------------------------------------------------------- /src/main/java/me/lokka30/phantomworlds/misc/Utils.java: -------------------------------------------------------------------------------- 1 | package me.lokka30.phantomworlds.misc; 2 | 3 | import me.lokka30.microlib.messaging.MessageUtils; 4 | import me.lokka30.microlib.messaging.MultiMessage; 5 | import me.lokka30.phantomworlds.PhantomWorlds; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.Location; 8 | import org.bukkit.World; 9 | import org.bukkit.command.CommandExecutor; 10 | import org.bukkit.command.CommandSender; 11 | import org.bukkit.entity.Player; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | import java.io.File; 16 | import java.io.FileInputStream; 17 | import java.io.FileOutputStream; 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | import java.nio.file.Files; 21 | import java.util.ArrayList; 22 | import java.util.Arrays; 23 | import java.util.HashSet; 24 | import java.util.List; 25 | import java.util.Locale; 26 | import java.util.Optional; 27 | import java.util.Properties; 28 | import java.util.zip.ZipEntry; 29 | import java.util.zip.ZipOutputStream; 30 | 31 | /** 32 | * This class contains Utility methods which are public & static which are used by multiple classes. 33 | * If a method is only used by one class then it is advised to keep it in the class to avoid 34 | * bloating this class. 35 | * 36 | * @author lokka30 37 | * @since v2.0.0 38 | */ 39 | public class Utils { 40 | 41 | /** 42 | * This is used for tab completion where numbers are expected, for example, coordinates in the 43 | * setspawn subcommand. 44 | */ 45 | public static final List ZERO_THRU_NINE = Arrays.asList("0", "1", "2", "3", "4", "5", 46 | "6", "7", "8", "9"); 47 | 48 | /** 49 | * This method returns a list of the names of worlds that are loaded on the server. Used in tab 50 | * completion, for example. 51 | * 52 | * @return set of world names 53 | * 54 | * @since v2.0.0 55 | */ 56 | public static HashSet getLoadedWorldsNameList() { 57 | final HashSet loadedWorlds = new HashSet<>(); 58 | Bukkit.getWorlds().forEach(world->loadedWorlds.add(world.getName())); 59 | return loadedWorlds; 60 | } 61 | 62 | /** 63 | * Attempts to register specified command. Sends status to console as logs. 64 | * 65 | * @param clazz CommandExecutor to be registered 66 | * @param command Name of the command as stated in plugin.yml 67 | * 68 | * @since v2.0.0 69 | */ 70 | public static void registerCommand(@NotNull final CommandExecutor clazz, @NotNull final String command) { 71 | if(PhantomWorlds.instance().getCommand(command) == null) { 72 | PhantomWorlds.logger().severe("Unable to register command '/" + command + "' - PluginCommand " 73 | + "is null. Was plugin.yml tampered with?"); 74 | } else { 75 | //noinspection ConstantConditions 76 | PhantomWorlds.instance().getCommand(command).setExecutor(clazz); 77 | PhantomWorlds.logger().info("Registered command '/" + command + "'."); 78 | } 79 | } 80 | 81 | /** 82 | * Tells the server to unload specified world so it can be deleted. Additionally: -> Kicks all 83 | * players from it before unloading. -> It does not transfer users to other worlds for security 84 | * purposes. This may be changed in the future. 85 | * 86 | * @param world World to be unloaded 87 | * 88 | * @since v2.0.0 89 | */ 90 | public static void unloadWorld(@NotNull final World world) { 91 | // inform console 92 | PhantomWorlds.logger().info(String.format( 93 | "Unloading world %s; kicking %s players from the world...", 94 | world.getName(), 95 | world.getPlayers().size() 96 | )); 97 | 98 | // kick players in world 99 | // using an iterator to avoid a possible ConcurrentModificationException 100 | world.getPlayers().iterator().forEachRemaining(player-> 101 | // yikes, this gets messy. :P 102 | player.kickPlayer(MessageUtils.colorizeAll( 103 | String.join("\n", 104 | PhantomWorlds.instance().messages.getConfig() 105 | .getStringList("command.phantomworlds.subcommands.unload.kick") 106 | ) 107 | .replace("%prefix%", 108 | PhantomWorlds.instance().messages.getConfig() 109 | .getString("common.prefix", "PhantomWorlds: ")) 110 | .replace("%world%", world.getName()) 111 | )) 112 | ); 113 | 114 | // time to unload the world 115 | Bukkit.unloadWorld(world, true); 116 | } 117 | 118 | /** 119 | * For the CommandSender specified, this method will list every player that the tab list will show 120 | * them. This does not work with vanish plugins that **exclusively** use packets, as it relies on 121 | * Bukkit's 'hidePlayer' system. 122 | * 123 | * @param sender commandsender to check. if console, all players are visible. 124 | * 125 | * @return list of usernames 126 | * 127 | * @since v2.0.0 128 | */ 129 | public static List getPlayersCanSeeList(@NotNull final CommandSender sender) { 130 | final List suggestions = new ArrayList<>(); 131 | 132 | if(!sender.hasPermission("phantomworlds.knows-vanished-users") 133 | && sender instanceof Player) { 134 | final Player player = (Player)sender; 135 | for(Player listedPlayer : Bukkit.getOnlinePlayers()) { 136 | if(player.canSee(listedPlayer)) { 137 | suggestions.add(listedPlayer.getName()); 138 | } 139 | } 140 | } else { 141 | for(Player listedPlayer : Bukkit.getOnlinePlayers()) { 142 | suggestions.add(listedPlayer.getName()); 143 | } 144 | } 145 | 146 | return suggestions; 147 | } 148 | 149 | /** 150 | * @param values Enum#values() call 151 | * 152 | * @return a list of string conversions of each enum value 153 | * 154 | * @since v2.0.0 155 | */ 156 | public static List enumValuesToStringList(final Object[] values) { 157 | final List strings = new ArrayList<>(); 158 | for(Object value : values) { 159 | strings.add(value.toString()); 160 | } 161 | return strings; 162 | } 163 | 164 | /** 165 | * Credit: StackOverflow 166 | * 167 | * @param val value to round 168 | * 169 | * @return val, rounded to 2 decimal places. 170 | */ 171 | public static double roundTwoDecimalPlaces(final double val) { 172 | return Math.round(val * 100) / 100.0; 173 | } 174 | 175 | public static Optional parseFromString(CommandSender sender, final StringBuilder value, final String option) { 176 | switch(value.toString().toLowerCase(Locale.ROOT)) { 177 | case "false": 178 | case "f": 179 | case "no": 180 | case "n": 181 | return Optional.of(false); 182 | case "true": 183 | case "t": 184 | case "yes": 185 | case "y": 186 | return Optional.of(true); 187 | default: 188 | (new MultiMessage( 189 | PhantomWorlds.instance().messages.getConfig().getStringList( 190 | "command.phantomworlds.subcommands.create.options.invalid-value"), 191 | Arrays.asList( 192 | new MultiMessage.Placeholder("prefix", 193 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", 194 | "&b&lPhantomWorlds: &7"), true), 195 | new MultiMessage.Placeholder("value", value.toString(), 196 | false), 197 | new MultiMessage.Placeholder("option", option, false), 198 | new MultiMessage.Placeholder("expected", 199 | "Boolean (true/false)", false) 200 | ))).send(sender); 201 | return Optional.empty(); 202 | } 203 | } 204 | 205 | public static void zipFolder(File sourceFolder, String destinationZipFile) throws IOException { 206 | try(FileOutputStream fos = new FileOutputStream(destinationZipFile); 207 | ZipOutputStream zos = new ZipOutputStream(fos)) { 208 | 209 | //zipFolder(sourceFolder, sourceFolder.getName(), zos); 210 | 211 | zipFile(sourceFolder, sourceFolder.getName(), zos); 212 | zos.closeEntry(); 213 | zos.flush(); 214 | zos.close(); 215 | fos.flush(); 216 | } catch(Exception e) { 217 | e.printStackTrace(); 218 | } 219 | } 220 | 221 | public static void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException { 222 | if(fileToZip.isHidden()) { 223 | return; 224 | } 225 | 226 | if(fileToZip.isDirectory()) { 227 | 228 | if(fileName.endsWith("/")) { 229 | 230 | zipOut.putNextEntry(new ZipEntry(fileName)); 231 | zipOut.closeEntry(); 232 | } else { 233 | 234 | zipOut.putNextEntry(new ZipEntry(fileName + "/")); 235 | zipOut.closeEntry(); 236 | } 237 | 238 | File[] children = fileToZip.listFiles(); 239 | if(children == null) { 240 | return; 241 | } 242 | 243 | for(File childFile : children) { 244 | zipFile(childFile, fileName + "/" + childFile.getName(), zipOut); 245 | } 246 | return; 247 | } 248 | 249 | FileInputStream fis = new FileInputStream(fileToZip); 250 | ZipEntry zipEntry = new ZipEntry(fileName); 251 | zipOut.putNextEntry(zipEntry); 252 | 253 | byte[] bytes = new byte[1024]; 254 | int length; 255 | 256 | while((length = fis.read(bytes)) >= 0) { 257 | zipOut.write(bytes, 0, length); 258 | } 259 | fis.close(); 260 | } 261 | 262 | public static void zipFolder(final File folder, final String parentFolder, final ZipOutputStream zos) throws IOException { 263 | 264 | if(folder == null || folder.exists()) { 265 | return; 266 | } 267 | 268 | final File[] files = folder.listFiles(); 269 | if(files == null) { 270 | return; 271 | } 272 | 273 | for (File file : files) { 274 | if (file.isDirectory()) { 275 | zipFolder(file, parentFolder + File.separator + file.getName(), zos); 276 | continue; 277 | } 278 | 279 | final ZipEntry zipEntry = new ZipEntry(parentFolder + File.separator + file.getName()); 280 | zos.putNextEntry(zipEntry); 281 | 282 | try (FileInputStream fis = new FileInputStream(file)) { 283 | final byte[] buffer = new byte[1024]; 284 | int length; 285 | while ((length = fis.read(buffer)) > 0) { 286 | zos.write(buffer, 0, length); 287 | } 288 | } 289 | zos.closeEntry(); 290 | } 291 | } 292 | 293 | public static boolean deleteFolder(File folder) { 294 | if (folder.exists()) { 295 | final File[] files = folder.listFiles(); 296 | if (files != null) { 297 | for (File file : files) { 298 | if (file.isDirectory()) { 299 | deleteFolder(file); 300 | } else { 301 | file.delete(); 302 | } 303 | } 304 | } 305 | } 306 | return folder.delete(); 307 | } 308 | 309 | public static void teleportToWorld(@NotNull CommandSender sender, @NotNull String subCommand, 310 | @NotNull String label, @Nullable String targetPlayerName, 311 | @Nullable String worldName) { 312 | Player targetPlayer; 313 | if(targetPlayerName != null) { 314 | targetPlayer = Bukkit.getPlayer(targetPlayerName); 315 | 316 | // If the target is offline or invisible to the sender, then stop 317 | if(targetPlayer == null || !Utils.getPlayersCanSeeList(sender) 318 | .contains(targetPlayer.getName())) { 319 | (new MultiMessage( 320 | PhantomWorlds.instance().messages.getConfig() 321 | .getStringList("command.phantomworlds.subcommands.common.player-offline"), 322 | Arrays.asList( 323 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 324 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 325 | new MultiMessage.Placeholder("player", targetPlayerName, false) 326 | ))).send(sender); 327 | return; 328 | } 329 | } else { 330 | if(sender instanceof Player) { 331 | targetPlayer = (Player)sender; 332 | } else { 333 | (new MultiMessage( 334 | PhantomWorlds.instance().messages.getConfig().getStringList( 335 | "command.phantomworlds.subcommands." + subCommand + ".usage-console"), 336 | Arrays.asList( 337 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 338 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 339 | new MultiMessage.Placeholder("label", label, false) 340 | ))).send(sender); 341 | return; 342 | } 343 | } 344 | 345 | if(worldName == null) { 346 | worldName = targetPlayer.getWorld().getName(); 347 | } 348 | 349 | final World world = Bukkit.getWorld(worldName); 350 | if(world == null) { 351 | (new MultiMessage( 352 | PhantomWorlds.instance().messages.getConfig() 353 | .getStringList("command.phantomworlds.subcommands.common.invalid-world"), 354 | Arrays.asList( 355 | new MultiMessage.Placeholder("prefix", PhantomWorlds.instance().messages.getConfig() 356 | .getString("common.prefix", "&b&lPhantomWorlds: &7"), true), 357 | new MultiMessage.Placeholder("world", worldName, false) 358 | ))).send(sender); 359 | return; 360 | } 361 | targetPlayer.teleport(parseSpawn(world)); 362 | 363 | (new MultiMessage( 364 | PhantomWorlds.instance().messages.getConfig() 365 | .getStringList("command.phantomworlds.subcommands." + subCommand + ".success"), 366 | Arrays.asList( 367 | new MultiMessage.Placeholder("prefix", 368 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 369 | true), 370 | new MultiMessage.Placeholder("player", targetPlayer.getName(), false), 371 | new MultiMessage.Placeholder("world", worldName, false) 372 | ))).send(sender); 373 | } 374 | 375 | public static Location parseSpawn(final World world) { 376 | final String cfgPath = "worlds-to-load." + world.getName() + ".spawn"; 377 | if(PhantomWorlds.instance().data.getConfig().contains(cfgPath)) { 378 | final double x = PhantomWorlds.instance().data.getConfig().getDouble(cfgPath + ".x", world.getSpawnLocation().getX()); 379 | final double y = PhantomWorlds.instance().data.getConfig().getDouble(cfgPath + ".y", world.getSpawnLocation().getY()); 380 | final double z = PhantomWorlds.instance().data.getConfig().getDouble(cfgPath + ".z", world.getSpawnLocation().getZ()); 381 | final float yaw = (float)PhantomWorlds.instance().data.getConfig().getDouble(cfgPath + ".yaw", world.getSpawnLocation().getYaw()); 382 | final float pitch = (float)PhantomWorlds.instance().data.getConfig().getDouble(cfgPath + ".pitch", world.getSpawnLocation().getPitch()); 383 | 384 | return new Location(world, x, y, z, yaw, pitch); 385 | } 386 | return world.getSpawnLocation(); 387 | } 388 | 389 | public static boolean checkWorld(@NotNull final CommandSender sender, final String usage, @Nullable final World world) { 390 | if(world == null) { 391 | 392 | (new MultiMessage( 393 | PhantomWorlds.instance().messages.getConfig() 394 | .getStringList(usage), Arrays.asList( 395 | new MultiMessage.Placeholder("prefix", 396 | PhantomWorlds.instance().messages.getConfig().getString("common.prefix", "&b&lPhantomWorlds: &7"), 397 | true), 398 | new MultiMessage.Placeholder("label", "pw", false) 399 | ))).send(sender); 400 | 401 | return false; 402 | } 403 | return true; 404 | } 405 | 406 | public static String defaultWorld() { 407 | try (InputStream input = Files.newInputStream(new File(PhantomWorlds.instance().getDataFolder(), "../../server.properties").toPath())) { 408 | 409 | final Properties prop = new Properties(); 410 | prop.load(input); 411 | 412 | return prop.getProperty("level-name"); 413 | } catch(Exception ignore) { 414 | return "world"; 415 | } 416 | } 417 | } --------------------------------------------------------------------------------