diff --git a/.github/workflows/pr.test.yml b/.github/workflows/pr.test.yml
index b21190d5..6fa231e5 100644
--- a/.github/workflows/pr.test.yml
+++ b/.github/workflows/pr.test.yml
@@ -6,6 +6,6 @@ on:
jobs:
test:
- uses: Multiverse/Multiverse-Core/.github/workflows/generic.test.yml@main
+ uses: Multiverse/Multiverse-Core/.github/workflows/generic.test.yml@MV5 # todo: Change back to main before release
with:
plugin_name: multiverse-inventories
diff --git a/README.md b/README.md
index 4ff8241e..9a730db7 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,7 @@
-
+
-# Multiverse Inventories
-
[](https://modrinth.com/plugin/multiverse-inventories)
[](https://hangar.papermc.io/Multiverse/Multiverse-Inventories)
[](https://dev.bukkit.org/projects/multiverse-inventories)
@@ -17,11 +15,11 @@
[Multiverse Inventories](https://dev.bukkit.org/projects/multiverse-inventories) is an add-on Plugin for [Multiverse core](https://dev.bukkit.org/projects/multiverse-core) that lets players have separate inventories **per world!** This makes it possible to create multi gamemode servers without Velocity or Bungee!
-Now it's time to create your very own server with Multiverse Inventories, do check out our [Wiki](https://github.com/Multiverse/Multiverse-Core/wiki/Home-(Inventories)) and [Usage Guide](https://github.com/Multiverse/Multiverse-Core/wiki/Basics-(Inventories)) to get started. Feel free to hop onto our [Discord](https://discord.gg/NZtfKky) if you have any questions or just want to have a chat with us!
+Now it's time to create your very own server with Multiverse Inventories, do check out our [Wiki](https://mvplugins.org) and [Usage Guide](https://mvplugins.org/inventories/fundamentals/basic-usage/) to get started. Feel free to hop onto our [Discord](https://discord.gg/NZtfKky) if you have any questions or just want to have a chat with us!
## Our other amazing sub-modules:
-With just [Multiverse Core](https://github.com/multiverse/multiverse) and any of the below plugins, you can access all of these other related features in the Multiverse ecosystem.
+With just [Multiverse Core](https://github.com/multiverse/multiverse-core) and any of the below plugins, you can access all of these other related features in the Multiverse ecosystem.
* [Multiverse-NetherPortals](https://github.com/Multiverse/Multiverse-NetherPortals) -> Have separate nether and end worlds for each of your overworlds!
* [Multiverse-Portals](https://github.com/Multiverse/Multiverse-Portals) -> Make custom portals to go to any destination!
@@ -38,7 +36,7 @@ Simply build the source with Gradle:
**Want to help improve Multiverse Inventories?** There are several ways you can support and contribute to the project.
* Take a look at our "Bug: Unconfirmed" issues, where you can find issues that need extra testing and investigation.
* Want others to love Multiverse too? You can join the [Multiverse Discord community](https://discord.gg/NZtfKky) and help others with issues and setup!
-* A Multiverse guru? You can update our [Wiki](https://github.com/Multiverse/Multiverse-Core/wiki) with your latest tips, tricks and guides! The wiki open for all to edit and improve.
+* A Multiverse guru? You can update our [Wiki](https://github.com/Multiverse/multiverse-web) with your latest tips, tricks and guides! The wiki open for all to edit and improve.
* Love coding? You could look at ["State: Open to PR"](https://github.com/Multiverse/Multiverse-Inventories/labels/State%3A%20Open%20to%20PR) and ["Resolution: Accepted"](https://github.com/Multiverse/Multiverse-Inventories/labels/Resolution%3A%20Accepted) issues. We're always happy to receive bug fixes and feature additions as [pull requests](https://www.freecodecamp.org/news/how-to-make-your-first-pull-request-on-github-3/).
* If you'd like to make a financial contribution to the project, do consider joining our [Patreon](https://www.patreon.com/dumptruckman) or make a one-time donation [here](https://paypal.me/dumptruckman)!
diff --git a/build.gradle b/build.gradle
index bb0a9882..127b7194 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,106 +1,98 @@
plugins {
- id 'java-library'
- id 'maven-publish'
id 'checkstyle'
- id 'com.github.johnrengelman.shadow' version '7.1.2'
+ id 'org.mvplugins.multiverse-plugin' version '1.1.0'
}
-version = System.getenv('GITHUB_VERSION') ?: 'local'
-group = 'com.onarandombox.multiverseinventories'
+group = 'org.mvplugins.multiverse.inventories'
description = 'Multiverse-Inventories'
-java.sourceCompatibility = JavaVersion.VERSION_11
-
repositories {
- mavenLocal()
- mavenCentral()
-
maven {
- name = 'onarandombox'
- url = uri('https://repo.onarandombox.com/content/groups/public')
+ name = 'codemc'
+ url = uri('https://repo.codemc.org/repository/maven-releases')
}
maven {
- name ='papermc'
- url = uri('https://papermc.io/repo/repository/maven-public/')
+ name = 'benwoo1110'
+ url = uri('https://repo.c0ding.party/multiverse-beta')
}
+}
- maven {
- name = 'jitpack.io'
- url = uri('https://jitpack.io/')
- }
+configure(apiDependencies) {
+ serverApiVersion = '1.21.3-R0.1-SNAPSHOT'
+ mockBukkitServerApiVersion = '1.21'
+ mockBukkitVersion = '4.31.1'
}
dependencies {
- // Spigot
- implementation('org.bukkit:bukkit:1.14.4-R0.1-SNAPSHOT') {
- exclude group: 'junit', module: 'junit'
- }
+ // Server API
+ // TODO make our custom plugin target paper instead of spigot
+ externalPlugin 'io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT'
// Core
- implementation('com.onarandombox.multiversecore:Multiverse-Core:4.2.2') {
- exclude group: 'me.main__.util', module: 'SerializationConfig'
- }
+ // TODO update to correct version once we have it published
+ externalPlugin 'org.mvplugins.multiverse.core:multiverse-core:5.0.0-SNAPSHOT'
// Config
- api 'com.dumptruckman.minecraft:JsonConfiguration:1.1'
- api ('com.googlecode.json-simple:json-simple:1.1.1') {
- exclude group: 'junit', module: 'junit'
- }
+ shadowed 'com.dumptruckman.minecraft:JsonConfiguration:1.2-SNAPSHOT'
+ shadowed 'net.minidev:json-smart:2.5.1'
// Utils
- api 'io.papermc:paperlib:1.0.7'
- api('com.dumptruckman.minecraft:Logging:1.1.1') {
+ shadowed('com.dumptruckman.minecraft:Logging:1.1.1') {
exclude group: 'junit', module: 'junit'
}
+ // Caching
+ shadowed("com.github.ben-manes.caffeine:caffeine:3.2.0")
+
+ // Luckperms for group context
+ compileOnly 'net.luckperms:api:5.4'
+
// Other plugins for import
- implementation('uk.co:MultiInv:3.0.6') {
+ compileOnly('uk.co:MultiInv:3.0.6') {
exclude group: '*', module: '*'
}
- implementation('me.drayshak:WorldInventories:1.0.2') {
+ compileOnly('me.drayshak:WorldInventories:1.0.2') {
exclude group: '*', module: '*'
}
-
- // Legacy Multiverse-Adventure
- implementation('com.onarandombox.multiverseadventure:Multiverse-Adventure:2.5.0-SNAPSHOT') {
+ // perworldinventory is weird and has snakeyaml included in the jar, so we can only use compileOnly for build to work properly
+ compileOnly('me.ebonjaeger:perworldinventory-kt:2.3.2') {
exclude group: '*', module: '*'
}
- // Tests
- testImplementation 'com.github.MilkBowl:VaultAPI:1.7.1'
- testImplementation 'junit:junit:4.13.2'
- testImplementation 'org.mockito:mockito-core:3.11.2'
-}
-
-
-java {
- withSourcesJar()
- withJavadocJar()
-}
-
-tasks.withType(JavaCompile).configureEach {
- options.encoding = 'UTF-8'
+ // hk2 for annotation processing only
+ compileOnly('org.glassfish.hk2:hk2-api:3.0.3') {
+ exclude group: '*', module: '*'
+ }
+ annotationProcessor 'org.glassfish.hk2:hk2-metadata-generator:3.0.3'
+ testAnnotationProcessor 'org.glassfish.hk2:hk2-metadata-generator:3.0.3'
}
-tasks.withType(Javadoc).configureEach {
- options.encoding = 'UTF-8'
+shadowJar {
+ relocate 'com.dumptruckman.minecraft.util.Logging', 'org.mvplugins.multiverse.inventories.utils.InvLogging'
+ relocate 'com.dumptruckman.minecraft.util.DebugLog', 'org.mvplugins.multiverse.inventories.utils.DebugFileLogger'
+ relocate 'com.dumptruckman.bukkit.configuration', 'org.mvplugins.multiverse.inventories.utils.configuration'
+ relocate 'net.minidev', 'org.mvplugins.multiverse.inventories.utils.minidev'
+ relocate 'com.github.benmanes', 'org.mvplugins.multiverse.inventories.utils.benmanes'
+ relocate 'com.google.errorprone', 'org.mvplugins.multiverse.inventories.utils.errorprone'
+
+ dependencies {
+ exclude(dependency {
+ it.moduleGroup == 'org.ow2.asm'
+ })
+ exclude(dependency {
+ it.moduleGroup == 'org.jetbrains'
+ })
+ }
}
-
-configurations {
- [apiElements, runtimeElements].each {
- it.outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(jar) }
- it.outgoing.artifact(shadowJar)
- }
+checkstyle {
+ toolVersion = '6.1.1'
+ configFile file('config/mv_checks.xml')
+ ignoreFailures = true
}
publishing {
- publications {
- maven(MavenPublication) {
- from components.java
- }
- }
repositories {
maven {
name = "GitHubPackages"
@@ -110,57 +102,12 @@ publishing {
password = System.getenv("GITHUB_TOKEN")
}
}
+
maven {
- name = "multiverse"
- def releasesRepoUrl = "https://repo.onarandombox.com/multiverse-releases"
- def snapshotsRepoUrl = "https://repo.onarandombox.com/multiverse-snapshots"
- url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
+ // todo: remove before mv5 release
+ name = "multiverseBeta"
+ url = "https://repo.c0ding.party/multiverse-beta"
credentials(PasswordCredentials)
}
}
}
-
-
-processResources {
- def props = [version: "${project.version}"]
- inputs.properties props
- filteringCharset 'UTF-8'
- filesMatching('plugin.yml') {
- expand props
- }
-
- // This task should never be skipped. The tests depend on this having been run but we want the new version number
- // that is created after tests are run and before we run again to publish.
- outputs.upToDateWhen { false }
-}
-
-
-checkstyle {
- toolVersion = '6.1.1'
- configFile file('config/mv_checks.xml')
- ignoreFailures = true
-}
-
-
-javadoc {
- source = sourceSets.main.allJava
- classpath = configurations.compileClasspath
-}
-
-
-project.configurations.api.canBeResolved = true
-
-shadowJar {
- relocate 'com.dumptruckman.minecraft.util.Logging', 'com.onarandombox.multiverseinventories.utils.InvLogging'
- relocate 'com.dumptruckman.minecraft.util.DebugLog', 'com.onarandombox.multiverseinventories.utils.DebugFileLogger'
- relocate 'com.dumptruckman.bukkit.configuration', 'com.onarandombox.multiverseinventories.utils.configuration'
- relocate 'io.papermc.lib', 'com.onarandombox.multiverseinventories.utils.paperlib'
- relocate 'net.minidev.json', 'com.onarandombox.multiverseinventories.utils.json'
-
- configurations = [project.configurations.api]
-
- archiveFileName = "$baseName-$version.$extension"
-}
-
-build.dependsOn shadowJar
-jar.enabled = false
diff --git a/config/multiverse-banner.png b/config/multiverse-banner.png
new file mode 100644
index 00000000..75877420
Binary files /dev/null and b/config/multiverse-banner.png differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index f398c33c..5c40527d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/settings.gradle b/settings.gradle
index 62b418fb..4a328fcc 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -2,4 +2,13 @@
* This file was generated by the Gradle 'init' task.
*/
+pluginManagement {
+ repositories {
+ gradlePluginPortal()
+ maven {
+ url = uri('https://repo.onarandombox.com/multiverse-releases')
+ }
+ }
+}
+
rootProject.name = 'multiverse-inventories'
diff --git a/src/main/java/com/onarandombox/multiverseinventories/AdventureListener.java b/src/main/java/com/onarandombox/multiverseinventories/AdventureListener.java
deleted file mode 100644
index c17b4524..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/AdventureListener.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.MultiverseAdventure.event.MVAResetFinishedEvent;
-import com.onarandombox.multiverseinventories.profile.container.ProfileContainer;
-import org.bukkit.OfflinePlayer;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-
-/**
- * Listener for Multiverse-Adventure events.
- */
-public class AdventureListener implements Listener {
-
- private MultiverseInventories inventories;
-
- public AdventureListener(MultiverseInventories inventories) {
- this.inventories = inventories;
- }
-
- /**
- * @param event The Multiverse-Adventure event to handle when a world has finished resetting.
- */
- @EventHandler
- public void worldReset(MVAResetFinishedEvent event) {
- ProfileContainer container = inventories.getWorldProfileContainerStore().getContainer(event.getWorld());
- for (OfflinePlayer player : inventories.getServer().getOfflinePlayers()) {
- container.removeAllPlayerData(player);
- }
- Logging.info("Removed all inventories for Multiverse-Adventure world.");
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/CoreDebugListener.java b/src/main/java/com/onarandombox/multiverseinventories/CoreDebugListener.java
deleted file mode 100644
index cd9685d8..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/CoreDebugListener.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.MultiverseCore.event.MVDebugModeEvent;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-
-public class CoreDebugListener implements Listener {
-
- CoreDebugListener(MultiverseInventories plugin) {
- plugin.getServer().getPluginManager().registerEvents(this, plugin);
- }
-
- @EventHandler
- public void onDebugModeChange(MVDebugModeEvent event) {
- Logging.setDebugLevel(event.getLevel());
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/DataStrings.java b/src/main/java/com/onarandombox/multiverseinventories/DataStrings.java
deleted file mode 100644
index baf6bfad..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/DataStrings.java
+++ /dev/null
@@ -1,302 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.dumptruckman.minecraft.util.Logging;
-import net.minidev.json.JSONArray;
-import net.minidev.json.JSONObject;
-import net.minidev.json.parser.JSONParser;
-import net.minidev.json.parser.ParseException;
-import org.bukkit.Bukkit;
-import org.bukkit.Location;
-import org.bukkit.World;
-import org.bukkit.potion.PotionEffect;
-import org.bukkit.potion.PotionEffectType;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * This class handles the formatting of strings for data i/o.
- */
-public class DataStrings {
-
- /**
- * Delimiter to separate a key and it's value.
- */
- public static final String VALUE_DELIMITER = ":";
- /**
- * Player stats identifier.
- */
- public static final String PLAYER_STATS = "stats";
- /**
- * Player inventory contents identifier.
- */
- public static final String PLAYER_INVENTORY_CONTENTS = "inventoryContents";
- /**
- * Player armor contents identifier.
- */
- public static final String PLAYER_ARMOR_CONTENTS = "armorContents";
- /**
- * Player off hand item identifier.
- */
- public static final String PLAYER_OFF_HAND_ITEM = "offHandItem";
- /**
- * Ender chest inventory contents identifier.
- */
- public static final String ENDER_CHEST_CONTENTS = "enderChestContents";
- /**
- * Player bed spawn location identifier.
- */
- public static final String PLAYER_BED_SPAWN_LOCATION = "bedSpawnLocation";
- /**
- * Player last location identifier.
- */
- public static final String PLAYER_LAST_LOCATION = "lastLocation";
- /**
- * Player last world identifier.
- */
- public static final String PLAYER_LAST_WORLD = "lastWorld";
- /**
- * Player should load identifier.
- */
- public static final String PLAYER_SHOULD_LOAD = "shouldLoad";
- /**
- * Player last known name identifier.
- */
- public static final String PLAYER_LAST_KNOWN_NAME = "lastKnownName";
- /**
- * Player profile type identifier.
- */
- public static final String PLAYER_PROFILE_TYPE = "profileType";
- /**
- * Player health identifier.
- */
- public static final String PLAYER_HEALTH = "hp";
- /**
- * Player experience identifier.
- */
- public static final String PLAYER_EXPERIENCE = "xp";
- /**
- * Player total experience identifier.
- */
- public static final String PLAYER_TOTAL_EXPERIENCE = "txp";
- /**
- * Player experience level identifier.
- */
- public static final String PLAYER_LEVEL = "el";
- /**
- * Player food level identifier.
- */
- public static final String PLAYER_FOOD_LEVEL = "fl";
- /**
- * Player exhaustion identifier.
- */
- public static final String PLAYER_EXHAUSTION = "ex";
- /**
- * Player saturation identifier.
- */
- public static final String PLAYER_SATURATION = "sa";
- /**
- * Player fall distance identifier.
- */
- public static final String PLAYER_FALL_DISTANCE = "fd";
- /**
- * Player fire ticks identifier.
- */
- public static final String PLAYER_FIRE_TICKS = "ft";
- /**
- * Player remaining air identifier.
- */
- public static final String PLAYER_REMAINING_AIR = "ra";
- /**
- * Player max air identifier.
- */
- public static final String PLAYER_MAX_AIR = "ma";
- /**
- * Location x identifier.
- */
- public static final String LOCATION_X = "x";
- /**
- * Location y identifier.
- */
- public static final String LOCATION_Y = "y";
- /**
- * Location z identifier.
- */
- public static final String LOCATION_Z = "z";
- /**
- * Location world identifier.
- */
- public static final String LOCATION_WORLD = "wo";
- /**
- * Location pitch identifier.
- */
- public static final String LOCATION_PITCH = "pi";
- /**
- * Location yaw identifier.
- */
- public static final String LOCATION_YAW = "ya";
- /**
- * Potion type identifier.
- */
- public static final String POTION_TYPE = "pt";
- /**
- * Potion duration identifier.
- */
- public static final String POTION_DURATION = "pd";
- /**
- * Potion amplifier identifier.
- */
- public static final String POTION_AMPLIFIER = "pa";
-
- private DataStrings() {
- throw new AssertionError();
- }
-
- /**
- * @param locString Parses this string and creates Location.
- * @return New location object or null if no location could be created.
- * @deprecated Locations do not use special handling because they are
- * {@link org.bukkit.configuration.serialization.ConfigurationSerializable}.
- */
- @Deprecated
- public static Location parseLocation(String locString) {
- if (locString.isEmpty()) {
- return null;
- }
- JSONObject jsonLoc;
- try {
- jsonLoc = (JSONObject) JSON_PARSER.parse(locString);
- } catch (ParseException e) {
- Logging.warning("Could not parse location! " + e.getMessage());
- return null;
- } catch (ClassCastException e) {
- Logging.warning("Could not parse location! " + e.getMessage());
- return null;
- }
- return parseLocMap(jsonLoc);
- }
-
- /**
- * @deprecated Locations do not use special handling because they are
- * {@link org.bukkit.configuration.serialization.ConfigurationSerializable}.
- */
- @Deprecated
- public static Location parseLocation(Map locMap) {
- return parseLocMap(locMap);
- }
-
- @Deprecated
- private static Location parseLocMap(Map locMap) {
- World world = null;
- double x = 0;
- double y = 0;
- double z = 0;
- float pitch = 0;
- float yaw = 0;
- if (locMap.containsKey(LOCATION_WORLD)) {
- world = Bukkit.getWorld(locMap.get(LOCATION_WORLD).toString());
- }
- if (locMap.containsKey(LOCATION_X)) {
- Object value = locMap.get(LOCATION_X);
- if (value instanceof Number) {
- x = ((Number) value).doubleValue();
- }
- }
- if (locMap.containsKey(LOCATION_Y)) {
- Object value = locMap.get(LOCATION_Y);
- if (value instanceof Number) {
- y = ((Number) value).doubleValue();
- }
- }
- if (locMap.containsKey(LOCATION_Z)) {
- Object value = locMap.get(LOCATION_Z);
- if (value instanceof Number) {
- z = ((Number) value).doubleValue();
- }
- }
- if (locMap.containsKey(LOCATION_PITCH)) {
- Object value = locMap.get(LOCATION_PITCH);
- if (value instanceof Number) {
- pitch = ((Number) value).floatValue();
- }
- }
- if (locMap.containsKey(LOCATION_YAW)) {
- Object value = locMap.get(LOCATION_YAW);
- if (value instanceof Number) {
- yaw = ((Number) value).floatValue();
- }
- }
- if (world == null) {
- return null;
- }
- return new Location(world, x, y, z, yaw, pitch);
- }
-
- /**
- * @param potionsString A player's potion effects in string form to be parsed into
- * {@link java.util.Collection}<{@link org.bukkit.potion.PotionEffect}>.
- * @return a collection of potion effects parsed from potionsString.
- * @deprecated PotionEffect do not use special handling because they are
- * {@link org.bukkit.configuration.serialization.ConfigurationSerializable}.
- */
- @Deprecated
- public static PotionEffect[] parsePotionEffects(String potionsString) {
- List potionEffectList = new LinkedList();
- if (potionsString.isEmpty()) {
- return potionEffectList.toArray(new PotionEffect[potionEffectList.size()]);
- }
- JSONArray jsonPotions;
- try {
- jsonPotions = (JSONArray) JSON_PARSER.parse(potionsString);
- } catch (ParseException e) {
- Logging.warning("Could not parse potions! " + e.getMessage());
- return potionEffectList.toArray(new PotionEffect[potionEffectList.size()]);
- } catch (ClassCastException e) {
- Logging.warning("Could not parse potions! " + e.getMessage());
- return potionEffectList.toArray(new PotionEffect[potionEffectList.size()]);
- }
- for (Object obj : jsonPotions) {
- if (obj instanceof JSONObject) {
- JSONObject jsonPotion = (JSONObject) obj;
- int type = -1;
- int duration = -1;
- int amplifier = -1;
- if (jsonPotion.containsKey(POTION_TYPE)) {
- Object value = jsonPotion.get(POTION_TYPE);
- if (value instanceof Number) {
- type = ((Number) value).intValue();
- }
- }
- if (jsonPotion.containsKey(POTION_AMPLIFIER)) {
- Object value = jsonPotion.get(POTION_AMPLIFIER);
- if (value instanceof Number) {
- amplifier = ((Number) value).intValue();
- }
- }
- if (jsonPotion.containsKey(POTION_DURATION)) {
- Object value = jsonPotion.get(POTION_DURATION);
- if (value instanceof Number) {
- duration = ((Number) value).intValue();
- }
- }
- if (type == -1 || duration == -1 || amplifier == -1) {
- Logging.fine("Could not parse potion effect string: " + obj);
- } else {
- PotionEffectType pType = PotionEffectType.getById(type);
- if (pType == null) {
- Logging.warning("Could not parse potion effect type: " + type);
- continue;
- }
- potionEffectList.add(new PotionEffect(pType, duration, amplifier));
- }
- } else {
- Logging.warning("Could not parse potion effect: " + obj);
- }
- }
- return potionEffectList.toArray(new PotionEffect[potionEffectList.size()]);
- }
-
- private static final JSONParser JSON_PARSER = new JSONParser(JSONParser.USE_INTEGER_STORAGE);
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/DefaultMessageProvider.java b/src/main/java/com/onarandombox/multiverseinventories/DefaultMessageProvider.java
deleted file mode 100644
index 71e6b397..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/DefaultMessageProvider.java
+++ /dev/null
@@ -1,248 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.onarandombox.multiverseinventories.locale.LazyLocaleMessageProvider;
-import com.onarandombox.multiverseinventories.locale.LocalizationLoadingException;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.locale.NoSuchLocalizationException;
-import com.onarandombox.multiverseinventories.util.Font;
-import org.bukkit.configuration.file.FileConfiguration;
-import org.bukkit.configuration.file.YamlConfiguration;
-import org.bukkit.plugin.java.JavaPlugin;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-
-/**
- * Implementation of MessageProvider.
- */
-class DefaultMessageProvider implements LazyLocaleMessageProvider {
-
- /**
- * Name of localization folder.
- */
- public static final String LOCALIZATION_FOLDER_NAME = "localization";
-
- private final HashMap>> messages;
- private final JavaPlugin plugin;
-
- private Locale locale = DEFAULT_LOCALE;
-
- public DefaultMessageProvider(JavaPlugin plugin) {
- this.plugin = plugin;
- messages = new HashMap>>();
-
- try {
- loadLocale(locale);
- } catch (NoSuchLocalizationException e) {
- // let's take the defaults from the enum!
- }
- }
-
- /**
- * Tries to load the locale.
- *
- * @param locale Locale to try to load.
- * @throws com.onarandombox.multiverseinventories.locale.LocalizationLoadingException if the Locale could not be loaded.
- */
- public void maybeLoadLocale(Locale locale) throws LocalizationLoadingException {
- if (!isLocaleLoaded(locale)) {
- try {
- loadLocale(locale);
- } catch (NoSuchLocalizationException e) {
- throw e;
- }
- }
- if (!isLocaleLoaded(locale))
- throw new LocalizationLoadingException("Couldn't load the localization: "
- + locale.toString(), locale);
- }
-
- /**
- * Formats a list of strings by passing each through {@link #format(String, Object...)}.
- *
- * @param strings List of strings to format.
- * @param args Arguments to pass in via %n.
- * @return List of formatted strings.
- */
- public List format(List strings, Object... args) {
- List formattedStrings = new ArrayList();
- for (String string : strings) {
- formattedStrings.add(format(string, args));
- }
- return formattedStrings;
- }
-
- /**
- * Formats a string by replacing ampersand with the Section symbol and %n with the corresponding args
- * object where n = argument index + 1.
- *
- * @param string String to format.
- * @param args Arguments to pass in via %n.
- * @return The formatted string.
- */
- public String format(String string, Object... args) {
- // Replaces & with the Section character
- string = string.replaceAll("(&([a-fA-FkK0-9]))", Font.SECTION_SYMBOL + "$2");
- // If there are arguments, %n notations in the message will be
- // replaced
- if (args != null) {
- for (int j = 0; j < args.length; j++) {
- string = string.replace("%" + (j + 1), args[j].toString());
- }
- }
- return string;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void loadLocale(Locale l) throws NoSuchLocalizationException {
- messages.remove(l);
-
- InputStream resstream = null;
- InputStream filestream = null;
-
- try {
- filestream = new FileInputStream(new File(plugin.getDataFolder(), l.getLanguage() + ".yml"));
- } catch (FileNotFoundException e) {
- }
-
- try {
- resstream = plugin.getResource(new StringBuilder(LOCALIZATION_FOLDER_NAME).append("/")
- .append(l.getLanguage()).append(".yml").toString());
- } catch (Exception e) {
- }
-
- if ((resstream == null) && (filestream == null))
- throw new NoSuchLocalizationException(l);
-
- messages.put(l, new HashMap>(Message.values().length));
-
- FileConfiguration resconfig = (resstream == null) ? null : YamlConfiguration.loadConfiguration(new InputStreamReader(resstream));
- FileConfiguration fileconfig = (filestream == null) ? null : YamlConfiguration.loadConfiguration(new InputStreamReader(filestream));
- for (Message m : Message.values()) {
- List values = m.getDefault();
-
- if (resconfig != null) {
- if (resconfig.isList(m.toString())) {
- values = resconfig.getStringList(m.toString());
- } else {
- values.add(resconfig.getString(m.toString(), values.get(0)));
- }
- }
- if (fileconfig != null) {
- if (fileconfig.isList(m.toString())) {
- values = fileconfig.getStringList(m.toString());
- } else {
- values.add(fileconfig.getString(m.toString(), values.get(0)));
- }
- }
-
- messages.get(l).put(m, values);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Set getLoadedLocales() {
- return messages.keySet();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isLocaleLoaded(Locale l) {
- return messages.containsKey(l);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getMessage(Message key, Object... args) {
- if (!isLocaleLoaded(locale)) {
- return format(key.getDefault().get(0), args);
- } else
- return format(messages.get(locale).get(key).get(0), args);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getMessage(Message key, Locale locale, Object... args) {
- try {
- maybeLoadLocale(locale);
- } catch (LocalizationLoadingException e) {
- e.printStackTrace();
- return getMessage(key, args);
- }
- return format(messages.get(locale).get(key).get(0), args);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public List getMessages(Message key, Object... args) {
- List result;
- if (!isLocaleLoaded(locale)) {
- result = format(key.getDefault(), args);
- } else {
- result = format(this.messages.get(locale).get(key), args);
- }
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public List getMessages(Message key, Locale locale, Object... args) {
- try {
- maybeLoadLocale(locale);
- } catch (LocalizationLoadingException e) {
- e.printStackTrace();
- return format(getMessages(key), args);
- }
- return format(messages.get(locale).get(key), args);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Locale getLocale() {
- return locale;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setLocale(Locale locale) {
- if (locale == null)
- throw new IllegalArgumentException("Can't set locale to null!");
- try {
- maybeLoadLocale(locale);
- } catch (LocalizationLoadingException e) {
- if (!locale.equals(DEFAULT_LOCALE))
- throw new IllegalArgumentException("Error while trying to load localization for the given Locale!", e);
- }
-
- this.locale = locale;
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/DefaultMessager.java b/src/main/java/com/onarandombox/multiverseinventories/DefaultMessager.java
deleted file mode 100644
index 57008559..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/DefaultMessager.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.onarandombox.multiverseinventories.locale.MessageProvider;
-import com.onarandombox.multiverseinventories.locale.Messager;
-import com.onarandombox.multiverseinventories.locale.Message;
-import org.bukkit.ChatColor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.plugin.java.JavaPlugin;
-
-import java.util.List;
-
-/**
- * Implementation of a Messager and MessageProvider using DefaultMessageProvider to implement the latter.
- */
-final class DefaultMessager extends DefaultMessageProvider implements Messager, MessageProvider {
-
- public DefaultMessager(JavaPlugin plugin) {
- super(plugin);
- }
-
- private void send(Message message, String prefix, CommandSender sender, Object... args) {
- List messages = this.getMessages(message, args);
- if (!messages.isEmpty()) {
- messages.set(0, prefix + " " + messages.get(0));
- sendMessages(sender, messages);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void bad(Message message, CommandSender sender, Object... args) {
- send(message, ChatColor.RED.toString() + this.getMessage(Message.GENERIC_ERROR), sender, args);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void normal(Message message, CommandSender sender, Object... args) {
- send(message, "", sender, args);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void good(Message message, CommandSender sender, Object... args) {
- send(message, ChatColor.GREEN.toString() + this.getMessage(Message.GENERIC_SUCCESS), sender, args);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void info(Message message, CommandSender sender, Object... args) {
- send(message, ChatColor.YELLOW.toString() + this.getMessage(Message.GENERIC_INFO), sender, args);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void help(Message message, CommandSender sender, Object... args) {
- send(message, ChatColor.GRAY.toString() + this.getMessage(Message.GENERIC_HELP), sender, args);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void sendMessage(CommandSender player, String message) {
- List messages = com.onarandombox.multiverseinventories.util.Font.splitString(message);
- sendMessages(player, messages);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void sendMessages(CommandSender player, List messages) {
- for (String s : messages) {
- player.sendMessage(s);
- }
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/DefaultPersistingProfile.java b/src/main/java/com/onarandombox/multiverseinventories/DefaultPersistingProfile.java
deleted file mode 100644
index 186b5916..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/DefaultPersistingProfile.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.onarandombox.multiverseinventories.profile.PlayerProfile;
-import com.onarandombox.multiverseinventories.share.PersistingProfile;
-import com.onarandombox.multiverseinventories.share.Shares;
-
-/**
- * Simple implementation of PersistingProfile.
- */
-final class DefaultPersistingProfile implements PersistingProfile {
-
- private Shares shares;
- private PlayerProfile profile;
-
- public DefaultPersistingProfile(Shares shares, PlayerProfile profile) {
- this.shares = shares;
- this.profile = profile;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Shares getShares() {
- return this.shares;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public PlayerProfile getProfile() {
- return this.profile;
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/FlatFileProfileDataSource.java b/src/main/java/com/onarandombox/multiverseinventories/FlatFileProfileDataSource.java
deleted file mode 100644
index 040d31f6..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/FlatFileProfileDataSource.java
+++ /dev/null
@@ -1,598 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.dumptruckman.bukkit.configuration.json.JsonConfiguration;
-import com.dumptruckman.minecraft.util.Logging;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.onarandombox.multiverseinventories.profile.ProfileDataSource;
-import com.onarandombox.multiverseinventories.profile.ProfileKey;
-import com.onarandombox.multiverseinventories.profile.ProfileTypes;
-import com.onarandombox.multiverseinventories.share.ProfileEntry;
-import com.onarandombox.multiverseinventories.share.Sharable;
-import com.onarandombox.multiverseinventories.share.SharableEntry;
-import com.onarandombox.multiverseinventories.profile.container.ContainerType;
-import com.onarandombox.multiverseinventories.profile.GlobalProfile;
-import com.onarandombox.multiverseinventories.profile.PlayerProfile;
-import com.onarandombox.multiverseinventories.profile.ProfileType;
-import net.minidev.json.JSONObject;
-import org.bukkit.Bukkit;
-import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.configuration.file.FileConfiguration;
-import org.json.simple.parser.JSONParser;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-
-class FlatFileProfileDataSource implements ProfileDataSource {
-
- private static final String JSON = ".json";
-
- private final JSONParser JSON_PARSER = new JSONParser();
-
- private final ExecutorService fileIOExecutorService = Executors.newSingleThreadExecutor();
-
- // TODO these probably need configurable max sizes
- private final Cache profileCache = CacheBuilder.newBuilder()
- .expireAfterAccess(10, TimeUnit.MINUTES)
- .maximumSize(1000)
- .build();
- private final Cache globalProfileCache = CacheBuilder.newBuilder()
- .expireAfterAccess(10, TimeUnit.MINUTES)
- .maximumSize(500)
- .build();
-
- private final File worldFolder;
- private final File groupFolder;
- private final File playerFolder;
-
- FlatFileProfileDataSource(MultiverseInventories plugin) throws IOException {
- // Make the data folders
- plugin.getDataFolder().mkdirs();
-
- // Check if the data file exists. If not, create it.
- this.worldFolder = new File(plugin.getDataFolder(), "worlds");
- if (!this.worldFolder.exists()) {
- if (!this.worldFolder.mkdirs()) {
- throw new IOException("Could not create world folder!");
- }
- }
- this.groupFolder = new File(plugin.getDataFolder(), "groups");
- if (!this.groupFolder.exists()) {
- if (!this.groupFolder.mkdirs()) {
- throw new IOException("Could not create group folder!");
- }
- }
- this.playerFolder = new File(plugin.getDataFolder(), "players");
- if (!this.playerFolder.exists()) {
- if (!this.playerFolder.mkdirs()) {
- throw new IOException("Could not create player folder!");
- }
- }
- }
-
- private FileConfiguration waitForConfigHandle(File file) {
- Future future = fileIOExecutorService.submit(new ConfigLoader(file));
- while (true) {
- try {
- return future.get();
- } catch (InterruptedException | ExecutionException e) {
- e.printStackTrace();
- }
- }
- }
-
- private static FileConfiguration getConfigHandleNow(File file) {
- return JsonConfiguration.loadConfiguration(file);
- }
-
- private static class ConfigLoader implements Callable {
- private final File file;
-
- private ConfigLoader(File file) {
- this.file = file;
- }
-
- @Override
- public FileConfiguration call() throws Exception {
- return getConfigHandleNow(file);
- }
- }
-
- private File getFolder(ContainerType type, String folderName) {
- File folder;
- switch (type) {
- case GROUP:
- folder = new File(this.groupFolder, folderName);
- break;
- case WORLD:
- folder = new File(this.worldFolder, folderName);
- break;
- default:
- folder = new File(this.worldFolder, folderName);
- break;
- }
-
- if (!folder.exists()) {
- folder.mkdirs();
- }
- return folder;
- }
-
- /**
- * Retrieves the data file for a player based on a given world/group name, creating it if necessary.
- *
- * @param type Indicates whether data is for group or world.
- * @param dataName The name of the group or world.
- * @param playerName The name of the player.
- * @return The data file for a player.
- * @throws IOException if there was a problem creating the file.
- */
- File getPlayerFile(ContainerType type, String dataName, String playerName) throws IOException {
- File jsonPlayerFile = new File(this.getFolder(type, dataName), playerName + JSON);
- if (!jsonPlayerFile.exists()) {
- try {
- jsonPlayerFile.createNewFile();
- } catch (IOException e) {
- throw new IOException("Could not create necessary player data file: " + jsonPlayerFile.getPath()
- + ". Data for " + playerName + " in " + type.name().toLowerCase() + " " + dataName
- + " may not be saved.", e);
- }
- }
- Logging.finer("got data file: %s. Type: %s, DataName: %s, PlayerName: %s",
- jsonPlayerFile.getPath(), type, dataName, playerName);
- return jsonPlayerFile;
- }
-
- /**
- * Retrieves the data file for a player for their global data, creating it if necessary.
- *
- * @param fileName The name of the file (player name or UUID) without extension.
- * @param createIfMissing If true, the file will be created it it does not exist.
- * @return The data file for a player.
- * @throws IOException if there was a problem creating the file.
- */
- File getGlobalFile(String fileName, boolean createIfMissing) throws IOException {
- File jsonPlayerFile = new File(playerFolder, fileName + JSON);
- if (createIfMissing && !jsonPlayerFile.exists()) {
- try {
- jsonPlayerFile.createNewFile();
- } catch (IOException e) {
- throw new IOException("Could not create necessary player file: " + jsonPlayerFile.getPath() + ". "
- + "There may be issues with " + fileName + "'s metadata", e);
- }
- }
- return jsonPlayerFile;
- }
-
- private void queueWrite(PlayerProfile profile) {
- fileIOExecutorService.submit(new FileWriter(profile.clone()));
- }
-
- private class FileWriter implements Callable {
- private final PlayerProfile profile;
-
- private FileWriter(PlayerProfile profile) {
- this.profile = profile;
- }
-
- @Override
- public Void call() throws Exception {
- processProfileWrite(profile);
- return null;
- }
- }
-
- private void processProfileWrite(PlayerProfile playerProfile) {
- try {
- File playerFile = this.getPlayerFile(playerProfile.getContainerType(),
- playerProfile.getContainerName(), playerProfile.getPlayer().getName());
- FileConfiguration playerData = getConfigHandleNow(playerFile);
- playerData.createSection(playerProfile.getProfileType().getName(), serializePlayerProfile(playerProfile));
- try {
- playerData.save(playerFile);
- } catch (IOException e) {
- Logging.severe("Could not save data for player: " + playerProfile.getPlayer().getName()
- + " for " + playerProfile.getContainerType().toString() + ": " + playerProfile.getContainerName());
- Logging.severe(e.getMessage());
- }
- } catch (final Exception e) {
- Logging.getLogger().log(Level.WARNING, "Error while attempting to write profile data.", e);
- }
- }
-
- private Map serializePlayerProfile(PlayerProfile playerProfile) {
- Map playerData = new LinkedHashMap();
- JSONObject jsonStats = new JSONObject();
- for (SharableEntry entry : playerProfile) {
- if (entry.getValue() != null) {
- if (entry.getSharable().getSerializer() == null) {
- continue;
- }
- Sharable sharable = entry.getSharable();
- if (sharable.getProfileEntry().isStat()) {
- jsonStats.put(sharable.getProfileEntry().getFileTag(),
- sharable.getSerializer().serialize(entry.getValue()));
- } else {
- playerData.put(sharable.getProfileEntry().getFileTag(),
- sharable.getSerializer().serialize(entry.getValue()));
- }
- }
- }
- if (!jsonStats.isEmpty()) {
- playerData.put(DataStrings.PLAYER_STATS, jsonStats);
- }
- return playerData;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void updatePlayerData(PlayerProfile playerProfile) {
- queueWrite(playerProfile);
- }
-
- private PlayerProfile getPlayerData(ProfileKey key) {
- PlayerProfile cached = profileCache.getIfPresent(key);
- if (cached != null) {
- return cached;
- }
- File playerFile = null;
- try {
- playerFile = getPlayerFile(key.getContainerType(), key.getDataName(), key.getPlayerName());
- } catch (IOException e) {
- e.printStackTrace();
- // Return an empty profile
- return PlayerProfile.createPlayerProfile(key.getContainerType(), key.getDataName(), key.getProfileType(),
- Bukkit.getOfflinePlayer(key.getPlayerUUID()));
- }
- FileConfiguration playerData = this.waitForConfigHandle(playerFile);
- if (convertConfig(playerData)) {
- try {
- playerData.save(playerFile);
- } catch (IOException e) {
- Logging.severe("Could not save data for player: " + key.getPlayerName()
- + " for " + key.getContainerType().toString() + ": " + key.getDataName() + " after conversion.");
- Logging.severe(e.getMessage());
- }
- }
- ConfigurationSection section = playerData.getConfigurationSection(key.getProfileType().getName());
- if (section == null) {
- section = playerData.createSection(key.getProfileType().getName());
- }
- PlayerProfile result = deserializePlayerProfile(key, convertSection(section));
- profileCache.put(key, result);
- return result;
- }
-
- @Override
- public PlayerProfile getPlayerData(ContainerType containerType, String dataName, ProfileType profileType, UUID playerUUID) {
- return getPlayerData(ProfileKey.createProfileKey(containerType, dataName, profileType, playerUUID));
- }
-
- private PlayerProfile deserializePlayerProfile(ProfileKey pKey, Map playerData) {
- PlayerProfile profile = PlayerProfile.createPlayerProfile(pKey.getContainerType(), pKey.getDataName(),
- pKey.getProfileType(), Bukkit.getOfflinePlayer(pKey.getPlayerUUID()));
- for (Object keyObj : playerData.keySet()) {
- String key = keyObj.toString();
- if (key.equalsIgnoreCase(DataStrings.PLAYER_STATS)) {
- final Object statsObject = playerData.get(key);
- if (statsObject instanceof String) {
- parseJsonPlayerStatsIntoProfile(statsObject.toString(), profile);
- } else {
- if (statsObject instanceof Map) {
- parsePlayerStatsIntoProfile((Map) statsObject, profile);
- } else {
- Logging.warning("Could not parse stats for " + pKey.getPlayerName());
- }
- }
- } else {
- if (playerData.get(key) == null) {
- Logging.fine("Player data '" + key + "' is null for: " + pKey.getPlayerName());
- continue;
- }
- try {
- Sharable sharable = ProfileEntry.lookup(false, key);
- if (sharable == null) {
- Logging.fine("Player fileTag '" + key + "' is unrecognized!");
- continue;
- }
- profile.set(sharable, sharable.getSerializer().deserialize(playerData.get(key)));
- } catch (Exception e) {
- Logging.fine("Could not parse fileTag: '" + key + "' with value '" + playerData.get(key) + "'");
- Logging.getLogger().log(Level.FINE, "Exception: ", e);
- e.printStackTrace();
- }
- }
- }
- Logging.finer("Created player profile from map for '" + pKey.getPlayerName() + "'.");
- return profile;
- }
-
- private void parsePlayerStatsIntoProfile(Map stats, PlayerProfile profile) {
- for (Object key : stats.keySet()) {
- Sharable sharable = ProfileEntry.lookup(true, key.toString());
- if (sharable != null) {
- profile.set(sharable, sharable.getSerializer().deserialize(stats.get(key).toString()));
- } else {
- Logging.warning("Could not parse stat: '" + key + "' for player '"
- + profile.getPlayer().getName() + "' for " + profile.getContainerType() + " '"
- + profile.getContainerName() + "'");
- }
- }
- }
-
- private void parseJsonPlayerStatsIntoProfile(String stats, PlayerProfile profile) {
- if (stats.isEmpty()) {
- return;
- }
- org.json.simple.JSONObject jsonStats = null;
- try {
- jsonStats = (org.json.simple.JSONObject) JSON_PARSER.parse(stats);
- } catch (org.json.simple.parser.ParseException e) {
- Logging.warning("Could not parse stats for player'" + profile.getPlayer().getName() + "' for " +
- profile.getContainerType() + " '" + profile.getContainerName() + "': " + e.getMessage());
- } catch (ClassCastException e) {
- Logging.warning("Could not parse stats for player'" + profile.getPlayer().getName() + "' for " +
- profile.getContainerType() + " '" + profile.getContainerName() + "': " + e.getMessage());
- }
- if (jsonStats == null) {
- Logging.warning("Could not parse stats for player'" + profile.getPlayer().getName() + "' for " +
- profile.getContainerType() + " '" + profile.getContainerName() + "'");
- return;
- }
- parsePlayerStatsIntoProfile(jsonStats, profile);
- }
-
- // TODO Remove this conversion
- private boolean convertConfig(FileConfiguration config) {
- ConfigurationSection section = config.getConfigurationSection("playerData");
- if (section != null) {
- config.set(ProfileTypes.SURVIVAL.getName(), section);
- config.set(ProfileTypes.CREATIVE.getName(), section);
- config.set(ProfileTypes.ADVENTURE.getName(), section);
- config.set("playerData", null);
- Logging.finer("Migrated old player data to new multi-profile format");
- return true;
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean removePlayerData(ContainerType containerType, String dataName, ProfileType profileType, String playerName) {
- if (profileType == null) {
- try {
- File playerFile = getPlayerFile(containerType, dataName, playerName);
- return playerFile.delete();
- } catch (IOException ignore) {
- Logging.warning("Attempted to delete file that did not exist for player " + playerName
- + " in " + containerType.name().toLowerCase() + " " + dataName);
- return false;
- }
- } else {
- File playerFile;
- try {
- playerFile = getPlayerFile(containerType, dataName, playerName);
- } catch (IOException e) {
- Logging.warning("Attempted to delete " + playerName + "'s data for "
- + profileType.getName().toLowerCase() + " mode in " + containerType.name().toLowerCase()
- + " " + dataName + " but the file did not exist.");
- return false;
- }
- FileConfiguration playerData = this.waitForConfigHandle(playerFile);
- playerData.set(profileType.getName(), null);
- try {
- playerData.save(playerFile);
- } catch (IOException e) {
- Logging.severe("Could not delete data for player: " + playerName
- + " for " + containerType.toString() + ": " + dataName);
- Logging.severe(e.getMessage());
- return false;
- }
- return true;
- }
- }
-
- private Map convertSection(ConfigurationSection section) {
- Map resultMap = new HashMap();
- for (String key : section.getKeys(false)) {
- Object obj = section.get(key);
- if (obj instanceof ConfigurationSection) {
- resultMap.put(key, convertSection((ConfigurationSection) obj));
- } else {
- resultMap.put(key, obj);
- }
- }
- return resultMap;
- }
-
- @Override
- @Deprecated
- public GlobalProfile getGlobalProfile(String playerName) {
- return getGlobalProfile(playerName, Bukkit.getOfflinePlayer(playerName).getUniqueId());
- }
-
- @Override
- public GlobalProfile getGlobalProfile(String playerName, UUID playerUUID) {
- GlobalProfile cached = globalProfileCache.getIfPresent(playerUUID);
- if (cached != null) {
- return cached;
- }
- File playerFile;
-
- // Migrate old data if necessary
- try {
- playerFile = getGlobalFile(playerName, false);
- } catch (IOException e) {
- // This won't ever happen
- e.printStackTrace();
- return GlobalProfile.createGlobalProfile(playerName);
- }
- if (playerFile.exists()) {
- GlobalProfile profile = loadGlobalProfile(playerFile, playerName, playerUUID);
- if (!migrateGlobalProfileToUUID(profile, playerFile)) {
- Logging.warning("Could not properly migrate player global data file for " + playerName);
- }
- globalProfileCache.put(playerUUID, profile);
- return profile;
- }
-
- // Load current format
- try {
- playerFile = getGlobalFile(playerUUID.toString(), true);
- } catch (IOException e) {
- e.printStackTrace();
- return GlobalProfile.createGlobalProfile(playerName, playerUUID);
- }
- GlobalProfile profile = loadGlobalProfile(playerFile, playerName, playerUUID);
- globalProfileCache.put(playerUUID, profile);
- return profile;
- }
-
- private boolean migrateGlobalProfileToUUID(GlobalProfile profile, File playerFile) {
- updateGlobalProfile(profile);
- return playerFile.delete();
- }
-
- private GlobalProfile loadGlobalProfile(File playerFile, String playerName, UUID playerUUID) {
- FileConfiguration playerData = this.waitForConfigHandle(playerFile);
- ConfigurationSection section = playerData.getConfigurationSection("playerData");
- if (section == null) {
- section = playerData.createSection("playerData");
- }
- return deserializeGlobalProfile(playerName, playerUUID, convertSection(section));
- }
-
- private GlobalProfile deserializeGlobalProfile(String playerName, UUID playerUUID,
- Map playerData) {
- GlobalProfile globalProfile = GlobalProfile.createGlobalProfile(playerName, playerUUID);
- for (String key : playerData.keySet()) {
- if (key.equalsIgnoreCase(DataStrings.PLAYER_LAST_WORLD)) {
- globalProfile.setLastWorld(playerData.get(key).toString());
- } else if (key.equalsIgnoreCase(DataStrings.PLAYER_SHOULD_LOAD)) {
- globalProfile.setLoadOnLogin(Boolean.valueOf(playerData.get(key).toString()));
- } else if (key.equalsIgnoreCase(DataStrings.PLAYER_LAST_KNOWN_NAME)) {
- globalProfile.setLastKnownName(playerData.get(key).toString());
- }
- }
- return globalProfile;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean updateGlobalProfile(GlobalProfile globalProfile) {
- File playerFile = null;
- try {
- playerFile = this.getGlobalFile(globalProfile.getPlayerUUID().toString(), true);
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- }
- FileConfiguration playerData = this.waitForConfigHandle(playerFile);
- playerData.createSection("playerData", serializeGlobalProfile(globalProfile));
- try {
- playerData.save(playerFile);
- } catch (IOException e) {
- Logging.severe("Could not save global data for player: " + globalProfile);
- Logging.severe(e.getMessage());
- return false;
- }
- return true;
- }
-
- private Map serializeGlobalProfile(GlobalProfile profile) {
- Map result = new HashMap(2);
- if (profile.getLastWorld() != null) {
- result.put(DataStrings.PLAYER_LAST_WORLD, profile.getLastWorld());
- }
- result.put(DataStrings.PLAYER_SHOULD_LOAD, profile.shouldLoadOnLogin());
- result.put(DataStrings.PLAYER_LAST_KNOWN_NAME, profile.getLastKnownName());
- return result;
- }
-
- @Override
- @Deprecated
- // TODO replace for UUID
- public void updateLastWorld(String playerName, String worldName) {
- GlobalProfile globalProfile = getGlobalProfile(playerName);
- globalProfile.setLastWorld(worldName);
- updateGlobalProfile(globalProfile);
- }
-
- @Override
- @Deprecated
- // TODO replace for UUID
- public void setLoadOnLogin(final String playerName, final boolean loadOnLogin) {
- final GlobalProfile globalProfile = getGlobalProfile(playerName);
- globalProfile.setLoadOnLogin(loadOnLogin);
- updateGlobalProfile(globalProfile);
- }
-
- @Override
- public void migratePlayerData(String oldName, String newName, UUID uuid, boolean removeOldData) throws IOException {
- File[] worldFolders = worldFolder.listFiles(File::isDirectory);
- if (worldFolders == null) {
- throw new IOException("Could not enumerate world folders");
- }
- File[] groupFolders = groupFolder.listFiles(File::isDirectory);
- if (groupFolders == null) {
- throw new IOException("Could not enumerate group folders");
- }
-
- for (File worldFolder : worldFolders) {
- ProfileKey key = ProfileKey.createProfileKey(ContainerType.WORLD, worldFolder.getName(),
- ProfileTypes.ADVENTURE, uuid, oldName);
- updatePlayerData(getPlayerData(key));
- updatePlayerData(getPlayerData(ProfileKey.createProfileKey(key, ProfileTypes.CREATIVE)));
- updatePlayerData(getPlayerData(ProfileKey.createProfileKey(key, ProfileTypes.SURVIVAL)));
- }
-
- for (File groupFolder : groupFolders) {
- ProfileKey key = ProfileKey.createProfileKey(ContainerType.GROUP, groupFolder.getName(),
- ProfileTypes.ADVENTURE, uuid, oldName);
- updatePlayerData(getPlayerData(key));
- updatePlayerData(getPlayerData(ProfileKey.createProfileKey(key, ProfileTypes.CREATIVE)));
- updatePlayerData(getPlayerData(ProfileKey.createProfileKey(key, ProfileTypes.SURVIVAL)));
- }
-
- if (removeOldData) {
- for (File worldFolder : worldFolders) {
- removePlayerData(ContainerType.WORLD, worldFolder.getName(), ProfileTypes.ADVENTURE, oldName);
- removePlayerData(ContainerType.WORLD, worldFolder.getName(), ProfileTypes.CREATIVE, oldName);
- removePlayerData(ContainerType.WORLD, worldFolder.getName(), ProfileTypes.SURVIVAL, oldName);
- }
- for (File groupFolder : groupFolders) {
- removePlayerData(ContainerType.GROUP, groupFolder.getName(), ProfileTypes.ADVENTURE, oldName);
- removePlayerData(ContainerType.GROUP, groupFolder.getName(), ProfileTypes.CREATIVE, oldName);
- removePlayerData(ContainerType.GROUP, groupFolder.getName(), ProfileTypes.SURVIVAL, oldName);
- }
- }
- }
-
- @Override
- public void clearProfileCache(ProfileKey key) {
- profileCache.invalidate(key);
- }
-
- void clearCache() {
- globalProfileCache.invalidateAll();
- profileCache.invalidateAll();
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/GameModeShareHandler.java b/src/main/java/com/onarandombox/multiverseinventories/GameModeShareHandler.java
deleted file mode 100644
index 55434da2..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/GameModeShareHandler.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.multiverseinventories.event.GameModeChangeShareHandlingEvent;
-import com.onarandombox.multiverseinventories.event.ShareHandlingEvent;
-import com.onarandombox.multiverseinventories.profile.ProfileType;
-import com.onarandombox.multiverseinventories.profile.ProfileTypes;
-import com.onarandombox.multiverseinventories.profile.container.ProfileContainer;
-import com.onarandombox.multiverseinventories.share.Sharables;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.GameMode;
-import org.bukkit.entity.Player;
-
-import java.util.List;
-
-/**
- * GameMode change implementation of ShareHandler.
- */
-final class GameModeShareHandler extends ShareHandler {
-
- private final GameMode fromGameMode;
- private final GameMode toGameMode;
- private final ProfileType fromType;
- private final ProfileType toType;
- private final String world;
- private final ProfileContainer worldProfileContainer;
- private final List worldGroups;
-
- GameModeShareHandler(MultiverseInventories inventories, Player player,
- GameMode fromGameMode, GameMode toGameMode) {
- super(inventories, player);
- this.fromGameMode = fromGameMode;
- this.toGameMode = toGameMode;
- this.fromType = ProfileTypes.forGameMode(fromGameMode);
- this.toType = ProfileTypes.forGameMode(toGameMode);
- this.world = player.getWorld().getName();
- this.worldProfileContainer = inventories.getWorldProfileContainerStore().getContainer(world);
- this.worldGroups = getAffectedWorldGroups();
-
- prepareProfiles();
- }
-
- private List getAffectedWorldGroups() {
- return this.inventories.getGroupManager().getGroupsForWorld(world);
- }
-
- @Override
- protected ShareHandlingEvent createEvent() {
- return new GameModeChangeShareHandlingEvent(player, affectedProfiles, fromGameMode, toGameMode);
- }
-
- private void prepareProfiles() {
- Logging.finer("=== " + player.getName() + " changing game mode from: " + fromType
- + " to: " + toType + " for world: " + world + " ===");
-
- setAlwaysWriteProfile(worldProfileContainer.getPlayerData(fromType, player));
-
- if (isPlayerAffectedByChange()) {
- addProfiles();
- }
- }
-
- private boolean isPlayerAffectedByChange() {
- if (isPlayerBypassingChange()) {
- logBypass();
- return false;
- }
- return true;
- }
-
- private boolean isPlayerBypassingChange() {
- return Perm.BYPASS_WORLD.hasBypass(player, world)
- || Perm.BYPASS_GAME_MODE.hasBypass(player, toGameMode.name().toLowerCase());
- }
-
- private void addProfiles() {
- if (hasWorldGroups()) {
- worldGroups.forEach(this::addProfilesForWorldGroup);
- } else {
- Logging.finer("No groups for world.");
- addReadProfile(worldProfileContainer.getPlayerData(toType, player), Sharables.allOf());
- }
- }
-
- private boolean hasWorldGroups() {
- return !worldGroups.isEmpty();
- }
-
- private void addProfilesForWorldGroup(WorldGroup worldGroup) {
- ProfileContainer container = worldGroup.getGroupProfileContainer();
- addWriteProfile(container.getPlayerData(fromType, player), Sharables.allOf());
- addReadProfile(container.getPlayerData(toType, player), Sharables.allOf());
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/InventoriesConfig.java b/src/main/java/com/onarandombox/multiverseinventories/InventoriesConfig.java
deleted file mode 100644
index 867e1a97..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/InventoriesConfig.java
+++ /dev/null
@@ -1,332 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.multiverseinventories.share.Sharables;
-import com.onarandombox.multiverseinventories.share.Shares;
-import com.onarandombox.multiverseinventories.util.CommentedYamlConfiguration;
-import io.papermc.lib.PaperLib;
-import org.bukkit.configuration.file.FileConfiguration;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Provides methods for interacting with the configuration of Multiverse-Inventories.
- */
-public final class InventoriesConfig {
-
- /**
- * Enum for easily keeping track of config paths, defaults and comments.
- */
- public enum Path {
- /**
- * Locale name config path, default and comments.
- */
- LANGUAGE_FILE_NAME("settings.locale", "en", "# This is the locale you wish to use."),
- /**
- * First Run flag config path, default and comments.
- */
- FIRST_RUN("settings.first_run", true, "# If this is true it will generate world groups for you based on MV worlds."),
- /**
- * First Run flag config path, default and comments.
- */
- USE_BYPASS("settings.use_bypass", false, "# If this is set to true, it will enable bypass permissions (Check the wiki for more info.)"),
-
- /**
- * Whether or not to make ungrouped worlds use the default group.
- */
- DEFAULT_UNGROUPED_WORLDS("settings.default_ungrouped_worlds", false, "# If set to true, any world not listed in a group will automatically use the settings for the default group!"),
-
- /**
- * Whether or not to save/load player data on log out/in.
- */
- LOGGING_SAVE_LOAD("settings.save_load_on_log_in_out", false,
- "# The default and suggested setting for this is FALSE.",
- "# False means Multiverse-Inventories will not attempt to load or save any player data when they log in and out.",
- "# That means that MINECRAFT will handle that exact thing JUST LIKE IT DOES NORMALLY.",
- "# Changing this to TRUE will have Multiverse-Inventories save player data when they log out and load it when they log in.",
- "# The biggest potential drawback here is that if your server crashes, player stats/inventories may be lost/rolled back!"),
-
- USE_OPTIONALS_UNGROUPED("shares.optionals_for_ungrouped_worlds", true,
- "# When set to true, optional shares WILL be utilized in cases where a group does not cover their uses for a world.",
- "# An example of this in action would be an ungrouped world using last_location. When this is true, players will return to their last location in that world.",
- "# When set to false, optional shares WILL NOt be utilized in these cases, effectively disabling it for ungrouped worlds."),
- /**
- * First Run flag config path, default and comments.
- */
- OPTIONAL_SHARES("shares.use_optionals", new ArrayList(),
- "# You must specify optional shares you wish to use here or they will be ignored.",
- "# The only built in optional shares are \"economy\" and \"last_location\"."),
- /**
- * Whether or not to split data based on game modes.
- */
- USE_GAME_MODE_PROFILES("settings.use_game_mode_profiles", false,
- "# If this is set to true, players will have different inventories/stats for each game mode.",
- "# Please note that old data migrated to the version that has this feature will have their data copied for both game modes.");
-
- private String path;
- private Object def;
- private List comments;
-
- Path(String path, Object def, String... comments) {
- this.path = path;
- this.def = def;
- this.comments = Arrays.asList(comments);
- }
-
- /**
- * Retrieves the path for a config option.
- *
- * @return The path for a config option.
- */
- private String getPath() {
- return this.path;
- }
-
- /**
- * Retrieves the default value for a config path.
- *
- * @return The default value for a config path.
- */
- private Object getDefault() {
- return this.def;
- }
-
- /**
- * Retrieves the comment for a config path.
- *
- * @return The comments for a config path.
- */
- private List getComments() {
- return this.comments;
- }
- }
-
- private final CommentedYamlConfiguration config;
- private final MultiverseInventories plugin;
-
- InventoriesConfig(MultiverseInventories plugin) throws IOException {
- this.plugin = plugin;
- // Make the data folders
- if (plugin.getDataFolder().mkdirs()) {
- Logging.fine("Created data folder.");
- }
-
- // Check if the config file exists. If not, create it.
- File configFile = new File(plugin.getDataFolder(), "config.yml");
- boolean configFileExists = configFile.exists();
- if (!configFileExists) {
- Logging.fine("Created config file.");
- configFile.createNewFile();
- }
-
- // Load the configuration file into memory
- boolean supportsCommentsNatively = PaperLib.getMinecraftVersion() > 17;
- config = new CommentedYamlConfiguration(configFile, !configFileExists || !supportsCommentsNatively);
-
- // Sets defaults config values
- this.setDefaults();
-
- config.getConfig().options().header("Multiverse-Inventories Settings");
-
- // Saves the configuration from memory to file
- config.save();
-
- Logging.setDebugLevel(this.getGlobalDebug());
- }
-
-
- /**
- * Loads default settings for any missing config values.
- */
- private void setDefaults() {
- for (InventoriesConfig.Path path : InventoriesConfig.Path.values()) {
- config.addComment(path.getPath(), path.getComments());
- if (this.getConfig().get(path.getPath()) == null) {
- if (path.getDefault() != null) {
- Logging.fine("Config: Defaulting '" + path.getPath() + "' to " + path.getDefault());
- this.getConfig().set(path.getPath(), path.getDefault());
- } else {
- this.getConfig().createSection(path.getPath());
- }
- }
- }
-
- }
-
- private Boolean getBoolean(Path path) {
- return this.getConfig().getBoolean(path.getPath(), (Boolean) path.getDefault());
- }
-
- private Integer getInt(Path path) {
- return this.getConfig().getInt(path.getPath(), (Integer) path.getDefault());
- }
-
- private String getString(Path path) {
- return this.getConfig().getString(path.getPath(), (String) path.getDefault());
- }
-
- FileConfiguration getConfig() {
- return this.config.getConfig();
- }
-
- /**
- * Sets globalDebug level.
- *
- * @param globalDebug The new value. 0 = off.
- */
- public void setGlobalDebug(int globalDebug) {
- plugin.getCore().getMVConfig().setGlobalDebug(globalDebug);
- }
-
- /**
- * Gets globalDebug level.
- *
- * @return globalDebug.
- */
- public int getGlobalDebug() {
- return plugin.getCore().getMVConfig().getGlobalDebug();
- }
-
- /**
- * Retrieves the locale string from the config.
- *
- * @return The locale string.
- */
- public String getLocale() {
- return this.getString(Path.LANGUAGE_FILE_NAME);
- }
-
- /**
- * Tells whether this is the first time the plugin has run as set by a config flag.
- *
- * @return True if first_run is set to true in config.
- */
- public boolean isFirstRun() {
- return this.getBoolean(Path.FIRST_RUN);
- }
-
- /**
- * Sets the first_run flag in the config so that the plugin no longer thinks it is the first run.
- *
- * @param firstRun What to set the flag to in the config.
- */
- void setFirstRun(boolean firstRun) {
- this.getConfig().set(Path.FIRST_RUN.getPath(), firstRun);
- }
-
- /**
- * @return True if we should check for bypass permissions.
- */
- public boolean isUsingBypass() {
- return this.getBoolean(Path.USE_BYPASS);
- }
-
- /**
- * @param useBypass Whether or not to check for bypass permissions.
- */
- public void setUsingBypass(boolean useBypass) {
- this.getConfig().set(Path.USE_BYPASS.getPath(), useBypass);
- }
-
- /**
- * Tells whether Multiverse-Inventories should save on player logout and load on player login.
- *
- * @return True if should save and load on player log out and in.
- */
- public boolean usingLoggingSaveLoad() {
- return this.getBoolean(Path.LOGGING_SAVE_LOAD);
- }
-
- /**
- * Sets whether Multiverse-Inventories should save on player logout and load on player login.
- *
- * @param useLoggingSaveLoad true if should save and load on player log out and in.
- */
- public void setUsingLoggingSaveLoad(boolean useLoggingSaveLoad) {
- this.getConfig().set(Path.LOGGING_SAVE_LOAD.getPath(), useLoggingSaveLoad);
- }
-
- private Shares optionalSharables = null;
-
- /**
- * @return A list of optional {@link com.onarandombox.multiverseinventories.share.Sharable}s to be treated as
- * regular {@link com.onarandombox.multiverseinventories.share.Sharable}s throughout the code.
- * A {@link com.onarandombox.multiverseinventories.share.Sharable} marked as optional is ignored if it is not
- * contained in this list.
- */
- public Shares getOptionalShares() {
- if (this.optionalSharables == null) {
- List list = this.getConfig().getList(Path.OPTIONAL_SHARES.getPath());
- if (list != null) {
- this.optionalSharables = Sharables.fromList(list);
- } else {
- Logging.warning("'" + Path.OPTIONAL_SHARES.getPath() + "' is setup incorrectly!");
- this.optionalSharables = Sharables.noneOf();
- }
- }
- return this.optionalSharables;
- }
-
- /**
- * @return true if worlds with no group should be considered part of the default group.
- */
- public boolean isDefaultingUngroupedWorlds() {
- return this.getBoolean(Path.DEFAULT_UNGROUPED_WORLDS);
- }
-
- /**
- * @param useDefaultGroup Set this to true to use the default group for ungrouped worlds.
- */
- public void setDefaultingUngroupedWorlds(boolean useDefaultGroup) {
- this.getConfig().set(Path.FIRST_RUN.getPath(), useDefaultGroup);
- }
-
- /**
- * @return True if using separate data for game modes.
- */
- public boolean isUsingGameModeProfiles() {
- return this.getBoolean(Path.USE_GAME_MODE_PROFILES);
- }
-
- /**
- * @param useGameModeProfile whether to use separate data for game modes.
- */
- public void setUsingGameModeProfiles(boolean useGameModeProfile) {
- this.getConfig().set(Path.USE_GAME_MODE_PROFILES.getPath(), useGameModeProfile);
- }
-
- /**
- * Whether Multiverse-Inventories will utilize optional shares in worlds that are not grouped.
- *
- * @return true if should utilize optional shares in worlds that are not grouped.
- */
- public boolean usingOptionalsForUngrouped() {
- return this.getBoolean(Path.USE_OPTIONALS_UNGROUPED);
- }
-
- /**
- * Sets whether Multiverse-Inventories will utilize optional shares in worlds that are not grouped.
- *
- * @param usingOptionalsForUngrouped true if should utilize optional shares in worlds that are not grouped.
- */
- public void setUsingOptionalsForUngrouped(final boolean usingOptionalsForUngrouped) {
- this.getConfig().set(Path.USE_OPTIONALS_UNGROUPED.getPath(), usingOptionalsForUngrouped);
- }
-
- /**
- * Saves the configuration file to disk.
- */
- // TODO remove need for this method.
- // TODO Figure out what I meant by the above todo message...
- public void save() {
- if (this.optionalSharables != null) {
- this.getConfig().set(Path.OPTIONAL_SHARES.getPath(), this.optionalSharables.toStringList());
- }
- this.config.save();
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/InventoriesListener.java b/src/main/java/com/onarandombox/multiverseinventories/InventoriesListener.java
deleted file mode 100644
index 8e1d8e4d..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/InventoriesListener.java
+++ /dev/null
@@ -1,469 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.MultiverseCore.api.MultiverseWorld;
-import com.onarandombox.MultiverseCore.event.MVConfigReloadEvent;
-import com.onarandombox.MultiverseCore.event.MVVersionEvent;
-import com.onarandombox.multiverseinventories.profile.GlobalProfile;
-import com.onarandombox.multiverseinventories.profile.PlayerProfile;
-import com.onarandombox.multiverseinventories.profile.container.ProfileContainer;
-import com.onarandombox.multiverseinventories.share.Sharables;
-import me.drayshak.WorldInventories.WorldInventories;
-import org.bukkit.Bukkit;
-import org.bukkit.Location;
-import org.bukkit.World;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.Item;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.Listener;
-import org.bukkit.event.entity.EntityPortalEvent;
-import org.bukkit.event.entity.PlayerDeathEvent;
-import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
-import org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result;
-import org.bukkit.event.player.PlayerChangedWorldEvent;
-import org.bukkit.event.player.PlayerGameModeChangeEvent;
-import org.bukkit.event.player.PlayerJoinEvent;
-import org.bukkit.event.player.PlayerQuitEvent;
-import org.bukkit.event.player.PlayerRespawnEvent;
-import org.bukkit.event.player.PlayerTeleportEvent;
-import org.bukkit.event.server.PluginDisableEvent;
-import org.bukkit.event.server.PluginEnableEvent;
-import org.bukkit.event.world.WorldUnloadEvent;
-import org.bukkit.inventory.InventoryHolder;
-import uk.co.tggl.pluckerpluck.multiinv.MultiInv;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * PlayerListener for MultiverseInventories.
- */
-public class InventoriesListener implements Listener {
-
- private MultiverseInventories inventories;
- private List currentGroups;
- private Location spawnLoc = null;
-
- public InventoriesListener(MultiverseInventories inventories) {
- this.inventories = inventories;
- }
-
- /**
- * Adds Multiverse-Inventories version info to /mv version.
- *
- * @param event The MVVersionEvent that this plugin will listen for.
- */
- @EventHandler
- public void versionRequest(MVVersionEvent event) {
- event.appendVersionInfo(this.inventories.getVersionInfo());
- File configFile = new File(this.inventories.getDataFolder(), "config.yml");
- File groupsFile = new File(this.inventories.getDataFolder(), "groups.yml");
- event.putDetailedVersionInfo("multiverse-inventories/config.yml", configFile);
- event.putDetailedVersionInfo("multiverse-inventories/groups.yml", groupsFile);
- }
-
- /**
- * Hooks Multiverse-Inventories into the Multiverse reload command.
- *
- * @param event The MVConfigReloadEvent that this plugin will listen for.
- */
- @EventHandler
- public void configReload(MVConfigReloadEvent event) {
- this.inventories.reloadConfig();
- event.addConfig("Multiverse-Inventories - config.yml");
- }
-
- /**
- * Called when a plugin is enabled.
- *
- * @param event The plugin enable event.
- */
- @EventHandler
- public void pluginEnable(PluginEnableEvent event) {
- try {
- if (event.getPlugin() instanceof MultiInv) {
- this.inventories.getImportManager().hookMultiInv((MultiInv) event.getPlugin());
- } else if (event.getPlugin() instanceof WorldInventories) {
- this.inventories.getImportManager().hookWorldInventories((WorldInventories) event.getPlugin());
- }
- } catch (NoClassDefFoundError ignore) {
- }
- }
-
- /**
- * Called when a plugin is disabled.
- *
- * @param event The plugin disable event.
- */
- @EventHandler
- public void pluginDisable(PluginDisableEvent event) {
- try {
- if (event.getPlugin() instanceof MultiInv) {
- this.inventories.getImportManager().unHookMultiInv();
- } else if (event.getPlugin() instanceof WorldInventories) {
- this.inventories.getImportManager().unHookWorldInventories();
- }
- } catch (NoClassDefFoundError ignore) {
- }
- }
-
- @EventHandler(priority = EventPriority.MONITOR)
- public void playerPreLogin(AsyncPlayerPreLoginEvent event) {
- if (event.getLoginResult() != Result.ALLOWED) {
- return;
- }
-
- Logging.finer("Loading global profile for Player{name:'%s', uuid:'%s'}.",
- event.getName(), event.getUniqueId());
-
- GlobalProfile globalProfile = inventories.getData().getGlobalProfile(event.getName(), event.getUniqueId());
- if (!globalProfile.getLastKnownName().equalsIgnoreCase(event.getName())) {
- // Data must be migrated
- Logging.info("Player %s changed name from '%s' to '%s'. Attempting to migrate playerdata...",
- event.getUniqueId(), globalProfile.getLastKnownName(), event.getName());
- try {
- inventories.getData().migratePlayerData(globalProfile.getLastKnownName(), event.getName(),
- event.getUniqueId(), true);
- } catch (IOException e) {
- Logging.severe("An error occurred while trying to migrate playerdata.");
- e.printStackTrace();
- }
-
- globalProfile.setLastKnownName(event.getName());
- inventories.getData().updateGlobalProfile(globalProfile);
- Logging.info("Migration complete!");
- }
- }
-
- /**
- * Called when a player joins the server.
- *
- * @param event The player join event.
- */
- @EventHandler
- public void playerJoin(final PlayerJoinEvent event) {
- final Player player = event.getPlayer();
- final GlobalProfile globalProfile = inventories.getData().getGlobalProfile(player.getName(), player.getUniqueId());
- final String world = globalProfile.getLastWorld();
- if (inventories.getMVIConfig().usingLoggingSaveLoad() && globalProfile.shouldLoadOnLogin()) {
- ShareHandlingUpdater.updatePlayer(inventories, player, new DefaultPersistingProfile(Sharables.allOf(),
- inventories.getWorldProfileContainerStore().getContainer(world).getPlayerData(player)));
- }
- inventories.getData().setLoadOnLogin(player.getName(), false);
- verifyCorrectWorld(player, player.getWorld().getName(), globalProfile);
- }
-
- /**
- * Called when a player leaves the server.
- *
- * @param event The player quit event.
- */
- @EventHandler
- public void playerQuit(final PlayerQuitEvent event) {
- final Player player = event.getPlayer();
- final String world = event.getPlayer().getWorld().getName();
- inventories.getData().updateLastWorld(player.getName(), world);
- if (inventories.getMVIConfig().usingLoggingSaveLoad()) {
- ShareHandlingUpdater.updateProfile(inventories, player, new DefaultPersistingProfile(Sharables.allOf(),
- inventories.getWorldProfileContainerStore().getContainer(world).getPlayerData(player)));
- inventories.getData().setLoadOnLogin(player.getName(), true);
- }
- }
-
- private void verifyCorrectWorld(Player player, String world, GlobalProfile globalProfile) {
- if (globalProfile.getLastWorld() == null) {
- inventories.getData().updateLastWorld(player.getName(), world);
- } else {
- if (!world.equals(globalProfile.getLastWorld())) {
- Logging.fine("Player did not spawn in the world they were last reported to be in!");
- new WorldChangeShareHandler(this.inventories, player,
- globalProfile.getLastWorld(), world).handleSharing();
- inventories.getData().updateLastWorld(player.getName(), world);
- }
- }
- }
-
- /**
- * Called when a player changes game modes.
- *
- * @param event The game mode change event.
- */
- @EventHandler(priority = EventPriority.MONITOR)
- public void playerGameModeChange(PlayerGameModeChangeEvent event) {
- if (event.isCancelled() || !inventories.getMVIConfig().isUsingGameModeProfiles()) {
- return;
- }
- Player player = event.getPlayer();
- new GameModeShareHandler(this.inventories, player,
- player.getGameMode(), event.getNewGameMode()).handleSharing();
- }
-
- /**
- * Called when a player changes worlds.
- *
- * @param event The world change event.
- */
- @EventHandler(priority = EventPriority.LOW)
- public void playerChangedWorld(PlayerChangedWorldEvent event) {
- Player player = event.getPlayer();
- World fromWorld = event.getFrom();
- World toWorld = player.getWorld();
-
- // A precaution.. Will this ever be true?
- if (fromWorld.equals(toWorld)) {
- Logging.fine("PlayerChangedWorldEvent fired when player travelling in same world.");
- return;
- }
- // Warn if not managed by Multiverse-Core
- if (this.inventories.getCore().getMVWorldManager().getMVWorld(toWorld) == null
- || this.inventories.getCore().getMVWorldManager().getMVWorld(fromWorld) == null) {
- Logging.fine("The from or to world is not managed by Multiverse-Core!");
- }
-
- new WorldChangeShareHandler(this.inventories, player, fromWorld.getName(), toWorld.getName()).handleSharing();
- inventories.getData().updateLastWorld(player.getName(), toWorld.getName());
- }
-
- /**
- * Called when a player teleports.
- *
- * @param event The player teleport event.
- */
- @EventHandler(priority = EventPriority.MONITOR)
- public void playerTeleport(PlayerTeleportEvent event) {
- if (event.isCancelled()
- || event.getFrom().getWorld().equals(event.getTo().getWorld())
- || !this.inventories.getMVIConfig().getOptionalShares().contains(Sharables.LAST_LOCATION)) {
- return;
- }
-
- Player player = event.getPlayer();
-
- String fromWorldName = event.getFrom().getWorld().getName();
- String toWorldName = event.getTo().getWorld().getName();
-
- ProfileContainer fromWorldProfileContainer = this.inventories.getWorldProfileContainerStore().getContainer(fromWorldName);
- PlayerProfile playerProfile = fromWorldProfileContainer.getPlayerData(player);
- playerProfile.set(Sharables.LAST_LOCATION, event.getFrom());
-
- List fromGroups = this.inventories.getGroupManager().getGroupsForWorld(fromWorldName);
- for (WorldGroup fromGroup : fromGroups) {
- playerProfile = fromGroup.getGroupProfileContainer().getPlayerData(event.getPlayer());
-
- if (fromGroup.containsWorld(toWorldName)) {
- if (!fromGroup.isSharing(Sharables.LAST_LOCATION)) {
- playerProfile.set(Sharables.LAST_LOCATION, event.getFrom());
- }
- } else {
- playerProfile.set(Sharables.LAST_LOCATION, event.getFrom());
- }
- }
-
- // Possibly prevents item duping exploit
- player.closeInventory();
- }
-
- /**
- * Called when a player dies.
- *
- * @param event The player death event.
- */
- @EventHandler(priority = EventPriority.MONITOR)
- public void playerDeath(PlayerDeathEvent event) {
- Logging.finer("=== Handling PlayerDeathEvent for: " + event.getEntity().getName() + " ===");
- String deathWorld = event.getEntity().getWorld().getName();
- ProfileContainer worldProfileContainer = this.inventories.getWorldProfileContainerStore().getContainer(deathWorld);
- PlayerProfile profile = worldProfileContainer.getPlayerData(event.getEntity());
- profile.set(Sharables.LEVEL, event.getNewLevel());
- profile.set(Sharables.EXPERIENCE, (float) event.getNewExp());
- profile.set(Sharables.TOTAL_EXPERIENCE, event.getNewTotalExp());
- this.inventories.getData().updatePlayerData(profile);
- for (WorldGroup worldGroup : this.inventories.getGroupManager().getGroupsForWorld(deathWorld)) {
- profile = worldGroup.getGroupProfileContainer().getPlayerData(event.getEntity());
- profile.set(Sharables.LEVEL, event.getNewLevel());
- profile.set(Sharables.EXPERIENCE, (float) event.getNewExp());
- profile.set(Sharables.TOTAL_EXPERIENCE, event.getNewTotalExp());
- this.inventories.getData().updatePlayerData(profile);
- }
- Logging.finer("=== Finished handling PlayerDeathEvent for: " + event.getEntity().getName() + "! ===");
- }
-
- @EventHandler(priority = EventPriority.MONITOR)
- public void playerRespawn(PlayerRespawnEvent event) {
- Location respawnLoc = event.getRespawnLocation();
- if (respawnLoc == null) {
- // This probably only happens if a naughty plugin sets the location to null...
- return;
- }
- final Player player = event.getPlayer();
- Bukkit.getScheduler().scheduleSyncDelayedTask(inventories, new Runnable() {
- public void run() {
- verifyCorrectWorld(player, player.getWorld().getName(),
- inventories.getData().getGlobalProfile(player.getName(), player.getUniqueId()));
- }
- }, 2L);
- }
-
- /**
- * Handles player respawns at the LOWEST priority.
- *
- * @param event The player respawn event.
- */
- @EventHandler(priority = EventPriority.LOWEST)
- public void lowestPriorityRespawn(PlayerRespawnEvent event) {
- if (!event.isBedSpawn()) {
- World world = event.getPlayer().getWorld();
- this.currentGroups = this.inventories.getGroupManager()
- .getGroupsForWorld(world.getName());
- this.handleRespawn(event, EventPriority.LOWEST);
- }
- }
-
- /**
- * Handles player respawns at the LOW priority.
- *
- * @param event The player respawn event.
- */
- @EventHandler(priority = EventPriority.LOW)
- public void lowPriorityRespawn(PlayerRespawnEvent event) {
- if (!event.isBedSpawn()) {
- this.handleRespawn(event, EventPriority.LOW);
- }
- }
-
- /**
- * Handles player respawns at the NORMAL priority.
- *
- * @param event The player respawn event.
- */
- @EventHandler(priority = EventPriority.NORMAL)
- public void normalPriorityRespawn(PlayerRespawnEvent event) {
- if (!event.isBedSpawn()) {
- this.handleRespawn(event, EventPriority.NORMAL);
- }
- }
-
- /**
- * Handles player respawns at the HIGH priority.
- *
- * @param event The player respawn event.
- */
- @EventHandler(priority = EventPriority.HIGH)
- public void highPriorityRespawn(PlayerRespawnEvent event) {
- if (!event.isBedSpawn()) {
- this.handleRespawn(event, EventPriority.HIGH);
- }
- }
-
- /**
- * Handles player respawns at the HIGHEST priority.
- *
- * @param event The player respawn event.
- */
- @EventHandler(priority = EventPriority.HIGHEST)
- public void highestPriorityRespawn(PlayerRespawnEvent event) {
- if (!event.isBedSpawn()) {
- this.handleRespawn(event, EventPriority.HIGHEST);
- }
- }
-
- /**
- * Handles player respawns at the MONITOR priority.
- *
- * @param event The player respawn event.
- */
- @EventHandler(priority = EventPriority.MONITOR)
- public void monitorPriorityRespawn(PlayerRespawnEvent event) {
- if (!event.isBedSpawn()) {
- this.handleRespawn(event, EventPriority.MONITOR);
- this.updateCompass(event);
- }
- }
-
- private void handleRespawn(PlayerRespawnEvent event, EventPriority priority) {
- for (WorldGroup group : this.currentGroups) {
- if (group.getSpawnPriority().equals(priority)) {
- String spawnWorldName = group.getSpawnWorld();
- if (spawnWorldName != null) {
- MultiverseWorld mvWorld = this.inventories.getCore()
- .getMVWorldManager().getMVWorld(spawnWorldName);
- if (mvWorld != null) {
- this.spawnLoc = mvWorld.getSpawnLocation();
- event.setRespawnLocation(this.spawnLoc);
- break;
- }
- }
- }
- }
- }
-
- private void updateCompass(PlayerRespawnEvent event) {
- if (event.getRespawnLocation().equals(this.spawnLoc)) {
- event.getPlayer().setCompassTarget(this.spawnLoc);
- }
- }
-
- @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
- public void entityPortal(EntityPortalEvent event) {
- Entity entity = event.getEntity();
- if (!(entity instanceof Item) && !(entity instanceof InventoryHolder)) {
- return;
- }
-
- World fromWorld = event.getFrom().getWorld();
- Location toLocation = event.getTo();
- if (toLocation == null) {
- // Apparently this happens sometimes.
- Logging.fine("Entity %s attempted to go to null location", entity);
- return;
- }
- World toWorld = toLocation.getWorld();
- if (toWorld == null) {
- // Apparently this also happens sometimes.
- Logging.fine("Entity %s attempted to go to null world", entity);
- return;
- }
-
- if (fromWorld.equals(toWorld)) {
- return;
- }
-
- List fromGroups = inventories.getGroupManager().getGroupsForWorld(fromWorld.getName());
- List toGroups = inventories.getGroupManager().getGroupsForWorld(toWorld.getName());
- // We only care about the groups that have the inventory sharable
- fromGroups = fromGroups.stream().filter(it -> it.isSharing(Sharables.INVENTORY)).collect(Collectors.toList());
- toGroups = toGroups.stream().filter(it -> it.isSharing(Sharables.INVENTORY)).collect(Collectors.toList());
- for (WorldGroup fromGroup : fromGroups) {
- if (toGroups.contains(fromGroup)) {
- Logging.finest("Allowing item or inventory holding %s to go from world %s to world %s", entity,
- fromWorld.getName(), toWorld.getName());
- // The from and to destinations share at least one group that has the inventory sharable.
- return;
- }
- }
-
- Logging.finest("Disallowing item or inventory holding %s to go from world %s to world %s since these" +
- "worlds do not share inventories", entity, fromWorld.getName(), toWorld.getName());
- event.setCancelled(true);
- }
-
- @EventHandler
- public void worldUnload(WorldUnloadEvent event) {
- String unloadWorldName = event.getWorld().getName();
-
- Logging.finer("Clearing data for world/groups container with '%s' world.", unloadWorldName);
-
- ProfileContainer fromWorldProfileContainer = this.inventories.getWorldProfileContainerStore().getContainer(unloadWorldName);
- fromWorldProfileContainer.clearContainer();
-
- List fromGroups = this.inventories.getGroupManager().getGroupsForWorld(unloadWorldName);
- for (WorldGroup fromGroup : fromGroups) {
- fromGroup.getGroupProfileContainer().clearContainer();
- }
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/MultiverseInventories.java b/src/main/java/com/onarandombox/multiverseinventories/MultiverseInventories.java
deleted file mode 100644
index d3d37d1c..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/MultiverseInventories.java
+++ /dev/null
@@ -1,471 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.MultiverseCore.MultiverseCore;
-import com.onarandombox.MultiverseCore.api.MVPlugin;
-import com.onarandombox.MultiverseCore.commands.HelpCommand;
-import com.onarandombox.commandhandler.CommandHandler;
-import com.onarandombox.multiverseinventories.profile.ProfileDataSource;
-import com.onarandombox.multiverseinventories.profile.WorldGroupManager;
-import com.onarandombox.multiverseinventories.profile.container.ContainerType;
-import com.onarandombox.multiverseinventories.profile.container.ProfileContainerStore;
-import com.onarandombox.multiverseinventories.share.Sharables;
-import com.onarandombox.multiverseinventories.command.AddSharesCommand;
-import com.onarandombox.multiverseinventories.command.AddWorldCommand;
-import com.onarandombox.multiverseinventories.command.CreateGroupCommand;
-import com.onarandombox.multiverseinventories.command.DeleteGroupCommand;
-import com.onarandombox.multiverseinventories.command.GroupCommand;
-import com.onarandombox.multiverseinventories.command.ImportCommand;
-import com.onarandombox.multiverseinventories.command.InfoCommand;
-import com.onarandombox.multiverseinventories.command.ListCommand;
-import com.onarandombox.multiverseinventories.command.MigrateCommand;
-import com.onarandombox.multiverseinventories.command.ReloadCommand;
-import com.onarandombox.multiverseinventories.command.RemoveSharesCommand;
-import com.onarandombox.multiverseinventories.command.RemoveWorldCommand;
-import com.onarandombox.multiverseinventories.command.SpawnCommand;
-import com.onarandombox.multiverseinventories.command.ToggleCommand;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.locale.Messager;
-import com.onarandombox.multiverseinventories.locale.Messaging;
-import com.onarandombox.multiverseinventories.migration.ImportManager;
-import com.onarandombox.multiverseinventories.util.Perm;
-import me.drayshak.WorldInventories.WorldInventories;
-import org.bukkit.Bukkit;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-import org.bukkit.plugin.Plugin;
-import org.bukkit.plugin.PluginDescriptionFile;
-import org.bukkit.plugin.PluginManager;
-import org.bukkit.plugin.java.JavaPlugin;
-import org.bukkit.plugin.java.JavaPluginLoader;
-import uk.co.tggl.pluckerpluck.multiinv.MultiInv;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Locale;
-import java.util.logging.Level;
-
-/**
- * Multiverse-Inventories plugin main class.
- */
-public class MultiverseInventories extends JavaPlugin implements MVPlugin, Messaging {
-
- private static MultiverseInventories inventoriesPlugin;
-
- public static MultiverseInventories getPlugin() {
- return inventoriesPlugin;
- }
-
- private final int requiresProtocol = 22;
- private final InventoriesListener inventoriesListener = new InventoriesListener(this);
- private final AdventureListener adventureListener = new AdventureListener(this);
-
- private Messager messager = new DefaultMessager(this);
- private WorldGroupManager worldGroupManager = null;
- private ProfileContainerStore worldProfileContainerStore = null;
- private ProfileContainerStore groupProfileContainerStore = null;
- private ImportManager importManager = new ImportManager(this);
-
- private CommandHandler commandHandler = null;
- private MultiverseCore core = null;
- private InventoriesConfig config = null;
- private FlatFileProfileDataSource data = null;
-
- private InventoriesDupingPatch dupingPatch;
-
- private File serverFolder = new File(System.getProperty("user.dir"));
-
- {
- inventoriesPlugin = this;
- }
-
- public MultiverseInventories() {
- super();
- }
-
- /**
- * This is for unit testing.
- * @param loader The PluginLoader to use.
- * @param description The Description file to use.
- * @param dataFolder The folder that other datafiles can be found in.
- * @param file The location of the plugin.
- */
- public MultiverseInventories(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) {
- super(loader, description, dataFolder, file);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onDisable() {
- for (final Player player : getServer().getOnlinePlayers()) {
- final String world = player.getWorld().getName();
- //getData().updateLastWorld(player.getName(), world);
- if (getMVIConfig().usingLoggingSaveLoad()) {
- ShareHandlingUpdater.updateProfile(this, player, new DefaultPersistingProfile(Sharables.allOf(),
- getWorldProfileContainerStore().getContainer(world).getPlayerData(player)));
- getData().setLoadOnLogin(player.getName(), true);
- }
- }
-
- this.dupingPatch.disable();
-
- Logging.shutdown();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onEnable() {
- Logging.init(this);
- Perm.register(this);
-
- MultiverseCore mvCore;
- mvCore = (MultiverseCore) this.getServer().getPluginManager().getPlugin("Multiverse-Core");
- // Test if the Core was found, if not we'll disable this plugin.
- if (mvCore == null) {
- Logging.severe("Multiverse-Core not found, disabling...");
- this.getServer().getPluginManager().disablePlugin(this);
- return;
- }
- this.setCore(mvCore);
-
- if (this.getCore().getProtocolVersion() < this.getRequiredProtocol()) {
- Logging.severe("Your Multiverse-Core is OUT OF DATE");
- Logging.severe("This version of Multiverse-Inventories requires Protocol Level: " + this.getRequiredProtocol());
- Logging.severe("Your of Core Protocol Level is: " + this.getCore().getProtocolVersion());
- Logging.severe("Grab an updated copy at: ");
- Logging.severe("http://bukkit.onarandombox.com/?dir=multiverse-core");
- this.getServer().getPluginManager().disablePlugin(this);
- return;
- }
-
- this.reloadConfig();
-
- try {
- this.getMessager().setLocale(new Locale(this.getMVIConfig().getLocale()));
- } catch (IllegalArgumentException e) {
- Logging.severe(e.getMessage());
- this.getServer().getPluginManager().disablePlugin(this);
- return;
- }
-
- // Initialize data class
- //this.getWorldProfileContainerStore().setWorldProfiles(this.getData().getWorldProfiles());
-
- Logging.setDebugLevel(getCore().getMVConfig().getGlobalDebug());
-
- this.getCore().incrementPluginCount();
-
- // Register Events
- Bukkit.getPluginManager().registerEvents(inventoriesListener, this);
- if (Bukkit.getPluginManager().getPlugin("Multiverse-Adventure") != null) {
- Bukkit.getPluginManager().registerEvents(adventureListener, this);
- }
- if (getCore().getProtocolVersion() >= 24) {
- new CoreDebugListener(this);
- }
-
- // Register Commands
- this.registerCommands();
-
- // Hook plugins that can be imported from
- this.hookImportables();
-
- Sharables.init(this);
-
- this.dupingPatch = InventoriesDupingPatch.enableDupingPatch(this);
-
- // Display enable message/version info
- Logging.log(true, Level.INFO, "enabled.");
- }
-
- private void registerCommands() {
- this.commandHandler = this.getCore().getCommandHandler();
- this.getCommandHandler().registerCommand(new InfoCommand(this));
- this.getCommandHandler().registerCommand(new ImportCommand(this));
- this.getCommandHandler().registerCommand(new ListCommand(this));
- this.getCommandHandler().registerCommand(new ReloadCommand(this));
- this.getCommandHandler().registerCommand(new AddWorldCommand(this));
- this.getCommandHandler().registerCommand(new RemoveWorldCommand(this));
- this.getCommandHandler().registerCommand(new AddSharesCommand(this));
- this.getCommandHandler().registerCommand(new RemoveSharesCommand(this));
- this.getCommandHandler().registerCommand(new CreateGroupCommand(this));
- this.getCommandHandler().registerCommand(new DeleteGroupCommand(this));
- this.getCommandHandler().registerCommand(new SpawnCommand(this));
- this.getCommandHandler().registerCommand(new GroupCommand(this));
- this.getCommandHandler().registerCommand(new ToggleCommand(this));
- this.getCommandHandler().registerCommand(new MigrateCommand(this));
- for (com.onarandombox.commandhandler.Command c : this.commandHandler.getAllCommands()) {
- if (c instanceof HelpCommand) {
- c.addKey("mvinv");
- }
- }
- }
-
- private void hookImportables() {
- final PluginManager pm = Bukkit.getPluginManager();
- Plugin plugin = pm.getPlugin("MultiInv");
- if (plugin != null) {
- this.getImportManager().hookMultiInv((MultiInv) plugin);
- }
- plugin = pm.getPlugin("WorldInventories");
- if (plugin != null) {
- this.getImportManager().hookWorldInventories((WorldInventories) plugin);
- }
- }
-
- /**
- * @return A class used for managing importing data from other similar plugins.
- */
- public ImportManager getImportManager() {
- return this.importManager;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean onCommand(CommandSender sender, Command command, String commandLabel, String[] args) {
- if (!this.isEnabled()) {
- sender.sendMessage("This plugin is Disabled!");
- return true;
- }
- ArrayList allArgs = new ArrayList(Arrays.asList(args));
- allArgs.add(0, command.getName());
- return this.getCommandHandler().locateAndRunCommand(sender, allArgs);
- }
-
- private CommandHandler getCommandHandler() {
- return this.commandHandler;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void log(Level level, String msg) {
- Logging.log(level, msg);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public MultiverseCore getCore() {
- return this.core;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setCore(MultiverseCore core) {
- this.core = core;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int getProtocolVersion() {
- return 1;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String dumpVersionInfo(String buffer) {
- buffer += logAndAddToPasteBinBuffer("=== Settings ===");
- buffer += logAndAddToPasteBinBuffer("First Run: " + this.getMVIConfig().isFirstRun());
- buffer += logAndAddToPasteBinBuffer("Using Bypass: " + this.getMVIConfig().isUsingBypass());
- buffer += logAndAddToPasteBinBuffer("Default Ungrouped Worlds: " + this.getMVIConfig().isDefaultingUngroupedWorlds());
- buffer += logAndAddToPasteBinBuffer("Save and Load on Log In and Out: " + this.getMVIConfig().usingLoggingSaveLoad());
- buffer += logAndAddToPasteBinBuffer("Using GameMode Profiles: " + this.getMVIConfig().isUsingGameModeProfiles());
- buffer += logAndAddToPasteBinBuffer("=== Shares ===");
- buffer += logAndAddToPasteBinBuffer("Optionals for Ungrouped Worlds: " + this.getMVIConfig().usingOptionalsForUngrouped());
- buffer += logAndAddToPasteBinBuffer("Enabled Optionals: " + this.getMVIConfig().getOptionalShares());
- buffer += logAndAddToPasteBinBuffer("=== Groups ===");
- for (WorldGroup group : this.getGroupManager().getGroups()) {
- buffer += logAndAddToPasteBinBuffer(group.toString());
- }
- return buffer;
- }
-
- /**
- * Builds a String containing Multiverse-Inventories' version info.
- *
- * @return The version info.
- */
- public String getVersionInfo() {
- StringBuilder versionInfo = new StringBuilder("[Multiverse-Inventories] Multiverse-Inventories Version: " + this.getDescription().getVersion() + '\n'
- + "[Multiverse-Inventories] === Settings ===" + '\n'
- + "[Multiverse-Inventories] First Run: " + this.getMVIConfig().isFirstRun() + '\n'
- + "[Multiverse-Inventories] Using Bypass: " + this.getMVIConfig().isUsingBypass() + '\n'
- + "[Multiverse-Inventories] Default Ungrouped Worlds: " + this.getMVIConfig().isDefaultingUngroupedWorlds() + '\n'
- + "[Multiverse-Inventories] Save and Load on Log In and Out: " + this.getMVIConfig().usingLoggingSaveLoad() + '\n'
- + "[Multiverse-Inventories] Using GameMode Profiles: " + this.getMVIConfig().isUsingGameModeProfiles() + '\n'
- + "[Multiverse-Inventories] === Shares ===" + '\n'
- + "[Multiverse-Inventories] Optionals for Ungrouped Worlds: " + this.getMVIConfig().usingOptionalsForUngrouped() + '\n'
- + "[Multiverse-Inventories] Enabled Optionals: " + this.getMVIConfig().getOptionalShares() + '\n'
- + "[Multiverse-Inventories] === Groups ===" + '\n');
-
- for (WorldGroup group : this.getGroupManager().getGroups()) {
- versionInfo.append("[Multiverse-Inventories] ").append(group.toString()).append('\n');
- }
-
- return versionInfo.toString();
- }
-
- private String logAndAddToPasteBinBuffer(String string) {
- Logging.info(string);
- return Logging.getPrefixedMessage(string + '\n', false);
- }
-
- /**
- * @return the Config object which contains settings for this plugin.
- */
- public InventoriesConfig getMVIConfig() {
- return this.config;
- }
-
- /**
- * Nulls the config object and reloads a new one, also resetting the world groups in memory.
- */
- @Override
- public void reloadConfig() {
- try {
- this.config = new InventoriesConfig(this);
- this.worldGroupManager = new YamlWorldGroupManager(this, this.config.getConfig());
- this.worldProfileContainerStore = new WeakProfileContainerStore(this, ContainerType.WORLD);
- this.groupProfileContainerStore = new WeakProfileContainerStore(this, ContainerType.GROUP);
-
- if (data != null) {
- this.data.clearCache();
- }
-
- //this.data = null;
- Logging.fine("Loaded config file!");
- } catch (IOException e) { // Catch errors loading the config file and exit out if found.
- Logging.severe(this.getMessager().getMessage(Message.ERROR_CONFIG_LOAD));
- Logging.severe(e.getMessage());
- Bukkit.getPluginManager().disablePlugin(this);
- return;
- }
-
- this.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
- @Override
- public void run() {
- // Create initial World Group for first run IF NO GROUPS EXIST
- if (getMVIConfig().isFirstRun()) {
- Logging.info("First run!");
- if (getGroupManager().getGroups().isEmpty()) {
- getGroupManager().createDefaultGroup();
- }
-
- getMVIConfig().setFirstRun(false);
- }
- getGroupManager().checkForConflicts(null);
- }
- }, 1L);
- }
-
- /**
- * @return the PlayerData object which contains data for this plugin.
- */
- public ProfileDataSource getData() {
- if (this.data == null) {
- // Loads the data
- try {
- this.data = new FlatFileProfileDataSource(this);
- } catch (IOException e) { // Catch errors loading the language file and exit out if found.
- Logging.severe(this.getMessager().getMessage(Message.ERROR_DATA_LOAD));
- Logging.severe(e.getMessage());
- Bukkit.getPluginManager().disablePlugin(this);
- return null;
- }
- }
- return this.data;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Messager getMessager() {
- return messager;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setMessager(Messager messager) {
- if (messager == null) {
- throw new IllegalArgumentException("The new messager can't be null!");
- }
- this.messager = messager;
- }
-
- /**
- * @return The required protocol version of core.
- */
- public int getRequiredProtocol() {
- return this.requiresProtocol;
- }
-
- /**
- * @return The World Group manager for this plugin.
- */
- public WorldGroupManager getGroupManager() {
- return this.worldGroupManager;
- }
-
- /**
- * Returns the world profile container store for this plugin.
- * Player profiles for an individual world can be found here.
- *
- * @return the world profile container store for this plugin.
- */
- public ProfileContainerStore getWorldProfileContainerStore() {
- return worldProfileContainerStore;
- }
-
- /**
- * Returns the group profile container store for this plugin.
- * Player profiles for a world group can be found here.
- *
- * @return the group profile container store for this plugin.
- */
- public ProfileContainerStore getGroupProfileContainerStore() {
- return groupProfileContainerStore;
- }
-
- /**
- * Gets the server's root-folder as {@link File}.
- *
- * @return The server's root-folder
- */
- public File getServerFolder() {
- return serverFolder;
- }
-
- /**
- * Sets this server's root-folder.
- *
- * @param newServerFolder The new server-root
- */
- public void setServerFolder(File newServerFolder) {
- if (!newServerFolder.isDirectory()) {
- throw new IllegalArgumentException("That's not a folder!");
- }
- this.serverFolder = newServerFolder;
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/ShareHandler.java b/src/main/java/com/onarandombox/multiverseinventories/ShareHandler.java
deleted file mode 100644
index 25008ab6..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/ShareHandler.java
+++ /dev/null
@@ -1,162 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.multiverseinventories.event.ShareHandlingEvent;
-import com.onarandombox.multiverseinventories.profile.PlayerProfile;
-import com.onarandombox.multiverseinventories.share.PersistingProfile;
-import com.onarandombox.multiverseinventories.share.Shares;
-import org.bukkit.Bukkit;
-import org.bukkit.entity.Player;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import static com.onarandombox.multiverseinventories.share.Sharables.allOf;
-
-/**
- * Abstract class for handling sharing of data between worlds and game modes.
- */
-public abstract class ShareHandler {
-
- protected final MultiverseInventories inventories;
- protected final Player player;
- final AffectedProfiles affectedProfiles;
-
- ShareHandler(MultiverseInventories inventories, Player player) {
- this.inventories = inventories;
- this.player = player;
- this.affectedProfiles = new AffectedProfiles();
- }
-
- /**
- * Finalizes the transfer from one world to another. This handles the switching
- * inventories/stats for a player and persisting the changes.
- */
- final void handleSharing() {
- ShareHandlingEvent event = this.createEvent();
-
- Bukkit.getPluginManager().callEvent(event);
- if (!event.isCancelled()) {
- this.completeSharing(event);
- }
- }
-
- protected final void setAlwaysWriteProfile(PlayerProfile profile) {
- affectedProfiles.setAlwaysWriteProfile(profile);
- }
-
- /**
- * @param profile The player profile that will need data saved to.
- * @param shares What from this group needs to be saved.
- */
- protected final void addWriteProfile(PlayerProfile profile, Shares shares) {
- affectedProfiles.addWriteProfile(profile, shares);
- }
-
- /**
- * Finalizes the transfer from one world to another. This handles the switching
- * inventories/stats for a player and persisting the changes.
- *
- * @param profile The player profile that will need data loaded from.
- * @param shares What from this group needs to be loaded.
- */
- protected final void addReadProfile(PlayerProfile profile, Shares shares) {
- affectedProfiles.addReadProfile(profile, shares);
- }
-
- protected abstract ShareHandlingEvent createEvent();
-
- protected void logBypass() {
- Logging.fine(player.getName() + " has bypass permission for 1 or more world/groups!");
- }
-
- private void completeSharing(ShareHandlingEvent event) {
- logAffectedProfilesCount(event);
- saveAlwaysWriteProfile(event);
- handleProfileChanges(event);
- logHandlingComplete(event);
- }
-
- private void logAffectedProfilesCount(ShareHandlingEvent event) {
- PersistingProfile alwaysWriteProfile = event.getAlwaysWriteProfile();
- int writeProfiles = event.getWriteProfiles().size() + (alwaysWriteProfile != null ? 1 : 0);
-
- Logging.finer("Change affected by %d fromProfiles and %d toProfiles", writeProfiles,
- event.getReadProfiles().size());
- }
-
- private void saveAlwaysWriteProfile(ShareHandlingEvent event) {
- if (event.getAlwaysWriteProfile() != null) {
- ShareHandlingUpdater.updateProfile(inventories, event.getPlayer(), event.getAlwaysWriteProfile());
- } else {
- Logging.warning("No fromWorld to save to");
- }
- }
-
- private void handleProfileChanges(ShareHandlingEvent event) {
- if (event.getReadProfiles().isEmpty()) {
- Logging.finest("No profiles to read from - nothing more to do.");
- } else {
- updateProfiles(event.getPlayer(), event.getWriteProfiles());
- updatePlayer(event.getPlayer(), event.getReadProfiles());
- }
- }
-
- private void updateProfiles(Player player, List writeProfiles) {
- for (PersistingProfile writeProfile : writeProfiles) {
- ShareHandlingUpdater.updateProfile(inventories, player, writeProfile);
- }
- }
-
- private void updatePlayer(Player player, List readProfiles) {
- for (PersistingProfile readProfile : readProfiles) {
- ShareHandlingUpdater.updatePlayer(inventories, player, readProfile);
- }
- }
-
- private void logHandlingComplete(ShareHandlingEvent event) {
- Logging.finer("=== %s complete for %s ===", event.getPlayer().getName(), event.getEventName());
- }
-
- public static class AffectedProfiles {
-
- private PersistingProfile alwaysWriteProfile;
- private final List writeProfiles = new LinkedList<>();
- private final List readProfiles = new LinkedList<>();
-
- AffectedProfiles() { }
-
- protected final void setAlwaysWriteProfile(PlayerProfile profile) {
- alwaysWriteProfile = new DefaultPersistingProfile(allOf(), profile);
- }
-
- /**
- * @param profile The player profile that will need data saved to.
- * @param shares What from this group needs to be saved.
- */
- protected final void addWriteProfile(PlayerProfile profile, Shares shares) {
- writeProfiles.add(new DefaultPersistingProfile(shares, profile));
- }
-
- /**
- * @param profile The player profile that will need data loaded from.
- * @param shares What from this group needs to be loaded.
- */
- protected final void addReadProfile(PlayerProfile profile, Shares shares) {
- readProfiles.add(new DefaultPersistingProfile(shares, profile));
- }
-
- public PersistingProfile getAlwaysWriteProfile() {
- return alwaysWriteProfile;
- }
-
- public List getWriteProfiles() {
- return writeProfiles;
- }
-
- public List getReadProfiles() {
- return readProfiles;
- }
- }
-
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/ShareHandlingUpdater.java b/src/main/java/com/onarandombox/multiverseinventories/ShareHandlingUpdater.java
deleted file mode 100644
index 5409a059..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/ShareHandlingUpdater.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.multiverseinventories.profile.container.ContainerType;
-import com.onarandombox.multiverseinventories.share.PersistingProfile;
-import com.onarandombox.multiverseinventories.share.Sharable;
-import com.onarandombox.multiverseinventories.share.Sharables;
-import org.apache.commons.lang.StringUtils;
-import org.bukkit.entity.Player;
-
-import java.util.ArrayList;
-import java.util.List;
-
-class ShareHandlingUpdater {
-
- static void updateProfile(final MultiverseInventories inventories,
- final Player player,
- final PersistingProfile profile) {
- new ShareHandlingUpdater(inventories, player, profile).updateProfile();
- }
-
- static void updatePlayer(final MultiverseInventories inventories,
- final Player player,
- final PersistingProfile profile) {
- new ShareHandlingUpdater(inventories, player, profile).updatePlayer();
- }
-
- private final MultiverseInventories inventories;
- private final Player player;
- private final PersistingProfile profile;
-
- private final List> saved = new ArrayList<>(Sharables.all().size());
- private final List> loaded = new ArrayList<>(Sharables.all().size());
- private final List> defaulted = new ArrayList<>(Sharables.all().size());
-
- private ShareHandlingUpdater(MultiverseInventories inventories, Player player, PersistingProfile profile) {
- this.inventories = inventories;
- this.player = player;
- this.profile = profile;
- }
-
- private void updateProfile() {
- for (Sharable> sharable : profile.getShares()) {
- if (isSharableUsed(sharable)) {
- saved.add(sharable);
- sharable.getHandler().updateProfile(profile.getProfile(), player);
- }
- }
- if (saved.size() > 0) {
- Logging.finer("Persisted: " + StringUtils.join(saved, ", ") + " to "
- + profile.getProfile().getContainerType() + ":" + profile.getProfile().getContainerName()
- + " (" + profile.getProfile().getProfileType() + ")"
- + " for player " + profile.getProfile().getPlayer().getName());
- }
- inventories.getData().updatePlayerData(profile.getProfile());
- }
-
- private void updatePlayer() {
- player.closeInventory();
- for (Sharable> sharable : profile.getShares()) {
- if (isSharableUsed(sharable)) {
- if (sharable.getHandler().updatePlayer(player, profile.getProfile())) {
- loaded.add(sharable);
- } else {
- defaulted.add(sharable);
- }
- }
- }
- if (!loaded.isEmpty()) {
- Logging.finer("Updated: " + loaded.toString() + " for "
- + profile.getProfile().getPlayer().getName() + " for "
- + profile.getProfile().getContainerType() + ":" + profile.getProfile().getContainerName()
- + " (" + profile.getProfile().getProfileType() + ")");
- }
- if (!defaulted.isEmpty()) {
- Logging.finer("Defaulted: " + defaulted.toString() + " for "
- + profile.getProfile().getPlayer().getName() + " for "
- + profile.getProfile().getContainerType() + ":" + profile.getProfile().getContainerName()
- + " (" + profile.getProfile().getProfileType() + ")");
- }
- }
-
- private boolean isSharableUsed(Sharable> sharable) {
- if (sharable.isOptional()) {
- if (!inventories.getMVIConfig().getOptionalShares().contains(sharable)) {
- Logging.finest("Ignoring optional share: " + sharable.getNames()[0]);
- return false;
- }
- if (profile.getProfile().getContainerType() == ContainerType.WORLD
- && !inventories.getMVIConfig().usingOptionalsForUngrouped()) {
- Logging.finest("Ignoring optional share '" + sharable.getNames()[0] + "' for ungrouped world!");
- return false;
- }
- }
- return true;
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/WeakProfileContainer.java b/src/main/java/com/onarandombox/multiverseinventories/WeakProfileContainer.java
deleted file mode 100644
index eb34c970..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/WeakProfileContainer.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.multiverseinventories.profile.ProfileDataSource;
-import com.onarandombox.multiverseinventories.profile.ProfileKey;
-import com.onarandombox.multiverseinventories.profile.WorldGroupManager;
-import com.onarandombox.multiverseinventories.profile.ProfileTypes;
-import com.onarandombox.multiverseinventories.profile.container.ContainerType;
-import com.onarandombox.multiverseinventories.profile.PlayerProfile;
-import com.onarandombox.multiverseinventories.profile.container.ProfileContainer;
-import com.onarandombox.multiverseinventories.profile.ProfileType;
-import com.onarandombox.multiverseinventories.profile.container.ProfileContainerStore;
-import org.bukkit.OfflinePlayer;
-import org.bukkit.entity.Player;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-/**
- * Implementation of ProfileContainer using WeakHashMaps to keep memory usage to a minimum.
- */
-final class WeakProfileContainer implements ProfileContainer {
-
- private Map> playerData = new WeakHashMap<>();
- private final MultiverseInventories inventories;
- private final String name;
- private final ContainerType type;
-
- WeakProfileContainer(MultiverseInventories inventories, String name, ContainerType type) {
- this.inventories = inventories;
- this.name = name;
- this.type = type;
- }
-
- /**
- * Gets the stored profiles for this player, mapped by ProfileType.
- *
- * @param name The name of player to get profile map for.
- * @return The profile map for the given player.
- */
- protected Map getPlayerData(String name) {
- return this.playerData.computeIfAbsent(name, k -> new HashMap<>());
- }
-
- protected ProfileDataSource getDataSource() {
- return this.getInventories().getData();
- }
-
- protected WorldGroupManager getGroupManager() {
- return this.getInventories().getGroupManager();
- }
-
- protected ProfileContainerStore getProfileManager() {
- return this.getInventories().getWorldProfileContainerStore();
- }
-
- protected MultiverseInventories getInventories() {
- return this.inventories;
- }
-
- @Override
- public PlayerProfile getPlayerData(Player player) {
- ProfileType type;
- if (inventories.getMVIConfig().isUsingGameModeProfiles()) {
- type = ProfileTypes.forGameMode(player.getGameMode());
- } else {
- type = ProfileTypes.SURVIVAL;
- }
- return getPlayerData(type, player);
- }
-
- @Override
- public PlayerProfile getPlayerData(ProfileType profileType, OfflinePlayer player) {
- Map profileMap = this.getPlayerData(player.getName());
- PlayerProfile playerProfile = profileMap.get(profileType);
- if (playerProfile == null) {
- playerProfile = getDataSource().getPlayerData(getContainerType(),
- getContainerName(), profileType, player.getUniqueId());
- Logging.finer("[%s - %s - %s - %s] not cached, loading from disk...",
- profileType, getContainerType(), playerProfile.getContainerName(), player.getName());
- profileMap.put(profileType, playerProfile);
- }
- return playerProfile;
- }
-
- @Override
- public void addPlayerData(PlayerProfile playerProfile) {
- this.getPlayerData(playerProfile.getPlayer().getName()).put(playerProfile.getProfileType(), playerProfile);
- }
-
- @Override
- public void removeAllPlayerData(OfflinePlayer player) {
- this.getPlayerData(player.getName()).clear();
- this.getDataSource().removePlayerData(getContainerType(), getContainerName(), null, player.getName());
- }
-
- @Override
- public void removePlayerData(ProfileType profileType, OfflinePlayer player) {
- this.getPlayerData(player.getName()).remove(profileType);
- this.getDataSource().removePlayerData(getContainerType(), getContainerName(), profileType, player.getName());
- }
-
- @Override
- public String getContainerName() {
- return name;
- }
-
- @Override
- public ContainerType getContainerType() {
- return type;
- }
-
- @Override
- public void clearContainer() {
- for (Map profiles : playerData.values()) {
- for (PlayerProfile profile : profiles.values()) {
- this.getDataSource().clearProfileCache(ProfileKey.createProfileKey(profile));
- }
- }
- this.playerData.clear();
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/WeakProfileContainerStore.java b/src/main/java/com/onarandombox/multiverseinventories/WeakProfileContainerStore.java
deleted file mode 100644
index ad853c80..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/WeakProfileContainerStore.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.onarandombox.multiverseinventories.profile.container.ContainerType;
-import com.onarandombox.multiverseinventories.profile.container.ProfileContainer;
-import com.onarandombox.multiverseinventories.profile.container.ProfileContainerStore;
-
-import java.util.Map;
-import java.util.WeakHashMap;
-
-final class WeakProfileContainerStore implements ProfileContainerStore {
-
- private final Map containers = new WeakHashMap<>();
-
- private final MultiverseInventories inventories;
- private final ContainerType containerType;
-
- WeakProfileContainerStore(MultiverseInventories inventories, ContainerType containerType) {
- this.inventories = inventories;
- this.containerType = containerType;
- }
-
- private MultiverseInventories getInventories() {
- return this.inventories;
- }
-
- @Override
- public void addContainer(ProfileContainer container) {
- this.containers.put(container.getContainerName().toLowerCase(), container);
- }
-
- @Override
- public ProfileContainer getContainer(String containerName) {
- ProfileContainer container = this.containers.get(containerName.toLowerCase());
- if (container == null) {
- container = new WeakProfileContainer(this.getInventories(), containerName, containerType);
- addContainer(container);
- }
- return container;
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/WorldChangeShareHandler.java b/src/main/java/com/onarandombox/multiverseinventories/WorldChangeShareHandler.java
deleted file mode 100644
index 33662872..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/WorldChangeShareHandler.java
+++ /dev/null
@@ -1,231 +0,0 @@
-package com.onarandombox.multiverseinventories;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.multiverseinventories.event.ShareHandlingEvent;
-import com.onarandombox.multiverseinventories.event.WorldChangeShareHandlingEvent;
-import com.onarandombox.multiverseinventories.profile.PlayerProfile;
-import com.onarandombox.multiverseinventories.profile.container.ProfileContainer;
-import com.onarandombox.multiverseinventories.share.Sharables;
-import com.onarandombox.multiverseinventories.share.Shares;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.entity.Player;
-
-import java.util.List;
-
-/**
- * WorldChange implementation of ShareHandler.
- */
-final class WorldChangeShareHandler extends ShareHandler {
-
- private final String fromWorld;
- private final String toWorld;
- private final List fromWorldGroups;
- private final List toWorldGroups;
-
- WorldChangeShareHandler(MultiverseInventories inventories, Player player, String fromWorld, String toWorld) {
- super(inventories, player);
- this.fromWorld = fromWorld;
- this.toWorld = toWorld;
-
- // Get any groups we may need to save stuff to.
- this.fromWorldGroups = getAffectedWorldGroups(fromWorld);
- // Get any groups we may need to load stuff from.
- this.toWorldGroups = getAffectedWorldGroups(toWorld);
-
- prepareProfiles();
- }
-
- private List getAffectedWorldGroups(String world) {
- return this.inventories.getGroupManager().getGroupsForWorld(world);
- }
-
- @Override
- protected ShareHandlingEvent createEvent() {
- return new WorldChangeShareHandlingEvent(player, affectedProfiles, fromWorld, toWorld);
- }
-
- private void prepareProfiles() {
- Logging.finer("=== %s traveling from world: %s to world: %s ===", player.getName(), fromWorld, toWorld);
-
- setAlwaysWriteWorldProfile();
-
- if (isPlayerAffectedByChange()) {
- addProfiles();
- }
- }
-
- private void setAlwaysWriteWorldProfile() {
- // We will always save everything to the world they come from.
- PlayerProfile fromWorldProfile = getWorldPlayerProfile(fromWorld, player);
- setAlwaysWriteProfile(fromWorldProfile);
- }
-
- private PlayerProfile getWorldPlayerProfile(String world, Player player) {
- return getWorldProfile(world).getPlayerData(player);
- }
-
- private ProfileContainer getWorldProfile(String world) {
- return inventories.getWorldProfileContainerStore().getContainer(world);
- }
-
- private boolean isPlayerAffectedByChange() {
- if (isPlayerBypassingChange()) {
- logBypass();
- return false;
- }
- return true;
- }
-
- private boolean isPlayerBypassingChange() {
- return Perm.BYPASS_WORLD.hasBypass(player, fromWorld);
- }
-
- private void addProfiles() {
- addWriteProfiles();
- new ReadProfilesAggregator().addReadProfiles();
- }
-
- private void addWriteProfiles() {
- if (hasFromWorldGroups()) {
- fromWorldGroups.forEach(wg -> new WorldGroupWrapper(wg).conditionallyAddWriteProfiles());
- } else {
- Logging.finer("No groups for fromWorld.");
- }
- }
-
- private boolean hasFromWorldGroups() {
- return !fromWorldGroups.isEmpty();
- }
-
- private class ReadProfilesAggregator {
-
- private Shares sharesToRead;
-
- private void addReadProfiles() {
- sharesToRead = Sharables.noneOf();
- addReadProfilesFromToWorldGroups();
- useToWorldForMissingShares();
- }
-
- private void addReadProfilesFromToWorldGroups() {
- if (hasToWorldGroups()) {
- toWorldGroups.forEach(this::conditionallyAddReadProfileForWorldGroup);
- } else {
- Logging.finer("No groups for toWorld.");
- }
- }
-
- private boolean hasToWorldGroups() {
- return !toWorldGroups.isEmpty();
- }
-
- private void conditionallyAddReadProfileForWorldGroup(WorldGroup worldGroup) {
- if (isPlayerAffectedByChange(worldGroup)) {
- if (isFromWorldNotInToWorldGroup(worldGroup)) {
- addReadProfileForWorldGroup(worldGroup);
- } else {
- sharesToRead.addAll(worldGroup.getShares());
- }
- }
- }
-
- private boolean isPlayerAffectedByChange(WorldGroup worldGroup) {
- if (isPlayerBypassingChange(worldGroup)) {
- logBypass();
- return false;
- }
- return true;
- }
-
- private boolean isPlayerBypassingChange(WorldGroup worldGroup) {
- return Perm.BYPASS_GROUP.hasBypass(player, worldGroup.getName());
- }
-
- private boolean isFromWorldNotInToWorldGroup(WorldGroup worldGroup) {
- return !worldGroup.containsWorld(fromWorld);
- }
-
- private void addReadProfileForWorldGroup(WorldGroup worldGroup) {
- PlayerProfile playerProfile = getWorldGroupPlayerData(worldGroup);
- Shares sharesToAdd = getWorldGroupShares(worldGroup);
-
- addReadProfile(playerProfile, sharesToAdd);
- sharesToRead.addAll(sharesToAdd);
- }
-
- private PlayerProfile getWorldGroupPlayerData(WorldGroup worldGroup) {
- return getWorldGroupProfileContainer(worldGroup).getPlayerData(player);
- }
-
- private ProfileContainer getWorldGroupProfileContainer(WorldGroup worldGroup) {
- return worldGroup.getGroupProfileContainer();
- }
-
- private Shares getWorldGroupShares(WorldGroup worldGroup) {
- return Sharables.fromShares(worldGroup.getShares());
- }
-
- private void useToWorldForMissingShares() {
- // We need to fill in any sharables that are not going to be transferred with what's saved in the world file.
- if (hasUnhandledShares()) {
- addUnhandledSharesFromToWorld();
- }
- }
-
- private boolean hasUnhandledShares() {
- return !sharesToRead.isSharing(Sharables.all());
- }
-
- private void addUnhandledSharesFromToWorld() {
- Shares unhandledShares = Sharables.complimentOf(sharesToRead);
-
- Logging.finer("%s are left unhandled, defaulting to toWorld", unhandledShares);
-
- addReadProfile(getToWorldPlayerData(), unhandledShares);
- }
-
- private PlayerProfile getToWorldPlayerData() {
- return getToWorldProfileContainer().getPlayerData(player);
- }
-
- private ProfileContainer getToWorldProfileContainer() {
- return inventories.getWorldProfileContainerStore().getContainer(toWorld);
- }
- }
-
- private class WorldGroupWrapper {
- private final WorldGroup worldGroup;
-
- public WorldGroupWrapper(WorldGroup worldGroup) {
- this.worldGroup = worldGroup;
- }
-
- private void conditionallyAddWriteProfiles() {
- if (isEligibleForWrite()) {
- addWriteProfiles();
- }
- }
-
- boolean isEligibleForWrite() {
- return groupDoesNotContainWorld(toWorld) || isNotSharingAll();
- }
-
- private boolean groupDoesNotContainWorld(String world) {
- return !worldGroup.containsWorld(world);
- }
-
- private boolean isNotSharingAll() {
- return !worldGroup.getShares().isSharing(Sharables.all());
- }
-
- void addWriteProfiles() {
- ProfileContainer container = worldGroup.getGroupProfileContainer();
- affectedProfiles.addWriteProfile(container.getPlayerData(player), getWorldGroupShares());
- }
-
- private Shares getWorldGroupShares() {
- return Sharables.fromShares(worldGroup.getShares());
- }
- }
-
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/blacklist/ItemBlacklist.java b/src/main/java/com/onarandombox/multiverseinventories/blacklist/ItemBlacklist.java
deleted file mode 100644
index 049ca185..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/blacklist/ItemBlacklist.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.onarandombox.multiverseinventories.blacklist;
-
-/**
- * Placeholder.
- */
-public interface ItemBlacklist {
-
-
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/blacklist/SimpleItemBlacklist.java b/src/main/java/com/onarandombox/multiverseinventories/blacklist/SimpleItemBlacklist.java
deleted file mode 100644
index e0395f3b..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/blacklist/SimpleItemBlacklist.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.onarandombox.multiverseinventories.blacklist;
-
-/**
- * Simple Implementation of ItemBlacklist.
- */
-public class SimpleItemBlacklist implements ItemBlacklist {
-
-
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/blacklist/package-info.java b/src/main/java/com/onarandombox/multiverseinventories/blacklist/package-info.java
deleted file mode 100644
index bf4177e5..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/blacklist/package-info.java
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * This package contains classes related to Item Blacklisting per world group/world.
- * It is also very unfinished and likely to be refactored later.
- */
-package com.onarandombox.multiverseinventories.blacklist;
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/AddSharesCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/AddSharesCommand.java
deleted file mode 100644
index e3e98458..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/AddSharesCommand.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.share.Sharables;
-import com.onarandombox.multiverseinventories.share.Shares;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.command.CommandSender;
-
-import java.util.List;
-
-/**
- * The /mvinv addshares Command.
- * @deprecated Deprecated in favor of /mvinv group.
- */
-@Deprecated
-public class AddSharesCommand extends InventoriesCommand {
-
- public AddSharesCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("Adds share(s) to a World Group.");
- this.setCommandUsage("/mvinv addshares {SHARE[,EXTRA]} {GROUP}");
- this.setArgRange(2, 2);
- this.addKey("mvinv addshares");
- this.addKey("mvinv addshare");
- this.addKey("mvinv adds");
- this.addKey("mvinvas");
- this.addKey("mvinvadds");
- this.addKey("mvinvaddshares");
- this.addKey("mvinvaddshare");
- this.setPermission(Perm.COMMAND_ADDSHARES.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- Shares newShares;
- Shares negativeShares;
- if (args.get(0).contains("all") || args.get(0).contains("everything") || args.get(0).contains("*")) {
- newShares = Sharables.allOf();
- negativeShares = Sharables.noneOf();
- } else if (args.get(0).contains("-all") || args.get(0).contains("-everything") || args.get(0).contains("-*")) {
- negativeShares = Sharables.allOf();
- newShares = Sharables.noneOf();
- } else {
- negativeShares = Sharables.noneOf();
- newShares = Sharables.noneOf();
- String[] sharesString = args.get(0).split(",");
- for (String shareString : sharesString) {
- if (shareString.startsWith("-") && shareString.length() > 1) {
- Shares shares = Sharables.lookup(shareString.substring(1));
- if (shares == null) {
- continue;
- }
- negativeShares.setSharing(shares, true);
- } else {
- Shares shares = Sharables.lookup(shareString);
- if (shares == null) {
- continue;
- }
- newShares.setSharing(shares, true);
- }
- }
- }
- if (newShares.isEmpty() && negativeShares.isEmpty()) {
- this.messager.normal(Message.ERROR_NO_SHARES_SPECIFIED, sender, args.get(0));
- return;
- }
- WorldGroup worldGroup = this.plugin.getGroupManager().getGroup(args.get(1));
- if (worldGroup == null) {
- this.messager.normal(Message.ERROR_NO_GROUP, sender, args.get(1));
- return;
- }
- worldGroup.getShares().mergeShares(newShares);
- worldGroup.getShares().removeAll(negativeShares);
- this.plugin.getGroupManager().updateGroup(worldGroup);
- this.plugin.getMVIConfig().save();
- this.messager.normal(Message.NOW_SHARING, sender, worldGroup.getName(),
- worldGroup.getShares().toString());
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/AddWorldCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/AddWorldCommand.java
deleted file mode 100644
index e4812a0a..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/AddWorldCommand.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.Bukkit;
-import org.bukkit.World;
-import org.bukkit.command.CommandSender;
-
-import java.util.List;
-
-/**
- * The /mvinv addworld Command.
- * @deprecated Deprecated in favor of /mvinv group.
- */
-@Deprecated
-public class AddWorldCommand extends InventoriesCommand {
-
- public AddWorldCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("Adds a World to a World Group.");
- this.setCommandUsage("/mvinv addworld {WORLD} {GROUP}");
- this.setArgRange(2, 2);
- this.addKey("mvinv addworld");
- this.addKey("mvinv addw");
- this.addKey("mvinvaw");
- this.addKey("mvinvaddw");
- this.addKey("mvinvaddworld");
- this.setPermission(Perm.COMMAND_ADDWORLD.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- World world = Bukkit.getWorld(args.get(0));
- if (world == null) {
- this.messager.normal(Message.ERROR_NO_WORLD, sender, args.get(0));
- return;
- }
- WorldGroup worldGroup = this.plugin.getGroupManager().getGroup(args.get(1));
- if (worldGroup == null) {
- this.messager.normal(Message.ERROR_NO_GROUP, sender, args.get(1));
- return;
- }
- if (worldGroup.containsWorld(world.getName())) {
- this.messager.normal(Message.WORLD_ALREADY_EXISTS, sender, world.getName(),
- worldGroup.getName());
- return;
- }
- worldGroup.addWorld(world);
- this.plugin.getGroupManager().updateGroup(worldGroup);
- this.plugin.getMVIConfig().save();
- this.messager.normal(Message.WORLD_ADDED, sender, world.getName(),
- worldGroup.getName());
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/CreateGroupCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/CreateGroupCommand.java
deleted file mode 100644
index d9da3a99..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/CreateGroupCommand.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.command.CommandSender;
-
-import java.util.List;
-
-/**
- * The /mvinv creategroup Command.
- */
-public class CreateGroupCommand extends InventoriesCommand {
-
- public CreateGroupCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("Creates a new World Group with no worlds and no shares.");
- this.setCommandUsage("/mvinv creategroup {NAME}");
- this.setArgRange(1, 1);
- this.addKey("mvinv creategroup");
- this.addKey("mvinv createg");
- this.addKey("mvinv cg");
- this.addKey("mvinvcreategroup");
- this.addKey("mvinvcreateg");
- this.addKey("mvinvcg");
- this.setPermission(Perm.COMMAND_CREATEGROUP.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- WorldGroup worldGroup = this.plugin.getGroupManager().getGroup(args.get(0));
- if (worldGroup != null) {
- this.messager.normal(Message.GROUP_EXISTS, sender, args.get(0));
- return;
- }
-
- worldGroup = this.plugin.getGroupManager().newEmptyGroup(args.get(0));
- this.plugin.getGroupManager().updateGroup(worldGroup);
- this.messager.normal(Message.GROUP_CREATION_COMPLETE, sender);
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/DeleteGroupCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/DeleteGroupCommand.java
deleted file mode 100644
index dd8c903a..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/DeleteGroupCommand.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.command.CommandSender;
-
-import java.util.List;
-
-/**
- * The /mvinv deletegroup Command.
- */
-public class DeleteGroupCommand extends InventoriesCommand {
-
- public DeleteGroupCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("Deletes a World Group.");
- this.setCommandUsage("/mvinv deletegroup {NAME}");
- this.setArgRange(1, 1);
- this.addKey("mvinv deletegroup");
- this.addKey("mvinv deleteg");
- this.addKey("mvinv dg");
- this.addKey("mvinvdeletegroup");
- this.addKey("mvinvdeleteg");
- this.addKey("mvinvdg");
- this.setPermission(Perm.COMMAND_DELETEGROUP.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- WorldGroup worldGroup = this.plugin.getGroupManager().getGroup(args.get(0));
- if (worldGroup == null) {
- this.messager.normal(Message.ERROR_NO_GROUP, sender, args.get(0));
- return;
- }
-
- this.plugin.getGroupManager().removeGroup(worldGroup);
- this.messager.normal(Message.GROUP_REMOVED, sender, args.get(0));
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/GroupCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/GroupCommand.java
deleted file mode 100644
index e4baefc6..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/GroupCommand.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.command.prompts.GroupControlPrompt;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.command.CommandSender;
-import org.bukkit.conversations.Conversable;
-import org.bukkit.conversations.Conversation;
-import org.bukkit.conversations.ConversationFactory;
-
-import java.util.List;
-
-/**
- * The /mvi info Command.
- */
-public class GroupCommand extends InventoriesCommand {
-
- public GroupCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("Creates a world group.");
- this.setCommandUsage("/mvinv group");
- this.setArgRange(0, 0);
- this.addKey("mvinv group");
- this.addKey("mvinv g");
- this.addKey("mvinvgroup");
- this.addKey("mvinvg");
- this.setPermission(Perm.COMMAND_GROUP.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- if (!(sender instanceof Conversable)) {
- this.messager.normal(Message.NON_CONVERSABLE, sender);
- return;
- }
-
- Conversable conversable = (Conversable) sender;
- Conversation conversation = new ConversationFactory(this.plugin)
- .withFirstPrompt(new GroupControlPrompt(plugin, sender))
- .withEscapeSequence("##")
- .withModality(false).buildConversation(conversable);
- conversation.begin();
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/ImportCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/ImportCommand.java
deleted file mode 100644
index 1831351b..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/ImportCommand.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.migration.DataImporter;
-import com.onarandombox.multiverseinventories.migration.MigrationException;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.ChatColor;
-import org.bukkit.command.CommandSender;
-
-import java.util.List;
-
-/**
- * The /mvi info Command.
- */
-public class ImportCommand extends InventoriesCommand {
-
- public ImportCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("Import from MultiInv/WorldInventories");
- this.setCommandUsage("/mvinv import " + ChatColor.GREEN + "{MultiInv|WorldInventories}");
- this.setArgRange(1, 1);
- this.addKey("mvinv import");
- this.addKey("mvinvim");
- this.addKey("mvinvimport");
- this.setPermission(Perm.COMMAND_IMPORT.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- DataImporter importer = null;
- if (args.get(0).equalsIgnoreCase("MultiInv")) {
- importer = this.plugin.getImportManager().getMultiInvImporter();
- } else if (args.get(0).equalsIgnoreCase("WorldInventories")) {
- importer = this.plugin.getImportManager().getWorldInventoriesImporter();
- } else {
- this.messager.bad(Message.ERROR_PLUGIN_NOT_ENABLED,
- sender, args.get(0));
- return;
- }
- if (importer == null) {
- this.messager.bad(Message.ERROR_PLUGIN_NOT_ENABLED,
- sender, args.get(0));
- } else {
- try {
- importer.importData();
- } catch (MigrationException e) {
- Logging.severe(e.getMessage());
- Logging.severe("Cause: " + e.getCauseException().getMessage());
- }
- }
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/InfoCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/InfoCommand.java
deleted file mode 100644
index 8567b3a6..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/InfoCommand.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.profile.container.ProfileContainer;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * The /mvi info Command.
- */
-public class InfoCommand extends InventoriesCommand {
-
- public InfoCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("World and Group Information");
- this.setCommandUsage("/mvinv info " + ChatColor.GREEN + "[WORLD|GROUP]");
- this.setArgRange(0, 1);
- this.addKey("mvinv info");
- this.addKey("mvinvi");
- this.addKey("mvinvinfo");
- this.setPermission(Perm.COMMAND_INFO.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- String name;
- if (args.isEmpty()) {
- if (!(sender instanceof Player)) {
- this.messager.normal(Message.INFO_ZERO_ARG, sender);
- return;
- }
- name = ((Player) sender).getWorld().getName();
- } else {
- name = args.get(0);
- }
-
- ProfileContainer worldProfileContainer = this.plugin.getWorldProfileContainerStore().getContainer(name);
- messager.normal(Message.INFO_WORLD, sender, name);
- if (worldProfileContainer != null && Bukkit.getWorld(worldProfileContainer.getContainerName()) != null) {
- worldInfo(sender, worldProfileContainer);
- } else {
- messager.normal(Message.ERROR_NO_WORLD_PROFILE, sender, name);
- }
- WorldGroup worldGroup = this.plugin.getGroupManager().getGroup(name);
- this.messager.normal(Message.INFO_GROUP, sender, name);
- if (worldGroup != null) {
- this.groupInfo(sender, worldGroup);
- } else {
- this.messager.normal(Message.ERROR_NO_GROUP, sender, name);
- }
- }
-
- private void groupInfo(CommandSender sender, WorldGroup worldGroup) {
- StringBuilder worldsString = new StringBuilder();
- Set worlds = worldGroup.getWorlds();
- if (worlds.isEmpty()) {
- worldsString.append("N/A");
- } else {
- for (String world : worlds) {
- if (!worldsString.toString().isEmpty()) {
- worldsString.append(", ");
- }
- worldsString.append(world);
- }
- }
- this.messager.normal(Message.INFO_GROUPS_INFO,
- sender, worldsString, worldGroup.getShares().toString());
- }
-
- private void worldInfo(CommandSender sender, ProfileContainer worldProfileContainer) {
- StringBuilder groupsString = new StringBuilder();
- List worldGroups = this.plugin.getGroupManager()
- .getGroupsForWorld(worldProfileContainer.getContainerName());
-
- if (worldGroups.isEmpty()) {
- groupsString.append("N/A");
- } else {
- for (WorldGroup worldGroup : worldGroups) {
- if (!groupsString.toString().isEmpty()) {
- groupsString.append(", ");
- }
- groupsString.append(worldGroup.getName());
- }
- }
-
- this.messager.normal(Message.INFO_WORLD_INFO,
- sender, groupsString.toString());
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/InventoriesCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/InventoriesCommand.java
deleted file mode 100644
index c06378d7..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/InventoriesCommand.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.commandhandler.Command;
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.locale.Messager;
-import org.bukkit.command.CommandSender;
-
-import java.util.List;
-
-/**
- * A base command class to easily retrieve the plugin associated.
- */
-public abstract class InventoriesCommand extends Command {
-
- /**
- * Instance of MultiverseInventories.
- */
- protected MultiverseInventories plugin;
- /**
- * Instance of messager used for Inventories.
- */
- protected Messager messager;
-
- public InventoriesCommand(MultiverseInventories plugin) {
- super(plugin);
- this.plugin = plugin;
- this.messager = plugin.getMessager();
- }
-
- @Override
- public abstract void runCommand(CommandSender sender, List args);
-}
-
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/ListCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/ListCommand.java
deleted file mode 100644
index aacb289e..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/ListCommand.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.command.CommandSender;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * The /mvi info Command.
- */
-public class ListCommand extends InventoriesCommand {
-
- public ListCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("World and Group Information");
- this.setCommandUsage("/mvinv list");
- this.setArgRange(0, 0);
- this.addKey("mvinv list");
- this.addKey("mvinvl");
- this.addKey("mvinvlist");
- this.setPermission(Perm.COMMAND_LIST.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- Collection groups = this.plugin.getGroupManager().getGroups();
- String groupsString = "N/A";
- if (!groups.isEmpty()) {
- StringBuilder builder = new StringBuilder();
- for (WorldGroup group : groups) {
- if (!builder.toString().isEmpty()) {
- builder.append(", ");
- }
- builder.append(group.getName());
- }
- groupsString = builder.toString();
- }
- this.messager.normal(Message.LIST_GROUPS, sender, groupsString);
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/MigrateCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/MigrateCommand.java
deleted file mode 100644
index 70feb105..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/MigrateCommand.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.profile.container.ProfileContainer;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Set;
-
-/**
- * The /mvi info Command.
- */
-public class MigrateCommand extends InventoriesCommand {
-
- public MigrateCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("Migrate player data from one name to another");
- this.setCommandUsage("/mvinv migrate " + ChatColor.GREEN + "{OLDNAME} {NEWNAME} [saveold]");
- this.setArgRange(2, 3);
- this.addKey("mvinv migrate");
- this.addKey("mvinvmigrate");
- this.setPermission(Perm.COMMAND_INFO.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- String oldName = args.get(0);
- String newName = args.get(1);
- boolean deleteOld = true;
- if (args.size() > 2) {
- if (args.get(2).equalsIgnoreCase("saveold")) {
- deleteOld = false;
- }
- }
- try {
- plugin.getData().migratePlayerData(oldName, newName, Bukkit.getOfflinePlayer(newName).getUniqueId(), deleteOld);
- messager.good(Message.MIGRATE_SUCCESSFUL, sender, oldName, newName);
- } catch (IOException e) {
- Logging.severe("Could not migrate data from name " + oldName + " to " + newName);
- e.printStackTrace();
- messager.bad(Message.MIGRATE_FAILED, sender, oldName, newName);
- }
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/ReloadCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/ReloadCommand.java
deleted file mode 100644
index 45596191..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/ReloadCommand.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.multiverseinventories.util.Perm;
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.locale.Message;
-import org.bukkit.command.CommandSender;
-
-import java.util.List;
-
-/**
- * The /mvi info Command.
- */
-public class ReloadCommand extends InventoriesCommand {
-
- public ReloadCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("Reloads config file");
- this.setCommandUsage("/mvinv reload");
- this.setArgRange(0, 0);
- this.addKey("mvinv reload");
- this.addKey("mvinvreload");
- this.setPermission(Perm.COMMAND_RELOAD.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- this.plugin.reloadConfig();
- this.messager.normal(Message.RELOAD_COMPLETE, sender);
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/RemoveSharesCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/RemoveSharesCommand.java
deleted file mode 100644
index 72c08ea1..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/RemoveSharesCommand.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.share.Sharable;
-import com.onarandombox.multiverseinventories.share.Sharables;
-import com.onarandombox.multiverseinventories.share.Shares;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.command.CommandSender;
-
-import java.util.List;
-
-/**
- * The /mvinv rmshares Command.
- * @deprecated Deprecated in favor of /mvinv group.
- */
-@Deprecated
-public class RemoveSharesCommand extends InventoriesCommand {
-
- public RemoveSharesCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("Removes share(s) from a World Group.");
- this.setCommandUsage("/mvinv removeshares {SHARE[,EXTRA]} {GROUP}");
- this.setArgRange(2, 2);
- this.addKey("mvinv removeshares");
- this.addKey("mvinv rmshares");
- this.addKey("mvinv removeshare");
- this.addKey("mvinv rmshare");
- this.addKey("mvinv removes");
- this.addKey("mvinv rms");
- this.addKey("mvinvrs");
- this.addKey("mvinvrms");
- this.addKey("mvinvremoves");
- this.addKey("mvinvremoveshares");
- this.addKey("mvinvrmshares");
- this.addKey("mvinvremoveshare");
- this.addKey("mvinvrmshare");
- this.setPermission(Perm.COMMAND_RMSHARES.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- Shares newShares;
- if (args.get(0).contains("all") || args.get(0).contains("everything") || args.get(0).contains("*")) {
- newShares = Sharables.allOf();
- } else {
- newShares = Sharables.noneOf();
- String[] sharesString = args.get(0).split(",");
- for (String shareString : sharesString) {
- Shares shares = Sharables.lookup(shareString);
- if (shares == null) {
- continue;
- }
- newShares.setSharing(shares, true);
- }
- }
- if (newShares.isEmpty()) {
- this.messager.normal(Message.ERROR_NO_SHARES_SPECIFIED, sender, args.get(0));
- return;
- }
- WorldGroup worldGroup = this.plugin.getGroupManager().getGroup(args.get(1));
- if (worldGroup == null) {
- this.messager.normal(Message.ERROR_NO_GROUP, sender, args.get(1));
- return;
- }
- for (Sharable sharable : newShares) {
- worldGroup.getShares().setSharing(sharable, false);
- }
- this.plugin.getGroupManager().updateGroup(worldGroup);
- this.plugin.getMVIConfig().save();
- this.messager.normal(Message.NOW_SHARING, sender, worldGroup.getName(),
- worldGroup.getShares().toString());
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/RemoveWorldCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/RemoveWorldCommand.java
deleted file mode 100644
index f715295a..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/RemoveWorldCommand.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.Bukkit;
-import org.bukkit.World;
-import org.bukkit.command.CommandSender;
-
-import java.util.List;
-
-/**
- * The /mvinv rmworld Command.
- * @deprecated Deprecated in favor of /mvinv group.
- */
-@Deprecated
-public class RemoveWorldCommand extends InventoriesCommand {
-
- public RemoveWorldCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("Removes a World from a World Group.");
- this.setCommandUsage("/mvinv removeworld {WORLD} {GROUP}");
- this.setArgRange(2, 2);
- this.addKey("mvinv removeworld");
- this.addKey("mvinv rmworld");
- this.addKey("mvinv removew");
- this.addKey("mvinv rmw");
- this.addKey("mvinvrw");
- this.addKey("mvinvrmw");
- this.addKey("mvinvremovew");
- this.addKey("mvinvremoveworld");
- this.addKey("mvinvrmworld");
- this.setPermission(Perm.COMMAND_RMWORLD.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- World world = Bukkit.getWorld(args.get(0));
- if (world == null) {
- this.messager.normal(Message.ERROR_NO_WORLD, sender, args.get(0));
- return;
- }
- WorldGroup worldGroup = this.plugin.getGroupManager().getGroup(args.get(1));
- if (worldGroup == null) {
- this.messager.normal(Message.ERROR_NO_GROUP, sender, args.get(1));
- return;
- }
- if (!worldGroup.containsWorld(world.getName())) {
- this.messager.normal(Message.WORLD_NOT_IN_GROUP, sender, world.getName(),
- worldGroup.getName());
- return;
- }
- worldGroup.removeWorld(world);
- this.plugin.getGroupManager().updateGroup(worldGroup);
- this.plugin.getMVIConfig().save();
- this.messager.normal(Message.WORLD_REMOVED, sender, world.getName(),
- worldGroup.getName());
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/SpawnCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/SpawnCommand.java
deleted file mode 100644
index c7869ae1..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/SpawnCommand.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.MultiverseCore.api.MultiverseWorld;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.util.Perm;
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.locale.Message;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.Location;
-import org.bukkit.World;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-
-import java.util.List;
-
-/**
- * The /mvi info Command.
- */
-public class SpawnCommand extends InventoriesCommand {
-
- public SpawnCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("Spawn");
- this.setCommandUsage("/mvinv spawn" + ChatColor.GOLD + " [PLAYER]");
- this.setArgRange(0, 1);
- this.addKey("mvinv spawn");
- this.addKey("mvinvspawn");
- this.addKey("mvinvs");
- this.addKey("gspawn");
- this.addKey("ispawn");
- this.setPermission(Perm.COMMAND_SPAWN.getPermission());
- this.addAdditonalPermission(Perm.COMMAND_SPAWN_OTHER.getPermission());
-
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- Player player = null;
- if (sender instanceof Player) {
- player = (Player) sender;
- }
- // If a persons name was passed in, you must be A. the console, or B have permissions
- if (args.size() == 1) {
- Perm perm = Perm.COMMAND_SPAWN_OTHER;
- if (player != null && !perm.has(player)) {
- this.messager.normal(Message.GENERIC_COMMAND_NO_PERMISSION, player,
- perm.getPermission().getDescription(), perm.getPermission().getName());
- return;
- }
- Player target = Bukkit.getPlayerExact(args.get(0));
- if (target != null) {
- this.messager.normal(Message.TELEPORTING, target);
- spawnAccurately(target);
-
- if (player != null) {
- this.messager.normal(Message.TELEPORTED_BY, target,
- ChatColor.YELLOW + player.getName());
- } else {
- this.messager.normal(Message.TELEPORTED_BY, target,
- ChatColor.LIGHT_PURPLE + this.messager
- .getMessage(Message.GENERIC_THE_CONSOLE));
- }
- } else {
- this.messager.normal(Message.GENERIC_NOT_LOGGED_IN, sender, args.get(0));
- }
- } else {
- Perm perm = Perm.COMMAND_SPAWN;
- if (player != null && !perm.has(player)) {
- this.messager.normal(Message.GENERIC_COMMAND_NO_PERMISSION, player,
- perm.getPermission().getDescription(), perm.getPermission().getName());
- return;
- }
- if (player != null) {
- this.messager.normal(Message.TELEPORTING, player);
- spawnAccurately(player);
- } else {
- this.messager.normal(Message.TELEPORT_CONSOLE_ERROR, sender);
- }
- }
- }
-
- private void spawnAccurately(Player player) {
- World world = null;
- for (WorldGroup group : this.plugin.getGroupManager().getGroupsForWorld(player.getWorld().getName())) {
- if (group.getSpawnWorld() != null) {
- world = Bukkit.getWorld(group.getSpawnWorld());
- if (world != null) {
- break;
- }
- }
- }
- if (world == null) {
- world = player.getWorld();
- }
- MultiverseWorld mvWorld = this.plugin.getCore()
- .getMVWorldManager().getMVWorld(world);
- Location spawnLocation;
- if (mvWorld != null) {
- spawnLocation = mvWorld.getSpawnLocation();
- } else {
- spawnLocation = world.getSpawnLocation();
- }
- this.plugin.getCore().getSafeTTeleporter().safelyTeleport(player, player, spawnLocation, false);
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/ToggleCommand.java b/src/main/java/com/onarandombox/multiverseinventories/command/ToggleCommand.java
deleted file mode 100644
index f30e9401..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/ToggleCommand.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.onarandombox.multiverseinventories.command;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.share.Sharable;
-import com.onarandombox.multiverseinventories.share.Sharables;
-import com.onarandombox.multiverseinventories.share.Shares;
-import com.onarandombox.multiverseinventories.locale.Message;
-import com.onarandombox.multiverseinventories.util.Perm;
-import org.bukkit.command.CommandSender;
-
-import java.util.List;
-
-/**
- * The /mvi info Command.
- */
-public class ToggleCommand extends InventoriesCommand {
-
- public ToggleCommand(MultiverseInventories plugin) {
- super(plugin);
- this.setName("Toggles the usage of optional sharables");
- this.setCommandUsage("/mvinv toggle {SHARE}");
- this.setArgRange(1, 1);
- this.addKey("mvinv toggle");
- this.addKey("mvinv t");
- this.setPermission(Perm.COMMAND_ADDSHARES.getPermission());
- }
-
- @Override
- public void runCommand(CommandSender sender, List args) {
- Shares shares = Sharables.lookup(args.get(0).toLowerCase());
- if (shares == null) {
- this.messager.normal(Message.ERROR_NO_SHARES_SPECIFIED, sender);
- return;
- }
- boolean foundOpt = false;
- for (Sharable sharable : shares) {
- if (sharable.isOptional()) {
- foundOpt = true;
- if (this.plugin.getMVIConfig().getOptionalShares().contains(sharable)) {
- this.plugin.getMVIConfig().getOptionalShares().remove(sharable);
- this.messager.normal(Message.NOW_NOT_USING_OPTIONAL, sender, sharable.getNames()[0]);
- } else {
- this.plugin.getMVIConfig().getOptionalShares().add(sharable);
- this.messager.normal(Message.NOW_USING_OPTIONAL, sender, sharable.getNames()[0]);
- }
- }
- }
- if (foundOpt) {
- this.plugin.getMVIConfig().save();
- } else {
- this.messager.normal(Message.NO_OPTIONAL_SHARES, sender, args.get(0));
- }
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/package-info.java b/src/main/java/com/onarandombox/multiverseinventories/command/package-info.java
deleted file mode 100644
index 988881fa..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/package-info.java
+++ /dev/null
@@ -1,5 +0,0 @@
-/**
- * This package contains all Commands.
- */
-package com.onarandombox.multiverseinventories.command;
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupControlPrompt.java b/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupControlPrompt.java
deleted file mode 100644
index fa517717..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupControlPrompt.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.onarandombox.multiverseinventories.command.prompts;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.locale.Message;
-import org.bukkit.command.CommandSender;
-import org.bukkit.conversations.ConversationContext;
-import org.bukkit.conversations.Prompt;
-
-public class GroupControlPrompt extends InventoriesPrompt {
-
- public GroupControlPrompt(final MultiverseInventories plugin, final CommandSender sender) {
- super(plugin, sender);
- }
-
- @Override
- public String getPromptText(final ConversationContext conversationContext) {
- return messager.getMessage(Message.GROUP_COMMAND_PROMPT);
- }
-
- @Override
- public Prompt acceptInput(final ConversationContext conversationContext, final String s) {
- if (s.equalsIgnoreCase("delete")) {
- return new GroupDeletePrompt(plugin, sender);
- } else if (s.equalsIgnoreCase("create")) {
- return new GroupCreatePrompt(plugin, sender);
- } else if (s.equalsIgnoreCase("edit")) {
- return new GroupEditPrompt(plugin, sender);
- } else {
- messager.normal(Message.INVALID_PROMPT_OPTION, sender);
- return this;
- }
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupCreatePrompt.java b/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupCreatePrompt.java
deleted file mode 100644
index ea03e3c1..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupCreatePrompt.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.onarandombox.multiverseinventories.command.prompts;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.locale.Message;
-import org.bukkit.command.CommandSender;
-import org.bukkit.conversations.ConversationContext;
-import org.bukkit.conversations.Prompt;
-
-class GroupCreatePrompt extends InventoriesPrompt {
-
- public GroupCreatePrompt(final MultiverseInventories plugin, final CommandSender sender) {
- super(plugin, sender);
- }
-
- @Override
- public String getPromptText(final ConversationContext conversationContext) {
- return messager.getMessage(Message.GROUP_CREATE_PROMPT);
- }
-
- @Override
- public Prompt acceptInput(final ConversationContext conversationContext, final String s) {
- final WorldGroup group = plugin.getGroupManager().getGroup(s);
- if (group == null) {
- if (s.isEmpty() || !s.matches("^[a-zA-Z0-9][a-zA-Z0-9_]*$")) {
- messager.normal(Message.GROUP_INVALID_NAME, sender);
- return this;
- }
- final WorldGroup newGroup = plugin.getGroupManager().newEmptyGroup(s);
- return new GroupWorldsPrompt(plugin, sender, newGroup,
- new GroupSharesPrompt(plugin, sender, newGroup, Prompt.END_OF_CONVERSATION, true), true);
- } else {
- messager.normal(Message.GROUP_EXISTS, sender, s);
- }
- return Prompt.END_OF_CONVERSATION;
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupDeletePrompt.java b/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupDeletePrompt.java
deleted file mode 100644
index 12617b81..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupDeletePrompt.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.onarandombox.multiverseinventories.command.prompts;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.locale.Message;
-import org.bukkit.ChatColor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.conversations.ConversationContext;
-import org.bukkit.conversations.Prompt;
-
-class GroupDeletePrompt extends InventoriesPrompt {
-
- public GroupDeletePrompt(final MultiverseInventories plugin, final CommandSender sender) {
- super(plugin, sender);
- }
-
- @Override
- public String getPromptText(final ConversationContext conversationContext) {
- final StringBuilder builder = new StringBuilder();
- for (WorldGroup group : plugin.getGroupManager().getGroups()) {
- if (builder.length() == 0) {
- builder.append(ChatColor.WHITE);
- } else {
- builder.append(ChatColor.GOLD).append(", ").append(ChatColor.WHITE);
- }
- builder.append(group.getName());
- }
- return messager.getMessage(Message.GROUP_DELETE_PROMPT, builder.toString());
- }
-
- @Override
- public Prompt acceptInput(final ConversationContext conversationContext, final String s) {
- final WorldGroup group = plugin.getGroupManager().getGroup(s);
- if (group == null) {
- messager.normal(Message.ERROR_NO_GROUP, sender, s);
- } else {
- plugin.getGroupManager().removeGroup(group);
- messager.normal(Message.GROUP_REMOVED, sender, s);
- }
- return Prompt.END_OF_CONVERSATION;
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupEditPrompt.java b/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupEditPrompt.java
deleted file mode 100644
index 395e99f3..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupEditPrompt.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.onarandombox.multiverseinventories.command.prompts;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.locale.Message;
-import org.bukkit.ChatColor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.conversations.ConversationContext;
-import org.bukkit.conversations.Prompt;
-
-class GroupEditPrompt extends InventoriesPrompt {
-
- public GroupEditPrompt(final MultiverseInventories plugin, final CommandSender sender) {
- super(plugin, sender);
- }
-
- @Override
- public String getPromptText(final ConversationContext conversationContext) {
- final StringBuilder builder = new StringBuilder();
- for (WorldGroup group : plugin.getGroupManager().getGroups()) {
- if (builder.length() == 0) {
- builder.append(ChatColor.WHITE);
- } else {
- builder.append(ChatColor.GOLD).append(", ").append(ChatColor.WHITE);
- }
- builder.append(group.getName());
- }
- return messager.getMessage(Message.GROUP_EDIT_PROMPT, builder.toString());
- }
-
- @Override
- public Prompt acceptInput(final ConversationContext conversationContext, final String s) {
- final WorldGroup group = plugin.getGroupManager().getGroup(s);
- if (group == null) {
- messager.normal(Message.ERROR_NO_GROUP, sender, s);
- } else {
- return new GroupModifyPrompt(plugin, sender, group);
- }
- return Prompt.END_OF_CONVERSATION;
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupModifyPrompt.java b/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupModifyPrompt.java
deleted file mode 100644
index 87a4abd4..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupModifyPrompt.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.onarandombox.multiverseinventories.command.prompts;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.locale.Message;
-import org.bukkit.command.CommandSender;
-import org.bukkit.conversations.ConversationContext;
-import org.bukkit.conversations.Prompt;
-
-class GroupModifyPrompt extends InventoriesPrompt {
-
- protected final WorldGroup group;
-
- public GroupModifyPrompt(final MultiverseInventories plugin, final CommandSender sender,
- final WorldGroup group) {
- super(plugin, sender);
- this.group = group;
- }
-
- @Override
- public String getPromptText(final ConversationContext conversationContext) {
- return messager.getMessage(Message.GROUP_MODIFY_PROMPT, group.getName());
- }
-
- @Override
- public Prompt acceptInput(final ConversationContext conversationContext, final String s) {
- if (s.equalsIgnoreCase("worlds")) {
- return new GroupWorldsPrompt(plugin, sender, group, this, false);
- } else if (s.equalsIgnoreCase("shares")) {
- return new GroupSharesPrompt(plugin, sender, group, this, false);
- } else {
- messager.normal(Message.INVALID_PROMPT_OPTION, sender);
- return this;
- }
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupSharesPrompt.java b/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupSharesPrompt.java
deleted file mode 100644
index f2071f52..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupSharesPrompt.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.onarandombox.multiverseinventories.command.prompts;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.share.Sharable;
-import com.onarandombox.multiverseinventories.share.Sharables;
-import com.onarandombox.multiverseinventories.share.Shares;
-import com.onarandombox.multiverseinventories.locale.Message;
-import org.bukkit.ChatColor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.conversations.ConversationContext;
-import org.bukkit.conversations.Prompt;
-
-class GroupSharesPrompt extends InventoriesPrompt {
-
- protected final WorldGroup group;
- protected final Prompt nextPrompt;
- protected final boolean isCreating;
- protected final Shares shares;
-
- public GroupSharesPrompt(final MultiverseInventories plugin, final CommandSender sender,
- final WorldGroup group, final Prompt nextPrompt,
- final boolean creatingGroup) {
- super(plugin, sender);
- this.group = group;
- this.nextPrompt = nextPrompt;
- this.isCreating = creatingGroup;
- this.shares = Sharables.fromShares(group.getShares());
- }
-
- @Override
- public String getPromptText(final ConversationContext conversationContext) {
- final StringBuilder builder = new StringBuilder();
- for (final Sharable sharable : shares) {
- if (builder.length() == 0) {
- builder.append(ChatColor.WHITE);
- } else {
- builder.append(ChatColor.GOLD).append(", ").append(ChatColor.WHITE);
- }
- builder.append(sharable.toString());
- }
- return messager.getMessage(Message.GROUP_SHARES_PROMPT, group.getName(), builder.toString());
- }
-
- @Override
- public Prompt acceptInput(final ConversationContext conversationContext, final String s) {
- if (s.equals("@")) {
- group.getShares().clear();
- group.getShares().addAll(this.shares);
- plugin.getGroupManager().updateGroup(group);
- if (isCreating) {
- messager.normal(Message.GROUP_CREATION_COMPLETE, sender);
- } else {
- messager.normal(Message.GROUP_UPDATED, sender);
- }
- messager.normal(Message.INFO_GROUP, sender, group.getName());
- messager.normal(Message.INFO_GROUPS_INFO, sender, group.getWorlds(), group.getShares());
- plugin.getGroupManager().checkForConflicts(sender);
- return nextPrompt;
- }
-
- boolean negative = false;
- Shares shares = Sharables.lookup(s.toLowerCase());
- if (shares == null && s.startsWith("-") && s.length() > 1) {
- negative = true;
- shares = Sharables.lookup(s.toLowerCase().substring(1));
- }
-
- if (shares == null) {
- messager.normal(Message.ERROR_NO_SHARES_SPECIFIED, sender);
- return this;
- }
- if (negative) {
- this.shares.removeAll(shares);
- return this;
- }
- this.shares.addAll(shares);
- return this;
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupWorldsPrompt.java b/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupWorldsPrompt.java
deleted file mode 100644
index 6d428863..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/GroupWorldsPrompt.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.onarandombox.multiverseinventories.command.prompts;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.WorldGroup;
-import com.onarandombox.multiverseinventories.locale.Message;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.World;
-import org.bukkit.command.CommandSender;
-import org.bukkit.conversations.ConversationContext;
-import org.bukkit.conversations.Prompt;
-
-import java.util.HashSet;
-import java.util.Set;
-
-class GroupWorldsPrompt extends InventoriesPrompt {
-
- protected final WorldGroup group;
- protected final Prompt nextPrompt;
- protected final boolean isCreating;
- protected final Set worlds;
-
- public GroupWorldsPrompt(final MultiverseInventories plugin, final CommandSender sender,
- final WorldGroup group, final Prompt nextPrompt,
- final boolean creatingGroup) {
- super(plugin, sender);
- this.group = group;
- this.nextPrompt = nextPrompt;
- this.isCreating = creatingGroup;
- this.worlds = new HashSet(group.getWorlds());
- }
-
- @Override
- public String getPromptText(final ConversationContext conversationContext) {
- final StringBuilder builder = new StringBuilder();
- for (final String world : worlds) {
- if (builder.length() == 0) {
- builder.append(ChatColor.WHITE);
- } else {
- builder.append(ChatColor.GOLD).append(", ").append(ChatColor.WHITE);
- }
- builder.append(world);
- }
- return messager.getMessage(Message.GROUP_WORLDS_PROMPT, group.getName(), builder.toString());
- }
-
- @Override
- public Prompt acceptInput(final ConversationContext conversationContext, final String s) {
- if (s.equals("@")) {
- if (worlds.isEmpty()) {
- messager.normal(Message.GROUP_WORLDS_EMPTY, sender);
- return this;
- }
- group.removeAllWorlds(false);
- group.addWorlds(worlds, false);
- if (!isCreating) {
- plugin.getGroupManager().updateGroup(group);
- messager.normal(Message.GROUP_UPDATED, sender);
- messager.normal(Message.INFO_GROUP, sender, group.getName());
- messager.normal(Message.INFO_GROUPS_INFO, sender, group.getWorlds(), group.getShares());
- }
- return nextPrompt;
- }
-
- boolean negative = false;
- World world = Bukkit.getWorld(s);
- if (world == null && s.startsWith("-") && s.length() > 1) {
- negative = true;
- world = Bukkit.getWorld(s.substring(1));
- }
-
- if (world == null) {
- messager.normal(Message.ERROR_NO_WORLD, sender, s);
- return this;
- }
- if (negative) {
- if (!worlds.contains(world.getName())) {
- messager.normal(Message.WORLD_NOT_IN_GROUP, sender, world.getName(), group.getName());
- return this;
- }
- worlds.remove(world.getName());
- return this;
- }
- worlds.add(world.getName());
- return this;
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/InventoriesPrompt.java b/src/main/java/com/onarandombox/multiverseinventories/command/prompts/InventoriesPrompt.java
deleted file mode 100644
index 7ec9f212..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/command/prompts/InventoriesPrompt.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.onarandombox.multiverseinventories.command.prompts;
-
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.locale.Messager;
-import org.bukkit.command.CommandSender;
-import org.bukkit.conversations.ConversationContext;
-import org.bukkit.conversations.Prompt;
-
-abstract class InventoriesPrompt implements Prompt {
-
- protected final MultiverseInventories plugin;
- protected final Messager messager;
- protected final CommandSender sender;
-
- InventoriesPrompt(final MultiverseInventories plugin, final CommandSender sender) {
- this.plugin = plugin;
- this.messager = plugin.getMessager();
- this.sender = sender;
- }
-
- @Override
- public boolean blocksForInput(final ConversationContext conversationContext) {
- return true;
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/locale/LazyLocaleMessageProvider.java b/src/main/java/com/onarandombox/multiverseinventories/locale/LazyLocaleMessageProvider.java
deleted file mode 100644
index baf9c688..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/locale/LazyLocaleMessageProvider.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.onarandombox.multiverseinventories.locale;
-
-import java.util.Locale;
-import java.util.Set;
-
-/**
- * Multiverse 2 LazyMessageProvider
- *
- * This interface describes a Multiverse-MessageProvider that only loads locales when they're needed.
- */
-public interface LazyLocaleMessageProvider extends MessageProvider {
-
- /**
- * Loads a localization for a specified {@link Locale}.
- *
- * If that localization is already loaded, this method will reload it.
- *
- * @param locale The desired {@link Locale}.
- * @throws LocalizationLoadingException When an error occurs while trying to load the specified localization.
- * @throws NoSuchLocalizationException When no localization was found for the desired locale.
- */
- void loadLocale(Locale locale) throws NoSuchLocalizationException, // SUPPRESS CHECKSTYLE: Redundant
- LocalizationLoadingException; // SUPPRESS CHECKSTYLE: Redundant
-
- /**
- * Retrieves all loaded localizations.
- *
- * @return A {@link Set} of {@link Locale}s whose localizations are currently loaded.
- */
- Set getLoadedLocales();
-
- /**
- * Detects if a localization is loaded for the specified {@link Locale}.
- *
- * @param locale The {@link Locale}.
- * @return Whether a localization is loaded for the specified {@link Locale}.
- */
- boolean isLocaleLoaded(Locale locale);
-
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/locale/LocalizationLoadingException.java b/src/main/java/com/onarandombox/multiverseinventories/locale/LocalizationLoadingException.java
deleted file mode 100644
index f5bfea63..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/locale/LocalizationLoadingException.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.onarandombox.multiverseinventories.locale;
-
-import java.io.IOException;
-import java.util.Locale;
-
-/**
- * Thrown when an error occurs while a localization is loaded.
- */
-public class LocalizationLoadingException extends IOException {
- private final Locale locale;
-
- public LocalizationLoadingException(Locale locale) {
- this.locale = locale;
- }
-
- public LocalizationLoadingException(String message, Locale locale) {
- super(message);
- this.locale = locale;
- }
-
- public LocalizationLoadingException(Throwable cause, Locale locale) {
- super(cause);
- this.locale = locale;
- }
-
- public LocalizationLoadingException(String message, Throwable cause, Locale locale) {
- super(message, cause);
- this.locale = locale;
- }
-
- /**
- * Retrieves the locale that was attempting to be loaded.
- *
- * @return The locale that was attempting to be loaded.
- */
- public Locale getLocale() {
- return locale;
- }
-
- @Override
- public String getMessage() {
- return super.getMessage() + " (While trying to load localization for locale " + getLocale() + ")";
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/locale/Message.java b/src/main/java/com/onarandombox/multiverseinventories/locale/Message.java
deleted file mode 100644
index badd749d..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/locale/Message.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.onarandombox.multiverseinventories.locale;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * An enum containing all messages/strings used by Multiverse.
- */
-public enum Message {
- // BEGIN CHECKSTYLE-SUPPRESSION: Javadoc
- TEST_STRING("a test-string from the enum"),
-
- // Generic Strings
- GENERIC_SORRY("Sorry..."),
- GENERIC_PAGE("Page"),
- GENERIC_OF("of"),
- GENERIC_UNLOADED("UNLOADED"),
- GENERIC_PLUGIN_DISABLED("This plugin is Disabled!"),
- GENERIC_ERROR("[Error]"),
- GENERIC_SUCCESS("[Success]"),
- GENERIC_INFO("[Info]"),
- GENERIC_HELP("[Help]"),
- GENERIC_COMMAND_NO_PERMISSION("You do not have permission to %1. (%2)"),
- GENERIC_THE_CONSOLE("the console"),
- GENERIC_NOT_LOGGED_IN("%1 is not logged on right now!"),
- GENERIC_OFF("OFF"),
-
- // Errors
- ERROR_CONFIG_LOAD("Encountered an error while loading the configuration file. Disabling..."),
- ERROR_DATA_LOAD("Encountered an error while loading the data file. Disabling..."),
- ERROR_NO_GROUP("&6There is no group with the name: &f%1"),
- ERROR_NO_WORLD("&6There is no world with the name: &f%1"),
- ERROR_NO_WORLD_PROFILE("&6There is no profile container for the world: &f%1"),
- ERROR_PLUGIN_NOT_ENABLED("&f%1 &6is not enabled so you may not import data from it!"),
- ERROR_UNSUPPORTED_IMPORT("&6Sorry, ''&f%1&6'' is not supported for importing."),
- ERROR_NO_SHARES_SPECIFIED("&cYou did not specify any valid shares!"),
-
- // Group Conflicts
- CONFLICT_RESULTS("Conflict found for groups: '%1' and '%2' because they both share: '%3' for the world(s): '%4'"),
- CONFLICT_CHECKING("Checking for conflicts in groups..."),
- CONFLICT_FOUND("Conflicts have been found... If these are not resolved, you may experience problems with your data."),
- CONFLICT_NOT_FOUND("No group conflicts found!"),
-
- //// Commands
- NON_CONVERSABLE("You are not allowed to access conversations (remote console?)"),
- INVALID_PROMPT_OPTION("&cThat is not a valid option! Type &f##&c to stop working on groups."),
- // Info Command
- INFO_ZERO_ARG("You may only use the no argument version of this command in game!"),
- INFO_WORLD("&b===[ Info for world: &6%1&b ]==="),
- INFO_WORLD_INFO("&6Groups:&f %1"),
- INFO_GROUP("&b===[ Info for group: &6%1&b ]==="),
- INFO_GROUPS_INFO("&6Worlds:&f %1", "&bShares:&f %2"),
- // Group Command
- GROUP_COMMAND_PROMPT("&6What would you like to do? &fCreate&6, &fEdit &6or &fDelete&6. Enter &f##&6 at any time to cancel."),
- GROUP_CREATE_PROMPT("&6Please name your new group: "),
- GROUP_EDIT_PROMPT("&6Edit which group? %1"),
- GROUP_DELETE_PROMPT("&6Delete which group? %1"),
- GROUP_MODIFY_PROMPT("&6Which would you like to change for &e%1&6? &fWorlds &6or &fShares&6. Enter &f##&6 to finish."),
- GROUP_WORLDS_PROMPT("&6Enter the name of a world to add to group &f%1&6 or enter &f@&6 to continue. To remove a world, precede the name with the minus symbol. (ex: &f-worldname&6). Current worlds: %2"),
- GROUP_SHARES_PROMPT("&6Enter &fall&6 or a specific share to add to group &f%1&6 or enter &f@&6 to continue. To remove shares, precede the name with the minus symbol (ex: &f-inventory&6). Current shares: %2"),
- GROUP_INVALID_NAME("&cThat name is not valid! May only contain letters, numbers, and underscores."),
- GROUP_EXISTS("&cThat group already exists! (&f%1&c)"),
- GROUP_REMOVED("&2Removed group: &f%1"),
- GROUP_WORLDS_EMPTY("&cYou may not have a group with no worlds, please add worlds or type &f##&c to cancel."),
- GROUP_CREATION_COMPLETE("&2You created a new group!"),
- GROUP_UPDATED("&2Group has been updated!"),
- // List Command
- LIST_GROUPS("&b===[ Group List ]===", "&6Groups:&f %1"),
- // Reload Command
- RELOAD_COMPLETE("&b===[ Reload Complete! ]==="),
- // AddWorld Command
- WORLD_ADDED("&6World:&f %1 &6added to Group: &f%2"),
- WORLD_ALREADY_EXISTS("&6World:&f %1 &6already part of Group: &f%2"),
- // RemoveWorld Command
- WORLD_REMOVED("&6World:&f %1 &6removed from Group: &f%2"),
- WORLD_NOT_IN_GROUP("&6World:&f %1 &6is not part of Group: &f%2"),
- // AddShares Command
- NOW_SHARING("&6Group: &f%1 &6is now sharing: &f%2"),
- // Spawn Command
- TELEPORTING("Teleporting to this world group's spawn..."),
- TELEPORTED_BY("You were teleported by: %1"),
- TELEPORT_CONSOLE_ERROR("From the console, you must provide a PLAYER"),
- // DebugCommand
- INVALID_DEBUG("&fInvalid debug level. Please use number 0-3. &b(3 being many many messages!)"),
- DEBUG_SET("Debug mode is %1"),
- // Toggle Command
- NOW_USING_OPTIONAL("&f%1 &6will now be considered when player's change world."),
- NOW_NOT_USING_OPTIONAL("&f%1 &6will no longer be considered when player's change world."),
- NO_OPTIONAL_SHARES("&f%1 &6is not an optional share!"),
- // Migrate Command
- MIGRATE_FAILED("Failed to migrate data from %1 to %2! Check logs for error details."),
- MIGRATE_SUCCESSFUL("Migrated data from %1 to %2!");
-
- // BEGIN CHECKSTYLE-SUPPRESSION: Javadoc
-
- private final List def;
-
- Message(String def, String... extra) {
- this.def = new ArrayList();
- this.def.add(def);
- this.def.addAll(Arrays.asList(extra));
- }
-
- /**
- * @return This {@link Message}'s default-message
- */
- public List getDefault() {
- return def;
- }
-
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/locale/MessageProvider.java b/src/main/java/com/onarandombox/multiverseinventories/locale/MessageProvider.java
deleted file mode 100644
index 815a8311..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/locale/MessageProvider.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package com.onarandombox.multiverseinventories.locale;
-
-import java.util.List;
-import java.util.Locale;
-
-/**
- * Multiverse 2 MessageProvider.
- *
- * This interface describes a Multiverse-MessageProvider.
- */
-public interface MessageProvider {
- /**
- * The default locale.
- */
- Locale DEFAULT_LOCALE = Locale.ENGLISH;
-
- /**
- * Returns a message (as {@link String}) for the specified key (as {@link Message}).
- *
- * @param key The key
- * @param args Args for String.format()
- * @return The message
- */
- String getMessage(Message key, Object... args);
-
- /**
- * Returns a message (as {@link String}) in a specified {@link Locale} for the specified key (as {@link Message}).
- *
- * @param key The Key
- * @param locale The {@link Locale}
- * @param args Args for String.format()
- * @return The message
- */
- String getMessage(Message key, Locale locale, Object... args);
-
- /**
- * Returns a message (as {@link List}) of Strings for the specified key (as {@link Message}).
- *
- * @param key The key
- * @param args Args for String.format()
- * @return The messages
- */
- List getMessages(Message key, Object... args);
-
- /**
- * Returns a message (as {@link List}) of Strings in a specified {@link Locale} for the specified key (as {@link Message}).
- *
- * @param key The key
- * @param locale The {@link Locale}
- * @param args Args for String.format()
- * @return The messages
- */
- List getMessages(Message key, Locale locale, Object... args);
-
- /**
- * Returns the Locale this MessageProvider is currently using.
- *
- * @return The locale this MessageProvider is currently using.
- */
- Locale getLocale();
-
- /**
- * Sets the locale for this MessageProvider.
- *
- * @param locale The new {@link Locale}.
- */
- void setLocale(Locale locale);
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/locale/Messager.java b/src/main/java/com/onarandombox/multiverseinventories/locale/Messager.java
deleted file mode 100644
index 86ed0110..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/locale/Messager.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.onarandombox.multiverseinventories.locale;
-
-import org.bukkit.command.CommandSender;
-
-import java.util.List;
-
-/**
- * This interface describes a Messager which sends messages to CommandSenders.
- */
-public interface Messager extends MessageProvider {
-
- /**
- * Sends a message to the specified player with the generic ERROR prefix.
- *
- * @param message The message to send.
- * @param sender The entity to send the messages to.
- * @param args arguments for String.format().
- */
- void bad(Message message, CommandSender sender, Object... args);
-
- /**
- * Sends a message to the specified player with NO special prefix.
- *
- * @param message The message to send.
- * @param sender The entity to send the messages to.
- * @param args arguments for String.format().
- */
- void normal(Message message, CommandSender sender, Object... args);
-
- /**
- * Sends a message to the specified player with the generic SUCCESS prefix.
- *
- * @param message The message to send.
- * @param sender The entity to send the messages to.
- * @param args arguments for String.format().
- */
- void good(Message message, CommandSender sender, Object... args);
-
- /**
- * Sends a message to the specified player with the generic INFO prefix.
- *
- * @param message The message to send.
- * @param sender The entity to send the messages to.
- * @param args arguments for String.format().
- */
- void info(Message message, CommandSender sender, Object... args);
-
- /**
- * Sends a message to the specified player with the generic HELP prefix.
- *
- * @param message The message to send.
- * @param sender The entity to send the messages to.
- * @param args arguments for String.format().
- */
- void help(Message message, CommandSender sender, Object... args);
-
- /**
- * Sends a message to a player that automatically takes words that are too long and puts them on a new line.
- *
- * @param player Player to send message to.
- * @param message Message to send.
- */
- void sendMessage(CommandSender player, String message);
-
- /**
- * Sends a message to a player that automatically takes words that are too long and puts them on a new line.
- *
- * @param player Player to send message to.
- * @param messages Messages to send.
- */
- void sendMessages(CommandSender player, List messages);
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/locale/Messaging.java b/src/main/java/com/onarandombox/multiverseinventories/locale/Messaging.java
deleted file mode 100644
index 971b4978..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/locale/Messaging.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.onarandombox.multiverseinventories.locale;
-
-/**
- * This interface is implemented by classes that use a {@link Messager}.
- */
-public interface Messaging {
-
- /**
- * @return The {@link Messager} used by the Plugin.
- */
- Messager getMessager();
-
- /**
- * Sets the {@link Messager} used by the Plugin.
- *
- * @param messager The new {@link Messager}. Must not be null!
- */
- void setMessager(Messager messager);
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/locale/NoSuchLocalizationException.java b/src/main/java/com/onarandombox/multiverseinventories/locale/NoSuchLocalizationException.java
deleted file mode 100644
index 31dd92ae..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/locale/NoSuchLocalizationException.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.onarandombox.multiverseinventories.locale;
-
-import java.util.Locale;
-
-/**
- * Thrown when the requested localization is not found.
- */
-public class NoSuchLocalizationException extends LocalizationLoadingException {
-
- public NoSuchLocalizationException(Locale locale) {
- super(locale);
- }
-
- public NoSuchLocalizationException(String message, Locale locale) {
- super(message, locale);
- }
-
- public NoSuchLocalizationException(String message, Throwable cause, Locale locale) {
- super(message, cause, locale);
- }
-
- public NoSuchLocalizationException(Throwable cause, Locale locale) {
- super(cause, locale);
- }
-
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/locale/package-info.java b/src/main/java/com/onarandombox/multiverseinventories/locale/package-info.java
deleted file mode 100644
index 6279ccea..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/locale/package-info.java
+++ /dev/null
@@ -1,5 +0,0 @@
-/**
- * This package contains Multiverse-Inventories localization features.
- */
-package com.onarandombox.multiverseinventories.locale;
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/migration/DataImporter.java b/src/main/java/com/onarandombox/multiverseinventories/migration/DataImporter.java
deleted file mode 100644
index e97a5fbd..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/migration/DataImporter.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.onarandombox.multiverseinventories.migration;
-
-import org.bukkit.plugin.Plugin;
-
-/**
- * Interface for data migration importers.
- */
-public interface DataImporter {
-
- /**
- * Imports the data from another plugin.
- *
- * @throws MigrationException If there was any MAJOR issue loading the data.
- */
- void importData() throws MigrationException;
-
- /**
- * @return The plugin associated with this Importer.
- */
- Plugin getPlugin();
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/migration/ImportManager.java b/src/main/java/com/onarandombox/multiverseinventories/migration/ImportManager.java
deleted file mode 100644
index b1eefaeb..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/migration/ImportManager.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.onarandombox.multiverseinventories.migration;
-
-import com.dumptruckman.minecraft.util.Logging;
-import com.onarandombox.multiverseinventories.MultiverseInventories;
-import com.onarandombox.multiverseinventories.migration.multiinv.MultiInvImporter;
-import com.onarandombox.multiverseinventories.migration.worldinventories.WorldInventoriesImporter;
-import me.drayshak.WorldInventories.WorldInventories;
-import uk.co.tggl.pluckerpluck.multiinv.MultiInv;
-
-/**
- * Manages the import heplers for other similar plugins.
- */
-public class ImportManager {
-
- private MultiInvImporter multiInvImporter = null;
- private WorldInventoriesImporter worldInventoriesImporter = null;
- private MultiverseInventories inventories;
-
- public ImportManager(MultiverseInventories inventories) {
- this.inventories = inventories;
- }
-
- /**
- * Hooks MultiInv for importing it's data.
- *
- * @param plugin Instance of MultiInv.
- */
- public void hookMultiInv(MultiInv plugin) {
- this.multiInvImporter = new MultiInvImporter(this.inventories, plugin);
- Logging.info("Hooked MultiInv for importing!");
- }
-
- /**
- * Hooks WorldInventories for importing it's data.
- *
- * @param plugin Instance of WorldInventories.
- */
- public void hookWorldInventories(WorldInventories plugin) {
- this.worldInventoriesImporter = new WorldInventoriesImporter(this.inventories, plugin);
- Logging.info("Hooked WorldInventories for importing!");
- }
-
- /**
- * @return The MultiInv importer class or null if not hooked.
- */
- public MultiInvImporter getMultiInvImporter() {
- return this.multiInvImporter;
- }
-
- /**
- * @return The WorldInventories importer class or null if not hooked.
- */
- public WorldInventoriesImporter getWorldInventoriesImporter() {
- return this.worldInventoriesImporter;
- }
-
- /**
- * Un-hooks MultiInv so we're not able to import from it anymore.
- */
- public void unHookMultiInv() {
- this.multiInvImporter = null;
- }
-
- /**
- * Un-hooks WorldInventories so we're not able to import from it anymore.
- */
- public void unHookWorldInventories() {
- this.worldInventoriesImporter = null;
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/migration/MigrationException.java b/src/main/java/com/onarandombox/multiverseinventories/migration/MigrationException.java
deleted file mode 100644
index c169b378..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/migration/MigrationException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.onarandombox.multiverseinventories.migration;
-
-/**
- * Exception thrown when migration doesn't go well.
- */
-public class MigrationException extends Exception {
-
- private Exception causeException = null;
-
- public MigrationException(String message) {
- super(message);
- }
-
- /**
- * Sets what the causing exception was, if any.
- *
- * @param exception The cause exception.
- * @return This exception for easy chainability.
- */
- public MigrationException setCauseException(Exception exception) {
- this.causeException = exception;
- return this;
- }
-
- /**
- * @return The causing exception or null if none.
- */
- public Exception getCauseException() {
- return this.causeException;
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/migration/package-info.java b/src/main/java/com/onarandombox/multiverseinventories/migration/package-info.java
deleted file mode 100644
index 139a8dbc..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/migration/package-info.java
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * This package contains thigns to help with importing player stats/inventory data from
- * other similar plugins.
- */
-package com.onarandombox.multiverseinventories.migration;
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/profile/GlobalProfile.java b/src/main/java/com/onarandombox/multiverseinventories/profile/GlobalProfile.java
deleted file mode 100644
index 77c8c58b..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/profile/GlobalProfile.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.onarandombox.multiverseinventories.profile;
-
-import org.bukkit.Bukkit;
-
-import java.util.UUID;
-
-/**
- * The global profile for a player which contains meta-data for the player.
- */
-public final class GlobalProfile {
-
- /**
- * Creates a global profile object for the given player with default values.
- *
- * @param playerName the player to create the profile object for.
- * @return a new GlobalProfile for the given player.
- * @deprecated Needs to use UUID.
- */
- @Deprecated
- public static GlobalProfile createGlobalProfile(String playerName) {
- return new GlobalProfile(playerName, Bukkit.getOfflinePlayer(playerName).getUniqueId());
- }
-
- /**
- * Creates a global profile object for the given player with default values.
- *
- * @param playerName the player to create the profile object for.
- * @param playerUUID the UUID of the player to create the profile for.
- * @return a new GlobalProfile for the given player.
- */
- public static GlobalProfile createGlobalProfile(String playerName, UUID playerUUID) {
- return new GlobalProfile(playerName, playerUUID);
- }
-
- private final UUID uuid;
- private String lastWorld = null;
- private String lastKnownName;
- private boolean loadOnLogin = false;
-
- private GlobalProfile(String name, UUID uuid) {
- this.uuid = uuid;
- this.lastKnownName = name;
- }
-
- /**
- * Returns the name of the player.
- *
- * @return The name of the player.
- * @deprecated Use {@link #getPlayerUUID()} to uniquely identify a player.
- * If you need player name, use {@link #getLastKnownName()}.
- */
- @Deprecated
- public String getPlayerName() {
- return this.lastKnownName;
- }
-
- /**
- * Returns the UUID of the player.
- *
- * @return the UUID of the player.
- */
- public UUID getPlayerUUID() {
- return uuid;
- }
-
- /**
- * Returns the last name the player was known to have.
- *
- * @return the last name the player was known to have.
- */
- public String getLastKnownName() {
- return lastKnownName;
- }
-
- /**
- * Sets the last name that the player was seen having.
- * This should be updated when a player's name is changed through Mojang but only after their data has been
- * migrated to the new name.
- *
- * @param lastKnownName the last known name for the player.
- */
- public void setLastKnownName(String lastKnownName) {
- this.lastKnownName = lastKnownName;
- }
-
- /**
- * Returns the name of last world the player was in.
- *
- * @return The last world the player was in or null if not set.
- */
- public String getLastWorld() {
- return this.lastWorld;
- }
-
- /**
- * Says whether the player data for the player's logout world should be loaded when the player logs in.
- * The default value is false.
- *
- * @return true if player data should be loaded when they log in.
- */
- public boolean shouldLoadOnLogin() {
- return loadOnLogin;
- }
-
- /**
- * Sets whether the player data for the player's logout world should be loaded when the player logs in.
- *
- * @param loadOnLogin true if player data should be loaded when they log in.
- */
- public void setLoadOnLogin(boolean loadOnLogin) {
- this.loadOnLogin = loadOnLogin;
- }
-
- /**
- * Sets the last world the player was known to be in. This is done automatically on world change.
- *
- * @param world The world the player is in.
- */
- public void setLastWorld(String world) {
- this.lastWorld = world;
- }
-
- @Override
- public String toString() {
- return "GlobalProfile{" +
- "uuid=" + uuid +
- ", lastWorld='" + lastWorld + '\'' +
- ", lastKnownName='" + lastKnownName + '\'' +
- ", loadOnLogin=" + loadOnLogin +
- '}';
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/profile/PlayerProfile.java b/src/main/java/com/onarandombox/multiverseinventories/profile/PlayerProfile.java
deleted file mode 100644
index 2755e949..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/profile/PlayerProfile.java
+++ /dev/null
@@ -1,134 +0,0 @@
-package com.onarandombox.multiverseinventories.profile;
-
-import com.onarandombox.multiverseinventories.share.Sharable;
-import com.onarandombox.multiverseinventories.share.SharableEntry;
-import com.onarandombox.multiverseinventories.profile.container.ContainerType;
-import org.bukkit.Bukkit;
-import org.bukkit.OfflinePlayer;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * Contains all the world/group specific data for a player.
- */
-public final class PlayerProfile implements Cloneable, Iterable {
-
- public static PlayerProfile createPlayerProfile(ContainerType containerType, String containerName,
- ProfileType profileType, OfflinePlayer player) {
- return new PlayerProfile(containerType, containerName, profileType, player);
- }
-
- /**
- * @deprecated Needs to use UUID for players
- */
- @Deprecated
- public static PlayerProfile createPlayerProfile(ContainerType containerType, String containerName,
- ProfileType profileType, String playerName) {
- return new PlayerProfile(containerType, containerName, profileType, Bukkit.getOfflinePlayer(playerName));
- }
-
- private Map data = new HashMap();
-
- private final OfflinePlayer player;
- private final ContainerType containerType;
- private final String containerName;
- private final ProfileType profileType;
-
- private PlayerProfile(ContainerType containerType, String containerName, ProfileType profileType, OfflinePlayer player) {
- this.containerType = containerType;
- this.profileType = profileType;
- this.containerName = containerName;
- this.player = player;
- }
-
- /**
- * @return The container type of profile, a group or world.
- */
- public ContainerType getContainerType() {
- return this.containerType;
- }
-
- /**
- * @return The name of the container, world or group, containing this profile.
- */
- public String getContainerName() {
- return this.containerName;
- }
-
- /**
- * @return the Player associated with this profile.
- */
- public OfflinePlayer getPlayer() {
- return this.player;
- }
-
- /**
- * @return The type of profile this object represents.
- */
- public ProfileType getProfileType() {
- return this.profileType;
- }
-
- /**
- * Retrieves the profile's value of the {@link Sharable} passed in.
- *
- * @param sharable Represents the key for the data wanted from the profile.
- * @param This indicates the type of return value to be expected.
- * @return The value of the sharable for this profile. Null if no value is set.
- */
- public T get(Sharable sharable) {
- SharableEntry entry = this.data.get(sharable);
- return sharable.getType().cast(entry != null ? entry.getValue() : null);
- }
-
- /**
- * Sets the profile's value for the {@link Sharable} passed in.
- *
- * @param sharable Represents the key for the data to store.
- * @param value The value of the data.
- * @param The type of value to be expected.
- */
- public void set(Sharable sharable, T value) {
- this.data.put(sharable, new SharableEntry(sharable, value));
- }
-
- public PlayerProfile clone() {
- try {
- return (PlayerProfile) super.clone();
- } catch (CloneNotSupportedException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public Iterator iterator() {
- return new SharablesIterator(data.values().iterator());
- }
-
- private static class SharablesIterator implements Iterator {
-
- private final Iterator backingIterator;
-
- private SharablesIterator(Iterator backingIterator) {
- this.backingIterator = backingIterator;
- }
-
- @Override
- public boolean hasNext() {
- return backingIterator.hasNext();
- }
-
- @Override
- public SharableEntry next() {
- return backingIterator.next();
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/profile/ProfileDataSource.java b/src/main/java/com/onarandombox/multiverseinventories/profile/ProfileDataSource.java
deleted file mode 100644
index 15427986..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/profile/ProfileDataSource.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package com.onarandombox.multiverseinventories.profile;
-
-import com.onarandombox.multiverseinventories.profile.container.ContainerType;
-
-import java.io.IOException;
-import java.util.UUID;
-
-/**
- * A source for updating and retrieving player profiles via persistence.
- */
-public interface ProfileDataSource {
-
- /**
- * Updates the persisted data for a player for a specific profile.
- *
- *
- * @param playerProfile The profile for the player that is being updated.
- */
- void updatePlayerData(PlayerProfile playerProfile);
-
- /**
- * Retrieves a PlayerProfile from the data source.
- *
- * @param containerType The type of container this profile is part of, world or group.
- * @param dataName World/Group to retrieve from.
- * @param profileType The type of profile to load data for, typically based on game mode.
- * @param playerUUID UUID of the player to retrieve for.
- * @return The player as returned from data. If no data was found, a new PlayerProfile will be
- * created.
- */
- PlayerProfile getPlayerData(ContainerType containerType, String dataName, ProfileType profileType, UUID playerUUID);
-
- /**
- * Removes the persisted data for a player for a specific profile.
- *
- * @param containerType The type of container this profile is part of, world or group.
- * @param dataName The name of the world/group the player's data is associated with.
- * @param profileType The type of profile we're removing, as per {@link ProfileType}. If null, this will remove
- * remove all profile types.
- * @param playerName The name of the player whose data is being removed.
- * @return True if successfully removed.
- */
- boolean removePlayerData(ContainerType containerType, String dataName, ProfileType profileType, String playerName);
-
- /**
- * Retrieves the global profile for a player which contains meta-data for the player.
- *
- * @param playerName The name of player to retrieve for.
- * @return The global profile for the specified player.
- * @deprecated UUID must be supported now.
- */
- @Deprecated
- GlobalProfile getGlobalProfile(String playerName);
-
- /**
- * Retrieves the global profile for a player which contains meta-data for the player.
- *
- * @param playerName The name of the player to retrieve for. This is required for updating name last known as.
- * @param playerUUID The UUID of the player.
- * @return the global profile for the player with the given UUID.
- */
- GlobalProfile getGlobalProfile(String playerName, UUID playerUUID);
-
- /**
- * Update the file for a player's global profile.
- *
- * @param globalProfile The GlobalProfile object to update the file for.
- * @return True if data successfully saved to file.
- */
- boolean updateGlobalProfile(GlobalProfile globalProfile);
-
- /**
- * A convenience method to update the GlobalProfile of a player with a specified world.
- *
- * @param playerName The player whose global profile this will update.
- * @param worldName The world to update the global profile with.
- */
- void updateLastWorld(String playerName, String worldName);
-
- /**
- * A convenience method for setting whether player data should be loaded on login for the specified player.
- *
- * @param playerName The player whose data should be loaded.
- * @param loadOnLogin Whether or not to load on login.
- */
- void setLoadOnLogin(String playerName, boolean loadOnLogin);
-
- /**
- * Copies all the data belonging to oldName to newName and removes the old data.
- *
- * @param oldName the previous name of the player.
- * @param newName the new name of the player.
- * @param playerUUID the UUID of the player.
- * @param removeOldData whether or not to remove the data belonging to oldName.
- * @throws IOException Thrown if something goes wrong while migrating the files.
- */
- void migratePlayerData(String oldName, String newName, UUID playerUUID, boolean removeOldData) throws IOException;
-
- /**
- * Clears a single profile in cache.
- */
- void clearProfileCache(ProfileKey key);
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/profile/ProfileKey.java b/src/main/java/com/onarandombox/multiverseinventories/profile/ProfileKey.java
deleted file mode 100644
index 0609391e..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/profile/ProfileKey.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.onarandombox.multiverseinventories.profile;
-
-import com.google.common.base.Objects;
-import com.onarandombox.multiverseinventories.profile.container.ContainerType;
-import org.bukkit.Bukkit;
-
-import java.util.UUID;
-
-public final class ProfileKey {
-
- public static ProfileKey createProfileKey(ContainerType containerType, String dataName,
- ProfileType profileType, UUID playerUUID, String playerName) {
- return new ProfileKey(containerType, dataName, profileType, playerUUID, playerName);
- }
-
- public static ProfileKey createProfileKey(ContainerType containerType, String dataName,
- ProfileType profileType, UUID playerUUID) {
- return new ProfileKey(containerType, dataName, profileType, playerUUID);
- }
-
- public static ProfileKey createProfileKey(ProfileKey copyKey, ContainerType containerType) {
- return new ProfileKey(containerType, copyKey.getDataName(), copyKey.getProfileType(), copyKey.getPlayerUUID(),
- copyKey.getPlayerName());
- }
-
- public static ProfileKey createProfileKey(ProfileKey copyKey, ProfileType profileType) {
- return new ProfileKey(copyKey.getContainerType(), copyKey.getDataName(), profileType, copyKey.getPlayerUUID(),
- copyKey.getPlayerName());
- }
-
- public static ProfileKey createProfileKey(ProfileKey copyKey, ContainerType containerType,
- ProfileType profileType) {
- return new ProfileKey(containerType, copyKey.getDataName(), profileType, copyKey.getPlayerUUID(),
- copyKey.getPlayerName());
- }
-
- public static ProfileKey createProfileKey(PlayerProfile profile) {
- return new ProfileKey(profile.getContainerType(), profile.getContainerName(), profile.getProfileType(),
- profile.getPlayer().getUniqueId(), profile.getPlayer().getName());
- }
-
- private final ContainerType containerType;
- private final String dataName;
- private final ProfileType profileType;
- private final String playerName;
- private final UUID playerUUID;
-
- private ProfileKey(ContainerType containerType, String dataName, ProfileType profileType, UUID playerUUID) {
- this.containerType = containerType;
- this.dataName = dataName;
- this.profileType = profileType;
- this.playerUUID = playerUUID;
- this.playerName = Bukkit.getOfflinePlayer(playerUUID).getName();
- }
-
- private ProfileKey(ContainerType containerType, String dataName, ProfileType profileType,
- UUID playerUUID, String playerName) {
- this.containerType = containerType;
- this.dataName = dataName;
- this.profileType = profileType;
- this.playerUUID = playerUUID;
- this.playerName = playerName;
- }
-
- public ContainerType getContainerType() {
- return containerType;
- }
-
- public String getDataName() {
- return dataName;
- }
-
- public ProfileType getProfileType() {
- return profileType;
- }
-
- public String getPlayerName() {
- return playerName;
- }
-
- public UUID getPlayerUUID() {
- return playerUUID;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof ProfileKey)) return false;
- final ProfileKey that = (ProfileKey) o;
- return getContainerType() == that.getContainerType() &&
- Objects.equal(getDataName(), that.getDataName()) &&
- Objects.equal(getProfileType(), that.getProfileType()) &&
- Objects.equal(getPlayerName(), that.getPlayerName()) &&
- Objects.equal(getPlayerUUID(), that.getPlayerUUID());
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(getContainerType(), getDataName(), getProfileType(), getPlayerName(), getPlayerUUID());
- }
-
- @Override
- public String toString() {
- return "ProfileKey{" +
- "containerType=" + containerType +
- ", dataName='" + dataName + '\'' +
- ", profileType=" + profileType +
- ", playerName='" + playerName + '\'' +
- ", playerUUID=" + playerUUID +
- '}';
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/profile/ProfileTypes.java b/src/main/java/com/onarandombox/multiverseinventories/profile/ProfileTypes.java
deleted file mode 100644
index 4de6121b..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/profile/ProfileTypes.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.onarandombox.multiverseinventories.profile;
-
-import org.bukkit.GameMode;
-
-/**
- * Static class for profile type lookup and protected registration.
- */
-public final class ProfileTypes {
-
- /**
- * The profile type for the SURVIVAL Game Mode.
- */
- public static final ProfileType SURVIVAL = ProfileType.createProfileType("SURVIVAL");
-
- /**
- * The profile type for the CREATIVE Game Mode.
- */
- public static final ProfileType CREATIVE = ProfileType.createProfileType("CREATIVE");
-
- /**
- * The profile type for the ADVENTURE Game Mode.
- */
- public static final ProfileType ADVENTURE = ProfileType.createProfileType("ADVENTURE");
-
- /**
- * Returns the appropriate ProfileType for the given game mode.
- *
- * @param mode The game mode to get the profile type for.
- * @return The profile type for the given game mode.
- */
- public static ProfileType forGameMode(GameMode mode) {
- switch (mode) {
- case SURVIVAL:
- return SURVIVAL;
- case CREATIVE:
- return CREATIVE;
- case ADVENTURE:
- return ADVENTURE;
- default:
- return SURVIVAL;
- }
- }
-
- private ProfileTypes() {
- throw new AssertionError();
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/profile/container/ProfileContainer.java b/src/main/java/com/onarandombox/multiverseinventories/profile/container/ProfileContainer.java
deleted file mode 100644
index e6ffc560..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/profile/container/ProfileContainer.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.onarandombox.multiverseinventories.profile.container;
-
-import com.onarandombox.multiverseinventories.profile.ProfileType;
-import com.onarandombox.multiverseinventories.profile.PlayerProfile;
-import org.bukkit.OfflinePlayer;
-import org.bukkit.entity.Player;
-
-/**
- * A container for player profiles in a given world or world group (based on {@link #getContainerType()}).
- * Players may have separate profiles per game mode within this container if game mode profiles are enabled.
- */
-public interface ProfileContainer {
-
- /**
- * Returns the name of this profile container which is primarily used for persistence purposes.
- * The name reflects the world name if this is a world profile container, or the arbitrary group name if
- * this is a world group profile container.
- *
- * @return The name to use to look up Data.
- */
- String getContainerName();
-
- /**
- * Returns the container type for this container.
- *
- * @return the container type.
- */
- ContainerType getContainerType();
-
- /**
- * Retrieves the profile for the given player.
- * If game mode profiles are enabled, the profile for their current game mode will be returned, otherwise their
- * survival profile will be returned.
- *
- * @param player Player to get profile for.
- * @return The profile for the given player.
- */
- PlayerProfile getPlayerData(Player player);
-
- /**
- * Retrieves the profile of the given type for the given player.
- *
- * @param profileType The type of profile to get data for, typically Survival or Creative.
- * @param player Player to get profile for.
- * @return The profile of the given type for the given player.
- */
- PlayerProfile getPlayerData(ProfileType profileType, OfflinePlayer player);
-
- /**
- * Adds a player profile to this profile container.
- *
- * @param playerProfile Player player to add.
- */
- void addPlayerData(PlayerProfile playerProfile);
-
- /**
- * Removes all of the profile data for a given player in this profile container.
- *
- * @param player Player to remove data for.
- */
- void removeAllPlayerData(OfflinePlayer player);
-
- /**
- * Removes the profile data for a specific type of profile in this profile container.
- *
- * @param profileType The type of profile to remove data for.
- * @param player Player to remove data for.
- */
- void removePlayerData(ProfileType profileType, OfflinePlayer player);
-
- /**
- * Clears all cached data in the container.
- */
- void clearContainer();
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/profile/container/ProfileContainerStore.java b/src/main/java/com/onarandombox/multiverseinventories/profile/container/ProfileContainerStore.java
deleted file mode 100644
index b7b4d9e2..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/profile/container/ProfileContainerStore.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.onarandombox.multiverseinventories.profile.container;
-
-/**
- * A utility for storing and retrieving profile containers.
- */
-public interface ProfileContainerStore {
-
- /**
- * Adds a profile container to the store.
- *
- * @param container profile container to add.
- */
- void addContainer(ProfileContainer container);
-
- /**
- * Returns the profile container for the given name.
- *
- * @param containerName Name of the profile container to retrieve.
- * @return the profile container for given name.
- */
- ProfileContainer getContainer(String containerName);
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/share/InventorySerializer.java b/src/main/java/com/onarandombox/multiverseinventories/share/InventorySerializer.java
deleted file mode 100644
index e1baa956..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/share/InventorySerializer.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.onarandombox.multiverseinventories.share;
-
-import com.onarandombox.multiverseinventories.util.MinecraftTools;
-import org.bukkit.Material;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A simple {@link SharableSerializer} usable with ItemStack[] which converts the ItemStack[] to the string format
- * that is used by default in Multiverse-Inventories.
- */
-public final class InventorySerializer implements SharableSerializer {
-
- private int inventorySize;
-
- public InventorySerializer(final int inventorySize) {
- this.inventorySize = inventorySize;
- }
-
- @Override
- public ItemStack[] deserialize(Object obj) {
- return unmapSlots(obj);
- }
-
- @Override
- public Object serialize(ItemStack[] itemStacks) {
- return mapSlots(itemStacks);
- }
-
- private Map mapSlots(ItemStack[] itemStacks) {
- Map result = new HashMap<>(itemStacks.length);
- for (int i = 0; i < itemStacks.length; i++) {
- if (itemStacks[i] != null && itemStacks[i].getType() != Material.AIR) {
- result.put(Integer.toString(i), itemStacks[i]);
- }
- }
- return result;
- }
-
- private ItemStack[] unmapSlots(Object obj) {
- ItemStack[] result = new ItemStack[inventorySize];
- if (obj instanceof Map) {
- Map, ?> invMap = (Map) obj;
- for (int i = 0; i < result.length; i++) {
- Object value = invMap.get(Integer.toString(i));
- if (value != null && value instanceof ItemStack) {
- result[i] = (ItemStack) value;
- } else {
- result[i] = new ItemStack(Material.AIR);
- }
- }
- return result;
- }
- return MinecraftTools.fillWithAir(result);
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/share/PersistingProfile.java b/src/main/java/com/onarandombox/multiverseinventories/share/PersistingProfile.java
deleted file mode 100644
index 20fc431b..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/share/PersistingProfile.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.onarandombox.multiverseinventories.share;
-
-import com.onarandombox.multiverseinventories.profile.PlayerProfile;
-
-/**
- * Simple interface for groups that are going to be saved/loaded. This is used specifically for when a user's world
- * change is being handled.
- */
-public interface PersistingProfile {
-
- /**
- * @return The shares that will be saved/loaded for the profile. This is the set of all Sharables that will be acted
- * upon when passed through the ShareHandler class, or any of its subclasses.
- */
- Shares getShares();
-
- /**
- * @return The player profile for the world/group that will be saved/loaded for.
- */
- PlayerProfile getProfile();
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/share/SharableEntry.java b/src/main/java/com/onarandombox/multiverseinventories/share/SharableEntry.java
deleted file mode 100644
index 418c1fdc..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/share/SharableEntry.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.onarandombox.multiverseinventories.share;
-
-public final class SharableEntry {
-
- private final Sharable sharable;
- private final T value;
-
- public SharableEntry(Sharable sharable, T initialValue) {
- this.sharable = sharable;
- this.value = initialValue;
- }
-
- public Sharable getSharable() {
- return sharable;
- }
-
- public T getValue() {
- return value;
- }
-}
diff --git a/src/main/java/com/onarandombox/multiverseinventories/share/package-info.java b/src/main/java/com/onarandombox/multiverseinventories/share/package-info.java
deleted file mode 100644
index 6f538d65..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/share/package-info.java
+++ /dev/null
@@ -1,5 +0,0 @@
-/**
- * Contains all external API classes for {@link com.onarandombox.multiverseinventories.share.Sharable}s and handling the sharing of those between worlds.
- */
-package com.onarandombox.multiverseinventories.share;
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/util/CommentedYamlConfiguration.java b/src/main/java/com/onarandombox/multiverseinventories/util/CommentedYamlConfiguration.java
deleted file mode 100644
index 718b7da6..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/util/CommentedYamlConfiguration.java
+++ /dev/null
@@ -1,278 +0,0 @@
-package com.onarandombox.multiverseinventories.util;
-
-import org.bukkit.configuration.file.FileConfiguration;
-import org.bukkit.configuration.file.YamlConfiguration;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A Configuration wrapper class that allows for comments to be applied to the config paths.
- */
-public final class CommentedYamlConfiguration {
-
- private final File file;
- private final FileConfiguration config;
- private final boolean doComments;
- private final HashMap comments;
-
- private static final Pattern NEW_LINE_PATTERN = Pattern.compile("\r?\n");
-
- public CommentedYamlConfiguration(File file, boolean doComments) {
- this.file = file;
- this.doComments = doComments;
- this.comments = new HashMap();
- this.config = new YamlConfiguration();
-
- try {
- this.config.load(file);
- } catch (Exception ignored) {}
- }
-
- /**
- * @return The underlying configuration object.
- */
- public FileConfiguration getConfig() {
- return this.config;
- }
-
- /**
- * Saves the file as per normal for YamlConfiguration and then parses the file and inserts
- * comments where necessary.
- *
- * @return True if successful.
- */
- public boolean save() {
- // try to save the config file, return false on failure
- try {
- config.save(file);
- } catch (Exception e) {
- return false;
- }
-
- // if we're not supposed to add comments, or there aren't any to add, we're done
- if (!doComments || comments.isEmpty()) {
- return true;
- }
-
- // convert config file to String
- String stringConfig = this.convertFileToString(file);
-
- // figure out where the header ends
- int indexAfterHeader = 0;
- Matcher newline = NEW_LINE_PATTERN.matcher(stringConfig);
-
- while (newline.find() && stringConfig.charAt(newline.end()) == '#') {
- indexAfterHeader = newline.end();
- }
-
- // convert stringConfig to array, ignoring the header
- String[] arrayConfig = stringConfig.substring(indexAfterHeader).split(newline.group());
-
- // begin building the new config, starting with the header
- StringBuilder newContents = new StringBuilder();
- newContents.append(stringConfig, 0, indexAfterHeader);
-
- // This holds the current path the lines are at in the config
- StringBuilder currentPath = new StringBuilder();
-
- // This flags if the line is a node or unknown text.
- boolean node;
- // The depth of the path. (number of words separated by periods - 1)
- int depth = 0;
-
- // Loop through the config lines
- for (final String line : arrayConfig) {
- // If the line is a node (and not something like a list value)
- if (line.contains(": ") || (line.length() > 1 && line.charAt(line.length() - 1) == ':')) {
- // This is a node so flag it as one
- node = true;
-
- // Grab the index of the end of the node name
- int index;
- index = line.indexOf(": ");
- if (index < 0) {
- index = line.length() - 1;
- }
- // If currentPath is empty, store the node name as the currentPath. (this is only on the first iteration, i think)
- if (currentPath.toString().isEmpty()) {
- currentPath = new StringBuilder(line.substring(0, index));
- } else {
- // Calculate the whitespace preceding the node name
- int whiteSpace = 0;
- for (int n = 0; n < line.length(); n++) {
- if (line.charAt(n) == ' ') {
- whiteSpace++;
- } else {
- break;
- }
- }
-
- int whiteSpaceDividedByTwo = whiteSpace / 2;
- // Find out if the current depth (whitespace * 2) is greater/lesser/equal to the previous depth
- if (whiteSpaceDividedByTwo > depth) {
- // Path is deeper. Add a dot and the node name
- currentPath.append(".").append(line, whiteSpace, index);
- depth++;
- } else if (whiteSpaceDividedByTwo < depth) {
- // Path is shallower, calculate current depth from whitespace (whitespace / 2) and subtract that many levels from the currentPath
- for (int i = 0; i < depth - whiteSpaceDividedByTwo; i++) {
- currentPath.replace(currentPath.lastIndexOf("."), currentPath.length(), "");
- }
- // Grab the index of the final period
- int lastIndex = currentPath.lastIndexOf(".");
- if (lastIndex < 0) {
- // if there isn't a final period, set the current path to nothing because we're at root
- currentPath = new StringBuilder();
- } else {
- // If there is a final period, replace everything after it with nothing
- currentPath.replace(currentPath.lastIndexOf("."), currentPath.length(), "").append(".");
- }
- // Add the new node name to the path
- currentPath.append(line, whiteSpace, index);
- // Reset the depth
- depth = whiteSpaceDividedByTwo;
- } else {
- // Path is same depth, replace the last path node name to the current node name
- int lastIndex = currentPath.lastIndexOf(".");
- if (lastIndex < 0) {
- // if there isn't a final period, set the current path to nothing because we're at root
- currentPath = new StringBuilder();
- } else {
- // If there is a final period, replace everything after it with nothing
- currentPath.replace(currentPath.lastIndexOf("."), currentPath.length(), "").append(".");
- }
-
- currentPath.append(line, whiteSpace, index);
- }
- }
- } else {
- node = false;
- }
-
- StringBuilder newLine = new StringBuilder();
-
- if (node) {
- // get the comment for the current node
- String comment = comments.get(currentPath.toString());
- if (comment != null && !comment.isEmpty()) {
- // if the previous line doesn't end in a colon
- // and there's not already a newline character,
- // add a newline before we add the comment
- char previousChar = newContents.charAt(newContents.length() - 2);
- if (previousChar != ':' && previousChar != '\n') {
- newLine.append("\n");
- }
-
- // add the comment
- newLine.append(comment).append("\n");
- }
- }
-
- // add the config line
- newLine.append(line).append("\n");
-
- // Add the (modified) line to the total config String
- newContents.append(newLine);
- }
-
- // try to save the config file, returning whether it saved successfully
- return this.stringToFile(newContents.toString(), file);
- }
-
- /**
- * Adds a comment just before the specified path. The comment can be multiple lines. An empty string will indicate
- * a blank line.
- *
- * @param path Configuration path to add comment.
- * @param commentLines Comments to add. One String per line.
- */
- public void addComment(String path, List commentLines) {
- StringBuilder commentString = new StringBuilder();
- StringBuilder leadingSpaces = new StringBuilder();
- for (int n = 0; n < path.length(); n++) {
- if (path.charAt(n) == '.') {
- leadingSpaces.append(" ");
- }
- }
- for (String line : commentLines) {
- if (commentString.length() > 0) {
- commentString.append("\n");
- }
- if (!line.isEmpty()) {
- commentString.append(leadingSpaces).append(line);
- }
- }
- comments.put(path, commentString.toString());
- }
-
- /**
- * Pass a file and it will return it's contents as a string.
- *
- * @param file File to read.
- * @return Contents of file. String will be empty in case of any errors.
- */
- private String convertFileToString(File file) {
- final int bufferSize = 1024;
- if (file != null && file.exists() && file.canRead() && !file.isDirectory()) {
- Writer writer = new StringWriter();
- char[] buffer = new char[bufferSize];
-
- try (InputStream is = new FileInputStream(file)) {
- int n;
- Reader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
- while ((n = reader.read(buffer)) != -1) {
- writer.write(buffer, 0, n);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- return writer.toString();
- } else {
- return "";
- }
- }
-
- /**
- * Writes the contents of a string to a file.
- *
- * @param source String to write.
- * @param file File to write to.
- * @return True on success.
- */
- private boolean stringToFile(String source, File file) {
- OutputStreamWriter out = null;
- try {
- out = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
- out.write(source);
- out.close();
- return true;
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- } finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/util/Font.java b/src/main/java/com/onarandombox/multiverseinventories/util/Font.java
deleted file mode 100644
index 71779d20..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/util/Font.java
+++ /dev/null
@@ -1,196 +0,0 @@
-package com.onarandombox.multiverseinventories.util;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Class for font functions including font width specifications.
- */
-public class Font {
-
- /**
- * Provides the char for a Section symbol.
- */
- public static final char SECTION_SYMBOL = (char) 167;
-
- private static final int LINE_LENGTH = 318;
- private static final HashMap FONT_WIDTH;
-
- static {
- FONT_WIDTH = new HashMap();
- /*
- * Widths is in pixels
- * Got them from fontWidths.txt uploaded to the Bukkit forum by Edward Hand
- * http://forums.bukkit.org/threads/formatting-module-output-text-into-columns.8481/
- */
- // BEGIN CHECKSTYLE-SUPPRESSION: MagicNumberCheck
- FONT_WIDTH.put(" ", 4);
- FONT_WIDTH.put("!", 2);
- FONT_WIDTH.put("\"", 5);
- FONT_WIDTH.put("#", 6);
- FONT_WIDTH.put("$", 6);
- FONT_WIDTH.put("%", 6);
- FONT_WIDTH.put("&", 6);
- FONT_WIDTH.put("'", 3);
- FONT_WIDTH.put("(", 5);
- FONT_WIDTH.put(")", 5);
- FONT_WIDTH.put("*", 5);
- FONT_WIDTH.put("+", 6);
- FONT_WIDTH.put(",", 2);
- FONT_WIDTH.put("-", 6);
- FONT_WIDTH.put(".", 2);
- FONT_WIDTH.put("/", 6);
- FONT_WIDTH.put("0", 6);
- FONT_WIDTH.put("1", 6);
- FONT_WIDTH.put("2", 6);
- FONT_WIDTH.put("3", 6);
- FONT_WIDTH.put("4", 6);
- FONT_WIDTH.put("5", 6);
- FONT_WIDTH.put("6", 6);
- FONT_WIDTH.put("7", 6);
- FONT_WIDTH.put("8", 6);
- FONT_WIDTH.put("9", 6);
- FONT_WIDTH.put(":", 2);
- FONT_WIDTH.put(";", 2);
- FONT_WIDTH.put("<", 5);
- FONT_WIDTH.put("=", 6);
- FONT_WIDTH.put(">", 5);
- FONT_WIDTH.put("?", 6);
- FONT_WIDTH.put("@", 7);
- FONT_WIDTH.put("A", 6);
- FONT_WIDTH.put("B", 6);
- FONT_WIDTH.put("C", 6);
- FONT_WIDTH.put("D", 6);
- FONT_WIDTH.put("E", 6);
- FONT_WIDTH.put("F", 6);
- FONT_WIDTH.put("G", 6);
- FONT_WIDTH.put("H", 6);
- FONT_WIDTH.put("I", 4);
- FONT_WIDTH.put("J", 6);
- FONT_WIDTH.put("K", 6);
- FONT_WIDTH.put("L", 6);
- FONT_WIDTH.put("M", 6);
- FONT_WIDTH.put("N", 6);
- FONT_WIDTH.put("O", 6);
- FONT_WIDTH.put("P", 6);
- FONT_WIDTH.put("Q", 6);
- FONT_WIDTH.put("R", 6);
- FONT_WIDTH.put("S", 6);
- FONT_WIDTH.put("T", 6);
- FONT_WIDTH.put("U", 6);
- FONT_WIDTH.put("V", 6);
- FONT_WIDTH.put("W", 6);
- FONT_WIDTH.put("X", 6);
- FONT_WIDTH.put("Y", 6);
- FONT_WIDTH.put("Z", 6);
- FONT_WIDTH.put("_", 6);
- FONT_WIDTH.put("'", 3);
- FONT_WIDTH.put("a", 6);
- FONT_WIDTH.put("b", 6);
- FONT_WIDTH.put("c", 6);
- FONT_WIDTH.put("d", 6);
- FONT_WIDTH.put("e", 6);
- FONT_WIDTH.put("f", 5);
- FONT_WIDTH.put("g", 6);
- FONT_WIDTH.put("h", 6);
- FONT_WIDTH.put("i", 2);
- FONT_WIDTH.put("j", 6);
- FONT_WIDTH.put("k", 5);
- FONT_WIDTH.put("l", 3);
- FONT_WIDTH.put("m", 6);
- FONT_WIDTH.put("n", 6);
- FONT_WIDTH.put("o", 6);
- FONT_WIDTH.put("p", 6);
- FONT_WIDTH.put("q", 6);
- FONT_WIDTH.put("r", 6);
- FONT_WIDTH.put("s", 6);
- FONT_WIDTH.put("t", 4);
- FONT_WIDTH.put("u", 6);
- FONT_WIDTH.put("v", 6);
- FONT_WIDTH.put("w", 6);
- FONT_WIDTH.put("x", 6);
- FONT_WIDTH.put("y", 6);
- FONT_WIDTH.put("z", 6);
- // END CHECKSTYLE-SUPPRESSION: MagicNumberCheck
- }
-
- private Font() { }
-
- /**
- * Get width of string in pixels.
- *
- * @param text String.
- * @return Length of string in pixels.
- */
- public static int stringWidth(String text) {
- if (FONT_WIDTH.isEmpty()) {
- return 0;
- }
- char[] chars = text.toCharArray();
- int width = 0;
- int spacepos = 0;
- for (int i = 0; i < chars.length; i++) {
- if (FONT_WIDTH.containsKey(String.valueOf(chars[i]))) {
- width += FONT_WIDTH.get(String.valueOf(chars[i]));
- } else if (chars[i] == SECTION_SYMBOL) {
- i++;
- }
- }
- return width;
- }
-
- /**
- * Get a List of Strings where none exceed the maximum line length.
- *
- * @param text String
- * @return List of Strings
- */
- public static List splitString(String text) {
- List split = new ArrayList();
- if (FONT_WIDTH.isEmpty()) {
- split.add(text);
- return split;
- }
- char[] chars = text.toCharArray();
- int width = 0;
- int lastspaceindex = 0;
- int lastlineindex = 0;
- String lastcolor = null;
- boolean colorfoundthisline = false;
- for (int i = 0; i < chars.length; i++) {
- if (FONT_WIDTH.containsKey(String.valueOf(chars[i]))) {
- width += FONT_WIDTH.get(String.valueOf(chars[i]));
- } else if (chars[i] == SECTION_SYMBOL) {
- i++;
- lastcolor = Character.toString(chars[i]);
- colorfoundthisline = true;
- }
- if ((width > LINE_LENGTH) && (lastspaceindex != 0)) {
- if (lastcolor != null && !colorfoundthisline) {
- split.add(Character.toString(SECTION_SYMBOL) + lastcolor
- + text.substring(lastlineindex, lastspaceindex));
- } else {
- split.add(text.substring(lastlineindex, lastspaceindex));
- }
- colorfoundthisline = false;
- lastlineindex = lastspaceindex;
- i = lastspaceindex;
- width = 0;
- }
- if (String.valueOf(chars[i]).equals(" ")) {
- lastspaceindex = i;
- }
- }
- if (!text.substring(lastlineindex).isEmpty())
- if (lastcolor != null && !colorfoundthisline) {
- split.add(Character.toString(SECTION_SYMBOL) + lastcolor
- + text.substring(lastlineindex));
- } else {
- split.add(text.substring(lastlineindex));
- }
-
- return split;
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/util/MinecraftTools.java b/src/main/java/com/onarandombox/multiverseinventories/util/MinecraftTools.java
deleted file mode 100644
index a79e49cb..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/util/MinecraftTools.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.onarandombox.multiverseinventories.util;
-
-import org.bukkit.Material;
-import org.bukkit.inventory.ItemStack;
-
-/**
- * General tools to help with minecraftian things.
- */
-public class MinecraftTools {
-
- private static final int TICKS_PER_SECOND = 20;
-
- private MinecraftTools() { }
-
- /**
- * Converts an amount of seconds to the appropriate amount of ticks.
- *
- * @param seconds Amount of seconds to convert
- * @return Ticks converted from seconds.
- */
- public static long convertSecondsToTicks(long seconds) {
- return seconds * TICKS_PER_SECOND;
- }
-
- /**
- * Fills an ItemStack array with air.
- *
- * @param items The ItemStack array to fill.
- * @return The air filled ItemStack array.
- */
- public static ItemStack[] fillWithAir(ItemStack[] items) {
- for (int i = 0; i < items.length; i++) {
- items[i] = new ItemStack(Material.AIR);
- }
- return items;
- }
-}
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/util/package-info.java b/src/main/java/com/onarandombox/multiverseinventories/util/package-info.java
deleted file mode 100644
index 0826b3ff..00000000
--- a/src/main/java/com/onarandombox/multiverseinventories/util/package-info.java
+++ /dev/null
@@ -1,5 +0,0 @@
-/**
- * This package contains utility classes.
- */
-package com.onarandombox.multiverseinventories.util;
-
diff --git a/src/main/java/com/onarandombox/multiverseinventories/InventoriesDupingPatch.java b/src/main/java/org/mvplugins/multiverse/inventories/InventoriesDupingPatch.java
similarity index 90%
rename from src/main/java/com/onarandombox/multiverseinventories/InventoriesDupingPatch.java
rename to src/main/java/org/mvplugins/multiverse/inventories/InventoriesDupingPatch.java
index 13fcbeae..3460e0e3 100644
--- a/src/main/java/com/onarandombox/multiverseinventories/InventoriesDupingPatch.java
+++ b/src/main/java/org/mvplugins/multiverse/inventories/InventoriesDupingPatch.java
@@ -1,4 +1,4 @@
-package com.onarandombox.multiverseinventories;
+package org.mvplugins.multiverse.inventories;
import java.util.HashMap;
import java.util.Iterator;
@@ -17,6 +17,7 @@
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.plugin.Plugin;
+import org.jvnet.hk2.annotations.Service;
/**
* This is a simple patch that fixes a
@@ -40,7 +41,7 @@
* @author Irmo van den Berge (bergerkiller)
* @version 1.0
*/
-class InventoriesDupingPatch {
+final class InventoriesDupingPatch {
private static final int SLOT_TIMEOUT = 5;
@@ -77,7 +78,7 @@ public void onCreativeSlotChange(InventoryCreativeEvent event) {
return; // Saves performance for most common case
}
InventoryHolder holder = event.getInventory().getHolder();
- if (holder instanceof Player && timeouts.containsKey(((Player) holder).getUniqueId())) {
+ if (holder instanceof Player player && timeouts.containsKey(player.getUniqueId())) {
event.setResult(Result.DENY);
}
}
@@ -90,8 +91,8 @@ public void onCreativeSlotChange(InventoryCreativeEvent event) {
*/
public void enable(Plugin plugin) {
Bukkit.getPluginManager().registerEvents(this.listener, plugin);
- this.updateTimeoutsTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(
- plugin, new UpdateTimeoutsTask(), 1, 1);
+ this.updateTimeoutsTaskId = Bukkit.getScheduler().runTaskTimer(
+ plugin, new UpdateTimeoutsTask(), 1, 1).getTaskId();
}
/**
@@ -114,13 +115,13 @@ public void run() {
Iterator> iter = timeouts.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry e = iter.next();
- int value = e.getValue().intValue() - 1;
+ int value = e.getValue() - 1;
if (value > 0) {
- e.setValue(Integer.valueOf(value));
+ e.setValue(value);
} else {
iter.remove();
}
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/MVEventsListener.java b/src/main/java/org/mvplugins/multiverse/inventories/MVEventsListener.java
new file mode 100644
index 00000000..0f0d136d
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/MVEventsListener.java
@@ -0,0 +1,112 @@
+package org.mvplugins.multiverse.inventories;
+
+import com.dumptruckman.minecraft.util.Logging;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.jetbrains.annotations.NotNull;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.event.MVConfigReloadEvent;
+import org.mvplugins.multiverse.core.event.MVDebugModeEvent;
+import org.mvplugins.multiverse.core.event.MVDumpsDebugInfoEvent;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.inventories.config.InventoriesConfig;
+import org.mvplugins.multiverse.inventories.profile.ProfileCacheManager;
+import org.mvplugins.multiverse.inventories.profile.ProfileDataSource;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+
+import java.io.File;
+
+@Service
+final class MVEventsListener implements Listener {
+
+ private final MultiverseInventories inventories;
+ private final InventoriesConfig config;
+ private final WorldGroupManager worldGroupManager;
+ private final ProfileCacheManager profileCacheManager;
+
+ @Inject
+ MVEventsListener(
+ @NotNull MultiverseInventories inventories,
+ @NotNull InventoriesConfig config,
+ @NotNull WorldGroupManager worldGroupManager,
+ @NotNull ProfileCacheManager profileCacheManager) {
+ this.inventories = inventories;
+ this.config = config;
+ this.worldGroupManager = worldGroupManager;
+ this.profileCacheManager = profileCacheManager;
+ }
+
+ /**
+ * Adds Multiverse-Inventories version info to /mv version.
+ *
+ * @param event The MVVersionEvent that this plugin will listen for.
+ */
+ @EventHandler
+ void dumpsDebugInfoRequest(MVDumpsDebugInfoEvent event) {
+ event.appendDebugInfo(getDebugInfo());
+ File configFile = new File(this.inventories.getDataFolder(), "config.yml");
+ File groupsFile = new File(this.inventories.getDataFolder(), "groups.yml");
+ event.putDetailedDebugInfo("multiverse-inventories/config.yml", configFile);
+ event.putDetailedDebugInfo("multiverse-inventories/groups.yml", groupsFile);
+ event.putDetailedDebugInfo("multiverse-inventories/cachestats.md", generateCacheStatsContent());
+ }
+
+ private String generateCacheStatsContent() {
+ var builder = new StringBuilder();
+ profileCacheManager.getCacheStats().forEach((cacheName, stats) -> {
+ builder.append("# ").append(cacheName).append("\n")
+ .append("- hits count: ").append(stats.hitCount()).append("\n")
+ .append("- misses count: ").append(stats.missCount()).append("\n")
+ .append("- loads count: ").append(stats.loadCount()).append("\n")
+ .append("- misses count: ").append(stats.missCount()).append("\n")
+ .append("- evictions: ").append(stats.evictionCount()).append("\n")
+ .append("- hit rate: ").append(stats.hitRate() * 100).append("%\n")
+ .append("- miss rate: ").append(stats.missRate() * 100).append("%\n")
+ .append("- avg load penalty: ").append(stats.averageLoadPenalty() / 1000000).append("ms\n")
+ .append("\n");
+ });
+ return builder.toString();
+ }
+
+ /**
+ * Builds a String containing Multiverse-Inventories' version info.
+ *
+ * @return The version info.
+ */
+ private String getDebugInfo() {
+ StringBuilder versionInfo = new StringBuilder("[Multiverse-Inventories] Multiverse-Inventories Version: " + inventories.getDescription().getVersion() + '\n'
+ + "[Multiverse-Inventories] === Settings ===" + '\n'
+ + "[Multiverse-Inventories] First Run: " + config.getFirstRun() + '\n'
+ + "[Multiverse-Inventories] Using Bypass: " + config.getEnableBypassPermissions() + '\n'
+ + "[Multiverse-Inventories] Default Ungrouped Worlds: " + config.getDefaultUngroupedWorlds() + '\n'
+ + "[Multiverse-Inventories] Save and Load on Log In and Out: " + config.getApplyPlayerdataOnJoin() + '\n'
+ + "[Multiverse-Inventories] Using GameMode Profiles: " + config.getEnableGamemodeShareHandling() + '\n'
+ + "[Multiverse-Inventories] === Shares ===" + '\n'
+ + "[Multiverse-Inventories] Optionals for Ungrouped Worlds: " + config.getUseOptionalsForUngroupedWorlds() + '\n'
+ + "[Multiverse-Inventories] Enabled Optionals: " + config.getActiveOptionalShares() + '\n'
+ + "[Multiverse-Inventories] === Groups ===" + '\n');
+
+ for (WorldGroup group : worldGroupManager.getGroups()) {
+ versionInfo.append("[Multiverse-Inventories] ").append(group.toString()).append('\n');
+ }
+
+ return versionInfo.toString();
+ }
+
+ @EventHandler
+ void onDebugModeChange(MVDebugModeEvent event) {
+ Logging.setDebugLevel(event.getLevel());
+ }
+
+ /**
+ * Hooks Multiverse-Inventories into the Multiverse reload command.
+ *
+ * @param event The MVConfigReloadEvent that this plugin will listen for.
+ */
+ @EventHandler
+ void configReload(MVConfigReloadEvent event) {
+ this.inventories.reloadConfig();
+ event.addConfig("Multiverse-Inventories - config.yml");
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventories.java b/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventories.java
new file mode 100644
index 00000000..f4f233da
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventories.java
@@ -0,0 +1,258 @@
+package org.mvplugins.multiverse.inventories;
+
+import com.dumptruckman.minecraft.util.Logging;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.PluginManager;
+import org.mvplugins.multiverse.core.config.CoreConfig;
+import org.mvplugins.multiverse.core.destination.DestinationsProvider;
+import org.mvplugins.multiverse.core.module.MultiverseModule;
+import org.mvplugins.multiverse.core.utils.StringFormatter;
+import org.mvplugins.multiverse.inventories.command.MVInvCommandConditions;
+import org.mvplugins.multiverse.inventories.command.MVInvCommandPermissions;
+import org.mvplugins.multiverse.inventories.commands.InventoriesCommand;
+import org.mvplugins.multiverse.inventories.command.MVInvCommandCompletion;
+import org.mvplugins.multiverse.inventories.command.MVInvCommandContexts;
+import org.mvplugins.multiverse.inventories.config.InventoriesConfig;
+import org.mvplugins.multiverse.inventories.dataimport.DataImportManager;
+import org.mvplugins.multiverse.inventories.dataimport.DataImporter;
+import org.mvplugins.multiverse.inventories.destination.LastLocationDestination;
+import org.mvplugins.multiverse.inventories.handleshare.ShareHandleListener;
+import org.mvplugins.multiverse.inventories.handleshare.SingleShareWriter;
+import org.mvplugins.multiverse.inventories.handleshare.SpawnChangeListener;
+import org.mvplugins.multiverse.inventories.handleshare.WriteOnlyShareHandler;
+import org.mvplugins.multiverse.inventories.profile.PlayerNamesMapper;
+import org.mvplugins.multiverse.inventories.profile.ProfileCacheManager;
+import org.mvplugins.multiverse.inventories.profile.ProfileDataSource;
+import org.mvplugins.multiverse.inventories.profile.key.GlobalProfileKey;
+import org.mvplugins.multiverse.inventories.profile.key.ProfileTypes;
+import org.mvplugins.multiverse.inventories.profile.container.ProfileContainerStoreProvider;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.share.Sharables;
+import org.mvplugins.multiverse.inventories.util.ItemStackConverter;
+import org.mvplugins.multiverse.inventories.util.Perm;
+import org.bukkit.Bukkit;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jakarta.inject.Provider;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.external.vavr.control.Try;
+
+/**
+ * Multiverse-Inventories plugin main class.
+ */
+@Service
+public class MultiverseInventories extends MultiverseModule {
+
+ private static final double TARGET_CORE_API_VERSION = 5.0;
+
+ @Inject
+ private Provider coreConfig;
+ @Inject
+ private Provider destinationsProvider;
+ @Inject
+ private Provider inventoriesConfig;
+ @Inject
+ private Provider shareHandleListener;
+ @Inject
+ private Provider respawnListener;
+ @Inject
+ private Provider mvEventsListener;
+ @Inject
+ private Provider worldGroupManager;
+ @Inject
+ private Provider playerNamesMapperProvider;
+ @Inject
+ private Provider profileDataSource;
+ @Inject
+ private Provider profileCacheManager;
+ @Inject
+ private Provider profileContainerStoreProvider;
+ @Inject
+ private Provider dataImportManager;
+ @Inject
+ private Provider mvInvCommandCompletion;
+ @Inject
+ private Provider mvInvCommandContexts;
+ @Inject
+ private Provider mvInvCommandConditions;
+ @Inject
+ private Provider mvInvCommandPermissions;
+
+ private InventoriesDupingPatch dupingPatch;
+ private boolean usingSpawnChangeEvent = false;
+
+ public MultiverseInventories() {
+ super();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onLoad() {
+ Logging.init(this);
+ this.getDataFolder().mkdirs();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final void onEnable() {
+ super.onEnable();
+
+ initializeDependencyInjection(new MultiverseInventoriesPluginBinder(this));
+ ProfileTypes.init(this);
+ Sharables.init(this);
+ Perm.register(this);
+ ItemStackConverter.init(this);
+ Logging.fine("ItemStackConverter is using byte serialization: " + ItemStackConverter.hasByteSerializeSupport());
+ this.reloadConfig();
+ inventoriesConfig.get().save().onFailure(e -> Logging.severe("Failed to save config file!"));
+
+ // Register Stuff
+ this.registerEvents();
+ this.setUpLocales();
+ this.registerCommands();
+ this.registerDestinations();
+
+ // Hook plugins that can be imported from
+ this.hookImportables();
+
+ // Init other extensions
+ this.hookLuckPerms();
+ this.dupingPatch = InventoriesDupingPatch.enableDupingPatch(this);
+ this.playerNamesMapperProvider.get().loadMap();
+
+ // Init api
+ MultiverseInventoriesApi.init(this.serviceLocator);
+
+ Logging.config("Version %s (API v%s) Enabled - By %s",
+ this.getDescription().getVersion(), getVersionAsNumber(), StringFormatter.joinAnd(this.getDescription().getAuthors()));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onDisable() {
+ super.onDisable();
+
+ for (final Player player : getServer().getOnlinePlayers()) {
+ SingleShareWriter.of(this, player, Sharables.LAST_LOCATION).write(player.getLocation().clone());
+ new WriteOnlyShareHandler(this, player).handleSharing();
+ if (inventoriesConfig.get().getApplyPlayerdataOnJoin()) {
+ profileDataSource.get().modifyGlobalProfile(
+ GlobalProfileKey.of(player), profile -> profile.setLoadOnLogin(true));
+ }
+ }
+
+ MultiverseInventoriesApi.shutdown();
+ this.dupingPatch.disable();
+ this.shutdownDependencyInjection();
+ Logging.shutdown();
+ }
+
+ private void registerEvents() {
+ PluginManager pluginManager = this.getServer().getPluginManager();
+ pluginManager.registerEvents(shareHandleListener.get(), this);
+ pluginManager.registerEvents(respawnListener.get(), this);
+ pluginManager.registerEvents(mvEventsListener.get(), this);
+ if (inventoriesConfig.get().getUseImprovedRespawnLocationDetection()) {
+ try {
+ Class.forName("org.bukkit.event.player.PlayerSpawnChangeEvent");
+ pluginManager.registerEvents(new SpawnChangeListener(this), this);
+ usingSpawnChangeEvent = true;
+ Logging.fine("Yayy PlayerSpawnChangeEvent will be used!");
+ } catch (ClassNotFoundException e) {
+ Logging.fine("PlayerSpawnChangeEvent will not be used!");
+ }
+ }
+ }
+
+ private void registerCommands() {
+ Try.run(() -> {
+ mvInvCommandCompletion.get();
+ mvInvCommandContexts.get();
+ mvInvCommandConditions.get();
+ mvInvCommandPermissions.get();
+ }).onFailure(e -> {
+ Logging.warning("Failed to register command completers: %s", e.getMessage());
+ });
+ registerCommands(InventoriesCommand.class);
+ }
+
+ private void registerDestinations() {
+ destinationsProvider.get().registerDestination(serviceLocator.getService(LastLocationDestination.class));
+ }
+
+ private void hookImportables() {
+ serviceLocator.getAllServices(DataImporter.class).forEach(dataImporter -> {
+ dataImportManager.get().register(dataImporter);
+ });
+ }
+
+ private void hookLuckPerms() {
+ Try.run(() -> Class.forName("net.luckperms.api.LuckPerms"))
+ .onFailure(e -> Logging.fine("Luckperms is not installed!"))
+ .andThenTry(() -> {
+ Logging.fine("Found luckperms!");
+ serviceLocator.getService(WorldGroupContextCalculator.class);
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double getTargetCoreVersion() {
+ return TARGET_CORE_API_VERSION;
+ }
+
+ /**
+ * Nulls the config object and reloads a new one, also resetting the world groups in memory.
+ */
+ @Override
+ public void reloadConfig() {
+ try {
+ Logging.setDebugLevel(coreConfig.get().getGlobalDebug());
+
+ inventoriesConfig.get().load().onFailure(e -> {
+ Logging.severe("Failed to load config file!");
+ Logging.severe(e.getMessage());
+ });
+ worldGroupManager.get().load().onFailure(e -> {
+ Logging.severe("Failed to load world groups!");
+ Logging.severe(e.getMessage());
+ });
+ profileContainerStoreProvider.get().clearCache();
+
+ if (profileDataSource.get() != null) {
+ profileCacheManager.get().clearAllCache();
+ }
+
+ Logging.fine("Reloaded all config and groups!");
+ } catch (Exception e) { // Catch errors loading the config file and exit out if found.
+ Logging.severe("Encountered an error while loading the configuration file. Disabling...");
+ Logging.severe(e.getMessage());
+ Bukkit.getPluginManager().disablePlugin(this);
+ return;
+ }
+
+ this.getServer().getScheduler().runTaskLater(this, () -> {
+ // Create initial World Group for first run IF NO GROUPS EXIST
+ if (inventoriesConfig.get().getFirstRun()) {
+ Logging.info("First run!");
+ if (worldGroupManager.get().getGroups().isEmpty()) {
+ worldGroupManager.get().createDefaultGroup();
+ }
+
+ inventoriesConfig.get().setFirstRun(false);
+ }
+ worldGroupManager.get().checkForConflicts(null);
+ }, 1L);
+ }
+
+ public boolean isUsingSpawnChangeEvent() {
+ return usingSpawnChangeEvent;
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventoriesApi.java b/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventoriesApi.java
new file mode 100644
index 00000000..46c32213
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventoriesApi.java
@@ -0,0 +1,124 @@
+package org.mvplugins.multiverse.inventories;
+
+import org.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.core.inject.PluginServiceLocator;
+import org.mvplugins.multiverse.inventories.config.InventoriesConfig;
+import org.mvplugins.multiverse.inventories.dataimport.DataImportManager;
+import org.mvplugins.multiverse.inventories.profile.PlayerNamesMapper;
+import org.mvplugins.multiverse.inventories.profile.ProfileCacheManager;
+import org.mvplugins.multiverse.inventories.profile.ProfileDataSource;
+import org.mvplugins.multiverse.inventories.profile.container.ProfileContainerStoreProvider;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+
+import java.util.Objects;
+
+/**
+ * Provides access to the Multiverse-Inventories API.
+ */
+public final class MultiverseInventoriesApi {
+
+ private static MultiverseInventoriesApi instance;
+
+ static void init(@NotNull PluginServiceLocator serviceLocator) {
+ if (instance != null) {
+ throw new IllegalStateException("MultiverseCoreApi has already been initialized!");
+ }
+ instance = new MultiverseInventoriesApi(serviceLocator);
+ }
+
+ static void shutdown() {
+ instance = null;
+ }
+
+ /**
+ * Gets the MultiverseInventoriesApi. This will throw an exception if the Multiverse-Inventories has not been initialized.
+ *
+ * @return The MultiverseInventoriesApi
+ */
+ public static @NotNull MultiverseInventoriesApi get() {
+ if (instance == null) {
+ throw new IllegalStateException("MultiverseInventoriesApi has not been initialized!");
+ }
+ return instance;
+ }
+
+ private final PluginServiceLocator serviceLocator;
+
+ private MultiverseInventoriesApi(@NotNull PluginServiceLocator serviceProvider) {
+ this.serviceLocator = serviceProvider;
+ }
+
+ /**
+ * Gets instance of our DataImportManager api.
+ *
+ * @return The DataImportManager instance
+ */
+ public @NotNull DataImportManager getDataImportManager() {
+ return Objects.requireNonNull(serviceLocator.getService(DataImportManager.class));
+ }
+
+ /**
+ * Gets instance of our InventoriesConfig api.
+ *
+ * @return The InventoriesConfig instance
+ */
+ public @NotNull InventoriesConfig getInventoriesConfig() {
+ return Objects.requireNonNull(serviceLocator.getService(InventoriesConfig.class));
+ }
+
+ /**
+ * Gets instance of our PlayerNamesMapper api.
+ *
+ * @return The PlayerNamesMapper instance
+ */
+ public @NotNull PlayerNamesMapper getPlayerNamesMapper() {
+ return Objects.requireNonNull(serviceLocator.getService(PlayerNamesMapper.class));
+ }
+
+ /**
+ * Gets instance of our ProfileCacheManager api.
+ *
+ * @return The ProfileCacheManager instance
+ */
+ public @NotNull ProfileCacheManager getProfileCacheManager() {
+ return Objects.requireNonNull(serviceLocator.getService(ProfileCacheManager.class));
+ }
+
+ /**
+ * Gets instance of our ProfileContainerStoreProvider api.
+ *
+ * @return The ProfileContainerStoreProvider instance
+ */
+ public @NotNull ProfileContainerStoreProvider getProfileContainerStoreProvider() {
+ return Objects.requireNonNull(serviceLocator.getService(ProfileContainerStoreProvider.class));
+ }
+
+ /**
+ * Gets instance of our ProfileDataSource api.
+ *
+ * @return The ProfileDataSource instance
+ */
+ public @NotNull ProfileDataSource getProfileDataSource() {
+ return Objects.requireNonNull(serviceLocator.getService(ProfileDataSource.class));
+ }
+
+ /**
+ * Gets instance of our WorldGroupManager api.
+ *
+ * @return The WorldGroupManager instance
+ */
+ public @NotNull WorldGroupManager getWorldGroupManager() {
+ return Objects.requireNonNull(serviceLocator.getService(WorldGroupManager.class));
+ }
+
+ /**
+ * Gets the instance of Multiverse-Inventories's PluginServiceLocator.
+ *
+ * You can use this to hook into the hk2 dependency injection system used by Multiverse-Inventories.
+ *
+ * @return The Multiverse-Inventories's PluginServiceLocator
+ */
+ public @NotNull PluginServiceLocator getServiceLocator() {
+ return serviceLocator;
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventoriesPluginBinder.java b/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventoriesPluginBinder.java
new file mode 100644
index 00000000..fa8bf235
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventoriesPluginBinder.java
@@ -0,0 +1,18 @@
+package org.mvplugins.multiverse.inventories;
+
+import org.mvplugins.multiverse.core.module.MultiverseModuleBinder;
+import org.mvplugins.multiverse.external.glassfish.hk2.utilities.binding.ScopedBindingBuilder;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+
+final class MultiverseInventoriesPluginBinder extends MultiverseModuleBinder {
+
+ MultiverseInventoriesPluginBinder(@NotNull MultiverseInventories plugin) {
+ super(plugin);
+ }
+
+ @Override
+ protected ScopedBindingBuilder bindPluginClass
+ (ScopedBindingBuilder bindingBuilder) {
+ return super.bindPluginClass(bindingBuilder).to(MultiverseInventories.class);
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/RespawnListener.java b/src/main/java/org/mvplugins/multiverse/inventories/RespawnListener.java
new file mode 100644
index 00000000..176b6917
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/RespawnListener.java
@@ -0,0 +1,134 @@
+package org.mvplugins.multiverse.inventories;
+
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerRespawnEvent;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
+import org.mvplugins.multiverse.core.world.WorldManager;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+
+import java.util.List;
+
+/**
+ * Specific events for handling player respawns location
+ */
+@Service
+final class RespawnListener implements Listener {
+
+ private final WorldGroupManager worldGroupManager;
+ private final WorldManager worldManager;
+
+ private List currentGroups;
+ private Location spawnLoc = null;
+
+ @Inject
+ RespawnListener(WorldGroupManager worldGroupManager, WorldManager worldManager) {
+ this.worldGroupManager = worldGroupManager;
+ this.worldManager = worldManager;
+ }
+
+ /**
+ * Handles player respawns at the LOWEST priority.
+ *
+ * @param event The player respawn event.
+ */
+ @EventHandler(priority = EventPriority.LOWEST)
+ void lowestPriorityRespawn(PlayerRespawnEvent event) {
+ if (!event.isBedSpawn()) {
+ World world = event.getPlayer().getWorld();
+ this.currentGroups = worldGroupManager.getGroupsForWorld(world.getName());
+ this.handleRespawn(event, EventPriority.LOWEST);
+ }
+ }
+
+ /**
+ * Handles player respawns at the LOW priority.
+ *
+ * @param event The player respawn event.
+ */
+ @EventHandler(priority = EventPriority.LOW)
+ void lowPriorityRespawn(PlayerRespawnEvent event) {
+ if (!event.isBedSpawn()) {
+ this.handleRespawn(event, EventPriority.LOW);
+ }
+ }
+
+ /**
+ * Handles player respawns at the NORMAL priority.
+ *
+ * @param event The player respawn event.
+ */
+ @EventHandler(priority = EventPriority.NORMAL)
+ void normalPriorityRespawn(PlayerRespawnEvent event) {
+ if (!event.isBedSpawn()) {
+ this.handleRespawn(event, EventPriority.NORMAL);
+ }
+ }
+
+ /**
+ * Handles player respawns at the HIGH priority.
+ *
+ * @param event The player respawn event.
+ */
+ @EventHandler(priority = EventPriority.HIGH)
+ void highPriorityRespawn(PlayerRespawnEvent event) {
+ if (!event.isBedSpawn()) {
+ this.handleRespawn(event, EventPriority.HIGH);
+ }
+ }
+
+ /**
+ * Handles player respawns at the HIGHEST priority.
+ *
+ * @param event The player respawn event.
+ */
+ @EventHandler(priority = EventPriority.HIGHEST)
+ void highestPriorityRespawn(PlayerRespawnEvent event) {
+ if (!event.isBedSpawn()) {
+ this.handleRespawn(event, EventPriority.HIGHEST);
+ }
+ }
+
+ /**
+ * Handles player respawns at the MONITOR priority.
+ *
+ * @param event The player respawn event.
+ */
+ @EventHandler(priority = EventPriority.MONITOR)
+ void monitorPriorityRespawn(PlayerRespawnEvent event) {
+ if (!event.isBedSpawn()) {
+ this.handleRespawn(event, EventPriority.MONITOR);
+ this.updateCompass(event);
+ }
+ }
+
+ private void handleRespawn(PlayerRespawnEvent event, EventPriority priority) {
+ for (WorldGroup group : this.currentGroups) {
+ if (!group.getSpawnPriority().equals(priority)) {
+ continue;
+ }
+ String spawnWorldName = group.getSpawnWorld();
+ if (spawnWorldName == null) {
+ continue;
+ }
+ LoadedMultiverseWorld mvWorld = worldManager.getLoadedWorld(spawnWorldName).getOrNull();
+ if (mvWorld != null) {
+ this.spawnLoc = mvWorld.getSpawnLocation();
+ event.setRespawnLocation(this.spawnLoc);
+ break;
+ }
+ }
+ }
+
+ private void updateCompass(PlayerRespawnEvent event) {
+ if (event.getRespawnLocation().equals(this.spawnLoc)) {
+ event.getPlayer().setCompassTarget(this.spawnLoc);
+ }
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/WorldGroupContextCalculator.java b/src/main/java/org/mvplugins/multiverse/inventories/WorldGroupContextCalculator.java
new file mode 100644
index 00000000..56c2378b
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/WorldGroupContextCalculator.java
@@ -0,0 +1,53 @@
+package org.mvplugins.multiverse.inventories;
+
+import com.dumptruckman.minecraft.util.Logging;
+import net.luckperms.api.LuckPermsProvider;
+import net.luckperms.api.context.ContextCalculator;
+import net.luckperms.api.context.ContextConsumer;
+import net.luckperms.api.context.ContextSet;
+import net.luckperms.api.context.ImmutableContextSet;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.external.jakarta.annotation.PostConstruct;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.vavr.control.Try;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+
+@Service
+final class WorldGroupContextCalculator implements ContextCalculator {
+
+ private static final String WORLD_GROUP_CONTEXT_KEY = "mvinv:worldgroup";
+ private final WorldGroupManager worldGroupManager;
+
+ @Inject
+ WorldGroupContextCalculator(WorldGroupManager worldGroupManager) {
+ this.worldGroupManager = worldGroupManager;
+ }
+
+ @PostConstruct
+ private void registerCalculator() {
+ Try.of(LuckPermsProvider::get)
+ .peek(luckPerms -> luckPerms.getContextManager().registerCalculator(this))
+ .onFailure(e -> Logging.warning("Failed to hook LuckPerms! %s", e.getMessage()));
+ }
+
+ @Override
+ public void calculate(@NotNull Player player, @NotNull ContextConsumer contextConsumer) {
+ ImmutableContextSet.Builder contextBuilder = ImmutableContextSet.builder();
+ worldGroupManager.getGroupsForWorld(player.getWorld().getName())
+ .forEach(worldGroup -> contextBuilder.add(WORLD_GROUP_CONTEXT_KEY, worldGroup.getName()));
+
+ contextConsumer.accept(contextBuilder.build());
+ }
+
+ @NotNull
+ @Override
+ public ContextSet estimatePotentialContexts() {
+ ImmutableContextSet.Builder contextBuilder = ImmutableContextSet.builder();
+ worldGroupManager.getGroups()
+ .forEach(worldGroup -> contextBuilder.add(WORLD_GROUP_CONTEXT_KEY, worldGroup.getName()));
+
+ return contextBuilder.build();
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandCompletion.java b/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandCompletion.java
new file mode 100644
index 00000000..7f18bd1f
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandCompletion.java
@@ -0,0 +1,179 @@
+package org.mvplugins.multiverse.inventories.command;
+
+import org.jetbrains.annotations.NotNull;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandCompletions;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.core.config.handle.PropertyModifyAction;
+import org.mvplugins.multiverse.core.utils.StringFormatter;
+import org.mvplugins.multiverse.external.acf.commands.BukkitCommandCompletionContext;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.vavr.control.Try;
+import org.mvplugins.multiverse.inventories.config.InventoriesConfig;
+import org.mvplugins.multiverse.inventories.dataimport.DataImportManager;
+import org.mvplugins.multiverse.inventories.profile.PlayerNamesMapper;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.profile.key.GlobalProfileKey;
+import org.mvplugins.multiverse.inventories.profile.key.ProfileType;
+import org.mvplugins.multiverse.inventories.profile.key.ProfileTypes;
+import org.mvplugins.multiverse.inventories.share.Sharables;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.mvplugins.multiverse.core.utils.StringFormatter.addonToCommaSeperated;
+
+@Service
+public final class MVInvCommandCompletion {
+
+ private final InventoriesConfig inventoriesConfig;
+ private final WorldGroupManager worldGroupManager;
+ private final DataImportManager dataImportManager;
+ private final PlayerNamesMapper playerNamesMapper;
+
+ @Inject
+ private MVInvCommandCompletion(
+ @NotNull InventoriesConfig inventoriesConfig,
+ @NotNull WorldGroupManager worldGroupManager,
+ @NotNull DataImportManager dataImportManager,
+ @NotNull MVCommandManager mvCommandManager,
+ @NotNull PlayerNamesMapper playerNamesMapper
+ ) {
+ this.inventoriesConfig = inventoriesConfig;
+ this.worldGroupManager = worldGroupManager;
+ this.dataImportManager = dataImportManager;
+ this.playerNamesMapper = playerNamesMapper;
+
+ MVCommandCompletions commandCompletions = mvCommandManager.getCommandCompletions();
+ commandCompletions.registerAsyncCompletion("dataimporters", this::suggestDataImporters);
+ commandCompletions.registerStaticCompletion("mvinvconfigs", inventoriesConfig.getStringPropertyHandle().getAllPropertyNames());
+ commandCompletions.registerAsyncCompletion("mvinvconfigvalues", this::suggestConfigValues);
+ commandCompletions.registerAsyncCompletion("mvinvplayernames", this::suggestPlayerNames);
+ commandCompletions.registerAsyncCompletion("mvinvprofiletypes", this::suggestProfileTypes);
+ commandCompletions.registerAsyncCompletion("sharables", this::suggestSharables);
+ commandCompletions.registerAsyncCompletion("shares", this::suggestShares);
+ commandCompletions.registerAsyncCompletion("worldGroups", this::suggestWorldGroups);
+ commandCompletions.registerAsyncCompletion("worldGroupWorlds", this::suggestWorldGroupWorlds);
+ }
+
+ private Collection suggestDataImporters(BukkitCommandCompletionContext context) {
+ return dataImportManager.getEnabledImporterNames();
+ }
+
+ private Collection suggestConfigValues(BukkitCommandCompletionContext context) {
+ return Try.of(() -> context.getContextValue(String.class))
+ .map(propertyName -> inventoriesConfig.getStringPropertyHandle()
+ .getSuggestedPropertyValue(propertyName, context.getInput(), PropertyModifyAction.SET))
+ .getOrElse(Collections.emptyList());
+ }
+
+ private Collection suggestPlayerNames(BukkitCommandCompletionContext context) {
+ if (Objects.equals(context.getInput(), "@all")) {
+ return Collections.emptyList();
+ }
+ List playerNames = getPlayerNames();
+ if (context.getInput().indexOf(',') == -1) {
+ playerNames.add("@all");
+ return playerNames;
+ }
+ return StringFormatter.addonToCommaSeperated(context.getInput(), playerNames);
+ }
+
+ private List getPlayerNames() {
+ return playerNamesMapper.getKeys()
+ .stream()
+ .map(GlobalProfileKey::getPlayerName)
+ .collect(Collectors.toList());
+ }
+
+ private Collection suggestProfileTypes(BukkitCommandCompletionContext context) {
+ if (!context.hasConfig("multiple")) {
+ return ProfileTypes.getTypes().stream()
+ .map(ProfileType::getName)
+ .map(String::toLowerCase)
+ .toList();
+ }
+
+ if (Objects.equals(context.getInput(), "@all")) {
+ return Collections.emptyList();
+ }
+ List profileTypes = ProfileTypes.getTypes()
+ .stream()
+ .map(ProfileType::getName)
+ .map(String::toLowerCase)
+ .collect(Collectors.toList());
+ if (context.getInput().indexOf(',') == -1) {
+ profileTypes.add("@all");
+ return profileTypes;
+ }
+ return StringFormatter.addonToCommaSeperated(context.getInput(), profileTypes);
+ }
+
+ private Collection suggestSharables(BukkitCommandCompletionContext context) {
+ String scope = context.getConfig("scope", "enabled");
+
+ return Sharables.all().stream()
+ .filter(sharable -> switch (scope) {
+ case "enabled" ->
+ !sharable.isOptional() || inventoriesConfig.getActiveOptionalShares().contains(sharable);
+ case "optional" -> sharable.isOptional();
+ default -> true;
+ })
+ .filter(sharable -> sharable.getNames().length > 0)
+ .map(sharable -> sharable.getNames()[0])
+ .toList();
+ }
+
+ private Collection suggestShares(BukkitCommandCompletionContext context) {
+ String input = context.getInput();
+
+ if (input.isEmpty()) {
+ // No input, so we're suggesting the first share
+ return Sharables.getShareNames();
+ }
+
+ int lastComma = input.lastIndexOf(",");
+ if (lastComma == -1) {
+ // No comma, so we're suggesting the first share
+ if (input.startsWith("-")) {
+ return Sharables.getShareNames().stream()
+ .map(name -> "-" + name)
+ .collect(Collectors.toList());
+ }
+ return Sharables.getShareNames();
+ }
+
+ // We're suggesting a share after a comma
+ String lastShare = input.substring(lastComma + 1);
+ String currentSharesString = input.substring(0, lastComma + (lastShare.startsWith("-") ? 2 : 1));
+ Set currentShares = Arrays.stream(input.split(","))
+ .map(share -> share.startsWith("-") ? share.substring(1) : share)
+ .collect(Collectors.toSet());
+
+ return Sharables.getShareNames().stream()
+ .filter(name -> !currentShares.contains(name))
+ .map(name -> currentSharesString + name)
+ .toList();
+ }
+
+ private Collection suggestWorldGroups(BukkitCommandCompletionContext context) {
+ return worldGroupManager.getGroups().stream()
+ .map(WorldGroup::getName)
+ .toList();
+ }
+
+ private Collection suggestWorldGroupWorlds(BukkitCommandCompletionContext context) {
+
+ var worlds = Try.of(() -> context.getContextValue(WorldGroup.class))
+ .map(WorldGroup::getWorlds)
+ .getOrElse(Collections.emptySet());
+
+ return addonToCommaSeperated(context.getInput(), worlds);
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandConditions.java b/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandConditions.java
new file mode 100644
index 00000000..b6e28aea
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandConditions.java
@@ -0,0 +1,47 @@
+package org.mvplugins.multiverse.inventories.command;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.external.acf.commands.BukkitCommandExecutionContext;
+import org.mvplugins.multiverse.external.acf.commands.BukkitCommandIssuer;
+import org.mvplugins.multiverse.external.acf.commands.BukkitConditionContext;
+import org.mvplugins.multiverse.external.acf.commands.CommandConditions;
+import org.mvplugins.multiverse.external.acf.commands.ConditionContext;
+import org.mvplugins.multiverse.external.acf.commands.ConditionFailedException;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.share.Sharable;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+@Service
+public final class MVInvCommandConditions {
+
+ private final WorldGroupManager worldGroupManager;
+
+ @Inject
+ private MVInvCommandConditions(@NotNull MVCommandManager commandManager, @NotNull WorldGroupManager worldGroupManager) {
+ this.worldGroupManager = worldGroupManager;
+
+ CommandConditions commandConditions
+ = commandManager.getCommandConditions();
+ commandConditions.addCondition(Sharable.class, "optionalSharable", this::checkOptionalSharable);
+ commandConditions.addCondition(String.class, "newWorldGroupName", this::checkNewWorldGroupName);
+ }
+
+ private void checkOptionalSharable(ConditionContext context,
+ BukkitCommandExecutionContext executionContext,
+ Sharable> sharable) {
+ if (sharable == null || !sharable.isOptional()) {
+ throw new ConditionFailedException(MVInvi18n.TOGGLE_NOOPTIONALSHARES);
+ }
+ }
+
+ private void checkNewWorldGroupName(ConditionContext context,
+ BukkitCommandExecutionContext executionContext,
+ String worldGroupName) {
+ if (worldGroupManager.getGroup(worldGroupName) != null) {
+ throw new ConditionFailedException(MVInvi18n.GROUP_EXISTS, "{group}", worldGroupName);
+ }
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandContexts.java b/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandContexts.java
new file mode 100644
index 00000000..dbe0a7ef
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandContexts.java
@@ -0,0 +1,185 @@
+package org.mvplugins.multiverse.inventories.command;
+
+import com.google.common.base.Strings;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.core.utils.REPatterns;
+import org.mvplugins.multiverse.external.acf.commands.BukkitCommandExecutionContext;
+import org.mvplugins.multiverse.external.acf.commands.CommandContexts;
+import org.mvplugins.multiverse.external.acf.commands.InvalidCommandArgument;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.external.vavr.control.Option;
+import org.mvplugins.multiverse.inventories.config.InventoriesConfig;
+import org.mvplugins.multiverse.inventories.profile.PlayerNamesMapper;
+import org.mvplugins.multiverse.inventories.profile.ProfileDataSource;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.profile.key.ContainerKey;
+import org.mvplugins.multiverse.inventories.profile.key.ContainerType;
+import org.mvplugins.multiverse.inventories.profile.key.GlobalProfileKey;
+import org.mvplugins.multiverse.inventories.profile.key.ProfileType;
+import org.mvplugins.multiverse.inventories.profile.key.ProfileTypes;
+import org.mvplugins.multiverse.inventories.share.Sharable;
+import org.mvplugins.multiverse.inventories.share.Sharables;
+import org.mvplugins.multiverse.inventories.share.Shares;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+@Service
+public final class MVInvCommandContexts {
+
+ private final WorldGroupManager worldGroupManager;
+ private final PlayerNamesMapper playerNamesMapper;
+ private final InventoriesConfig config;
+ private final ProfileDataSource profileDataSource;
+
+ @Inject
+ private MVInvCommandContexts(
+ @NotNull MVCommandManager commandManager,
+ @NotNull WorldGroupManager worldGroupManager,
+ @NotNull PlayerNamesMapper playerNamesMapper,
+ @NotNull InventoriesConfig config,
+ @NotNull ProfileDataSource profileDataSource
+ ) {
+ this.worldGroupManager = worldGroupManager;
+ this.playerNamesMapper = playerNamesMapper;
+ this.config = config;
+ this.profileDataSource = profileDataSource;
+
+ CommandContexts commandContexts = commandManager.getCommandContexts();
+ commandContexts.registerContext(ContainerKey[].class, this::parseContainerKeyArray);
+ commandContexts.registerContext(GlobalProfileKey[].class, this::parseGlobalProfileKeyArray);
+ commandContexts.registerIssuerAwareContext(ProfileType.class, this::parseProfileType);
+ commandContexts.registerIssuerAwareContext(ProfileType[].class, this::parseProfileTypeArray);
+ commandContexts.registerContext(Sharable.class, this::parseSharable);
+ commandContexts.registerContext(Shares.class, this::parseShares);
+ commandContexts.registerContext(WorldGroup.class, this::parseWorldGroup);
+ }
+
+ private ProfileType parseProfileType(BukkitCommandExecutionContext context) {
+ if (!config.getEnableGamemodeShareHandling()) {
+ return ProfileTypes.getDefault();
+ }
+ String profileType = context.popFirstArg();
+ return ProfileTypes.forName(profileType)
+ .getOrElseThrow(() -> new InvalidCommandArgument("Invalid profile type: " + profileType));
+ }
+
+ private ContainerKey[] parseContainerKeyArray(BukkitCommandExecutionContext context) {
+ String keyStrings = context.popFirstArg();
+ if (keyStrings.equals("@all")) {
+ return Arrays.stream(ContainerType.values()).flatMap(containerType ->
+ profileDataSource.listContainerDataNames(containerType)
+ .stream()
+ .map(containerName -> ContainerKey.create(containerType, containerName)))
+ .toArray(ContainerKey[]::new);
+ }
+ List containerKeys = new ArrayList<>();
+ String[] typesSplit = REPatterns.SEMICOLON.split(keyStrings);
+ for (String typeSplit : typesSplit) {
+ String[] keyValueSplit = REPatterns.EQUALS.split(typeSplit, 2);
+ if (keyValueSplit.length != 2) {
+ // todo: Probably error invalid format
+ continue;
+ }
+ ContainerType containerType = ContainerType.valueOf(keyValueSplit[0].toUpperCase());
+ String[] dataNameSplit = REPatterns.COMMA.split(keyValueSplit[1]);
+ List availableDataNames = profileDataSource.listContainerDataNames(containerType);
+ for (String dataName : dataNameSplit) {
+ if (availableDataNames.contains(dataName)) {
+ containerKeys.add(ContainerKey.create(containerType, dataName));
+ }
+ }
+ }
+ return containerKeys.toArray(new ContainerKey[0]);
+ }
+
+ private GlobalProfileKey[] parseGlobalProfileKeyArray(BukkitCommandExecutionContext context) {
+ String keyStrings = context.popFirstArg();
+ if (keyStrings.equals("@all")) {
+ return playerNamesMapper.getKeys().toArray(GlobalProfileKey[]::new);
+ }
+ // todo: UUID parsing
+ String[] profileNames = REPatterns.COMMA.split(keyStrings);
+ return Arrays.stream(profileNames)
+ .map(playerNamesMapper::getKey)
+ .filter(Option::isDefined)
+ .map(Option::get)
+ .toArray(GlobalProfileKey[]::new);
+ }
+
+ private ProfileType[] parseProfileTypeArray(BukkitCommandExecutionContext context) {
+ String keyStrings = context.popFirstArg();
+ if (keyStrings.equals("@all")) {
+ return ProfileTypes.getTypes().toArray(ProfileType[]::new);
+ }
+ String[] profileNames = REPatterns.COMMA.split(keyStrings);
+ return Arrays.stream(profileNames)
+ .map(ProfileTypes::forName)
+ .filter(Option::isDefined)
+ .map(Option::get)
+ .toArray(ProfileType[]::new);
+ }
+
+ private Sharable> parseSharable(BukkitCommandExecutionContext context) {
+ String sharableName = context.popFirstArg();
+ Sharable> targetSharable = Sharables.all().stream()
+ .filter(sharable -> sharable.getNames().length > 0)
+ .filter(sharable -> sharable.getNames()[0].equals(sharableName))
+ .findFirst()
+ .orElse(null);
+
+ if (targetSharable != null) {
+ return targetSharable;
+ }
+ if (context.isOptional()) {
+ return null;
+ }
+ throw new InvalidCommandArgument(MVInvi18n.ERROR_NOSHARESSPECIFIED);
+ }
+
+ private Shares parseShares(BukkitCommandExecutionContext context) {
+ String shareStrings = context.popFirstArg();
+ if (Strings.isNullOrEmpty(shareStrings)) {
+ throw new InvalidCommandArgument(MVInvi18n.ERROR_NOSHARESSPECIFIED);
+ }
+
+ String[] shareNames = shareStrings.split(",");
+ Shares newShares = Sharables.noneOf();
+ Shares negativeShares = Sharables.noneOf();
+ for (String shareName : shareNames) {
+ if (shareName.startsWith("-")) {
+ shareName = shareName.substring(1);
+ Option.of(Sharables.lookup(shareName))
+ .peek(shares -> negativeShares.setSharing(shares, true));
+ continue;
+ }
+ Option.of(Sharables.lookup(shareName))
+ .peek(shares -> newShares.setSharing(shares, true));
+ }
+
+ newShares.setSharing(negativeShares, false);
+ if (newShares.isEmpty()) {
+ throw new InvalidCommandArgument(MVInvi18n.ERROR_NOSHARESSPECIFIED);
+ }
+
+ return newShares;
+ }
+
+ private WorldGroup parseWorldGroup(BukkitCommandExecutionContext context) {
+ String groupName = context.popFirstArg();
+ WorldGroup group = worldGroupManager.getGroup(groupName);
+ if (group != null) {
+ return group;
+ }
+ if (context.isOptional()) {
+ return null;
+ }
+ throw new InvalidCommandArgument(MVInvi18n.ERROR_NOGROUP);
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandPermissions.java b/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandPermissions.java
new file mode 100644
index 00000000..5a88faa9
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandPermissions.java
@@ -0,0 +1,20 @@
+package org.mvplugins.multiverse.inventories.command;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.core.command.MVCommandPermissions;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.config.InventoriesConfig;
+
+@Service
+public class MVInvCommandPermissions {
+
+ @Inject
+ MVInvCommandPermissions(@NotNull MVCommandManager commandManager, @NotNull InventoriesConfig config) {
+
+ MVCommandPermissions commandPermissions = commandManager.getCommandPermissions();
+ commandPermissions.registerPermissionChecker("mvinv-gamemode-profile-true", commandIssuer -> config.getEnableGamemodeShareHandling());
+ commandPermissions.registerPermissionChecker("mvinv-gamemode-profile-false", commandIssuer -> !config.getEnableGamemodeShareHandling());
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/AddDisabledSharesCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/AddDisabledSharesCommand.java
new file mode 100644
index 00000000..ab29340d
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/AddDisabledSharesCommand.java
@@ -0,0 +1,53 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.jetbrains.annotations.NotNull;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.share.Shares;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+@Service
+final class AddDisabledSharesCommand extends InventoriesCommand {
+
+ private final WorldGroupManager worldGroupManager;
+
+ @Inject
+ AddDisabledSharesCommand(@NotNull WorldGroupManager worldGroupManager) {
+ this.worldGroupManager = worldGroupManager;
+ }
+
+ @Subcommand("add-disabled-shares")
+ @CommandPermission("multiverse.inventories.adddisabledshares")
+ @CommandCompletion("@worldGroups @shares")
+ @Syntax(" ")
+ @Description("Add one or more disabled shares to a group.")
+ void onAddDisabledSharesCommand(
+ MVCommandIssuer issuer,
+
+ @Syntax("")
+ @Description("Group you want to add the disabled shares to.")
+ WorldGroup group,
+
+ @Syntax("")
+ @Description("One or more sharables to disable for the given group.")
+ Shares shares
+ ) {
+ group.getDisabledShares().mergeShares(shares);
+ worldGroupManager.updateGroup(group);
+ issuer.sendInfo(MVInvi18n.DISABLEDSHARES_NOWSHARING,
+ replace("{group}").with(group.getName()),
+ replace("{shares}").with(group.getDisabledShares().toStringList()));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/AddSharesCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/AddSharesCommand.java
new file mode 100644
index 00000000..080398cc
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/AddSharesCommand.java
@@ -0,0 +1,58 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.external.acf.commands.BukkitCommandIssuer;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.share.Sharables;
+import org.mvplugins.multiverse.inventories.share.Shares;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+@Service
+final class AddSharesCommand extends InventoriesCommand {
+
+ private final WorldGroupManager worldGroupManager;
+
+ @Inject
+ AddSharesCommand(@NotNull WorldGroupManager worldGroupManager) {
+ this.worldGroupManager = worldGroupManager;
+ }
+
+ @Subcommand("add-shares")
+ @CommandPermission("multiverse.inventories.addshares")
+ @CommandCompletion("@worldGroups @shares")
+ @Syntax(" ")
+ @Description("Add one or more shares to a group.")
+ void onAddSharesCommand(
+ MVCommandIssuer issuer,
+
+ @Syntax("")
+ @Description("Group you want to add the shares to.")
+ WorldGroup group,
+
+ @Syntax("")
+ @Description("One or more sharables to add.")
+ Shares shares
+ ) {
+ group.getShares().mergeShares(shares);
+ worldGroupManager.updateGroup(group);
+ var negativeshares = Sharables.allOf();
+ negativeshares.setSharing(group.getShares(), false);
+ issuer.sendInfo(MVInvi18n.SHARES_NOWSHARING,
+ replace("{group}").with(group.getName()),
+ replace("{shares}").with(group.getShares().toStringList()),
+ replace("{negativeshares}").with(negativeshares.toStringList()));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/AddWorldsCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/AddWorldsCommand.java
new file mode 100644
index 00000000..3cf97d1e
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/AddWorldsCommand.java
@@ -0,0 +1,64 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
+import org.mvplugins.multiverse.core.world.MultiverseWorld;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+@Service
+final class AddWorldsCommand extends InventoriesCommand {
+
+ private final WorldGroupManager worldGroupManager;
+
+ @Inject
+ AddWorldsCommand(@NotNull WorldGroupManager worldGroupManager) {
+ this.worldGroupManager = worldGroupManager;
+ }
+
+ @Subcommand("add-worlds")
+ @CommandPermission("multiverse.inventories.addworlds")
+ @CommandCompletion("@worldGroups @mvworlds:multiple,scope=both")
+ @Syntax(" ")
+ @Description("Adds a World to a World Group.")
+ void onAddWorldCommand(
+ MVCommandIssuer issuer,
+
+ @Syntax("")
+ @Description("Group you want to add the world to.")
+ WorldGroup group,
+
+ @Syntax("")
+ @Description("World name to add.")
+ MultiverseWorld[] worlds
+ ) {
+ List worldNames = Arrays.stream(worlds).map(MultiverseWorld::getName).toList();
+ String worldNamesString = String.join(", ", worldNames);
+ if (!group.getWorlds().addAll(worldNames)) {
+ issuer.sendError(MVInvi18n.ADDWORLD_WORLDALREADYEXISTS,
+ replace("{group}").with(group.getName()),
+ replace("{world}").with(worldNamesString));
+ return;
+ }
+ worldGroupManager.updateGroup(group);
+ issuer.sendInfo(MVInvi18n.ADDWORLD_WORLDADDED,
+ replace("{group}").with(group.getName()),
+ replace("{world}").with(worldNamesString));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/CacheCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/CacheCommand.java
new file mode 100644
index 00000000..f63bd0ed
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/CacheCommand.java
@@ -0,0 +1,63 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import com.github.benmanes.caffeine.cache.stats.CacheStats;
+import org.bukkit.entity.Player;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Flags;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.profile.ProfileCacheManager;
+
+import java.util.Map;
+
+@Service
+final class CacheCommand extends InventoriesCommand {
+
+ private final ProfileCacheManager ProfileCacheManager;
+
+ @Inject
+ CacheCommand(@NotNull ProfileCacheManager ProfileCacheManager) {
+ this.ProfileCacheManager = ProfileCacheManager;
+ }
+
+ @Subcommand("cache stats")
+ @CommandPermission("multiverse.inventories.cache.stats")
+ void onCacheStatsCommand(MVCommandIssuer issuer) {
+ Map stats = this.ProfileCacheManager.getCacheStats();
+ for (Map.Entry entry : stats.entrySet()) {
+ issuer.sendMessage("Cache: " + entry.getKey());
+ issuer.sendMessage(" hits count: " + entry.getValue().hitCount());
+ issuer.sendMessage(" misses count: " + entry.getValue().missCount());
+ issuer.sendMessage(" loads count: " + entry.getValue().loadCount());
+ issuer.sendMessage(" evictions: " + entry.getValue().evictionCount());
+ issuer.sendMessage(" hit rate: " + entry.getValue().hitRate() * 100 + "%");
+ issuer.sendMessage(" miss rate: " + entry.getValue().missRate() * 100 + "%");
+ issuer.sendMessage(" avg load penalty: " + entry.getValue().averageLoadPenalty() / 1000000 + "ms");
+ issuer.sendMessage("--------");
+ }
+ }
+
+ @Subcommand("cache invalidate all")
+ @CommandPermission("multiverse.inventories.cache.invalidate")
+ void onCacheClearAllCommand(MVCommandIssuer issuer) {
+ this.ProfileCacheManager.clearAllCache();
+ }
+
+ @Subcommand("cache invalidate player")
+ @CommandPermission("multiverse.inventories.cache.invalidate")
+ @CommandCompletion("@players")
+ @Syntax("")
+ void onCacheClearProfileCommand(
+ MVCommandIssuer issuer,
+
+ @Flags("resolve=issuerAware")
+ Player player) {
+ this.ProfileCacheManager.clearPlayerProfileCache(key ->
+ key.getPlayerUUID().equals(player.getUniqueId()));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/ConfigCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/ConfigCommand.java
new file mode 100644
index 00000000..998df4b6
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/ConfigCommand.java
@@ -0,0 +1,68 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.jetbrains.annotations.NotNull;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.core.exceptions.MultiverseException;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Optional;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.vavr.control.Option;
+import org.mvplugins.multiverse.inventories.config.InventoriesConfig;
+
+@Service
+final class ConfigCommand extends InventoriesCommand {
+
+ private final InventoriesConfig config;
+
+ @Inject
+ ConfigCommand(@NotNull InventoriesConfig config) {
+ this.config = config;
+ }
+
+ @Subcommand("config")
+ @CommandPermission("multiverse.inventories.config")
+ @CommandCompletion("@mvinvconfigs @mvinvconfigvalues")
+ @Syntax(" [value]")
+ @Description("Show or set a config value.")
+ void onConfigCommand(
+ MVCommandIssuer issuer,
+
+ @Syntax("")
+ @Description("The name of the config to set or show.")
+ String name,
+
+ @Optional
+ @Syntax("[value]")
+ @Description("The value to set the config to. If not specified, the current value will be shown.")
+ String value) {
+ if (value == null) {
+ showConfigValue(issuer, name);
+ return;
+ }
+ updateConfigValue(issuer, name, value);
+ }
+
+ private void showConfigValue(MVCommandIssuer issuer, String name) {
+ config.getStringPropertyHandle().getProperty(name)
+ .onSuccess(value -> issuer.sendMessage(name + "is currently set to " + value))
+ .onFailure(e -> issuer.sendMessage(e.getMessage()));
+ }
+
+ private void updateConfigValue(MVCommandIssuer issuer, String name, String value) {
+ // TODO: Update with localization
+ config.getStringPropertyHandle().setPropertyString(name, value)
+ .onSuccess(ignore -> {
+ config.save();
+ issuer.sendMessage("Successfully set " + name + " to " + value);
+ })
+ .onFailure(ignore -> issuer.sendMessage("Unable to set " + name + " to " + value + "."))
+ .onFailure(MultiverseException.class, e -> Option.of(e.getLocalizableMessage()).peek(issuer::sendError));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/CreateGroupCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/CreateGroupCommand.java
new file mode 100644
index 00000000..8717975c
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/CreateGroupCommand.java
@@ -0,0 +1,68 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.core.world.MultiverseWorld;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Conditions;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Optional;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.share.Shares;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import java.util.Arrays;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+@Service
+final class CreateGroupCommand extends InventoriesCommand {
+ private final WorldGroupManager worldGroupManager;
+
+ @Inject
+ CreateGroupCommand(@NotNull WorldGroupManager worldGroupManager) {
+ this.worldGroupManager = worldGroupManager;
+ }
+
+ @Subcommand("create-group")
+ @CommandPermission("multiverse.inventories.creategroup")
+ @CommandCompletion("@empty @mvworlds:multiple,scope=both @shares")
+ @Syntax(" [share[,extra]] [world[,extra]]")
+ @Description("Creates a new empty World Group with no worlds and no shares.")
+ void onCreateGroupCommand(
+ MVCommandIssuer issuer,
+
+ @Conditions("newWorldGroupName")
+ @Syntax("")
+ @Description("New group name to create.")
+ @NotNull String groupName,
+
+ @Optional
+ @Syntax("[world[,extra]]")
+ MultiverseWorld[] worlds,
+
+ @Optional
+ @Syntax("[share,[extra]]")
+ Shares shares
+ ) {
+ WorldGroup worldGroup = worldGroupManager.newEmptyGroup(groupName);
+ if (worlds != null) {
+ worldGroup.getWorlds().addAll(Arrays.stream(worlds).map(MultiverseWorld::getName).toList());
+ }
+ if (shares != null) {
+ worldGroup.getShares().mergeShares(shares);
+ }
+ worldGroupManager.updateGroup(worldGroup);
+ issuer.sendInfo(MVInvi18n.GROUP_CREATIONCOMPLETE, replace("{group}").with(groupName));
+ issuer.sendInfo(MVInvi18n.INFO_GROUP_INFO, replace("{worlds}").with(worldGroup.getWorlds()));
+ issuer.sendInfo(MVInvi18n.INFO_GROUP_INFOSHARES, replace("{shares}").with(worldGroup.getShares()));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/DeleteGroupCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/DeleteGroupCommand.java
new file mode 100644
index 00000000..42529934
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/DeleteGroupCommand.java
@@ -0,0 +1,58 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
+import org.mvplugins.multiverse.core.command.queue.CommandQueuePayload;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+@Service
+final class DeleteGroupCommand extends InventoriesCommand {
+ private final CommandQueueManager commandQueueManager;
+ private final WorldGroupManager worldGroupManager;
+
+ @Inject
+ DeleteGroupCommand(
+ @NotNull CommandQueueManager commandQueueManager,
+ @NotNull WorldGroupManager worldGroupManager
+ ) {
+ this.commandQueueManager = commandQueueManager;
+ this.worldGroupManager = worldGroupManager;
+ }
+
+ @Subcommand("delete-group")
+ @CommandPermission("multiverse.inventories.deletegroup")
+ @CommandCompletion("@worldGroups")
+ @Syntax("")
+ @Description("Deletes a World Group.")
+ void onDeleteGroupCommand(
+ MVCommandIssuer issuer,
+
+ @Syntax("")
+ @Description("Inventories group to delete.")
+ WorldGroup group
+ ) {
+ commandQueueManager.addToQueue(CommandQueuePayload.issuer(issuer)
+ .prompt(Message.of(MVInvi18n.DELETEGROUP_CONFIRMPROMPT, replace("{group}").with(group.getName())))
+ .action(() -> doDeleteGroup(issuer, group)));
+ }
+
+ private void doDeleteGroup(MVCommandIssuer issuer, WorldGroup group) {
+ worldGroupManager.removeGroup(group);
+ issuer.sendInfo(MVInvi18n.DELETEGROUP_SUCCESS, replace("{group}").with(group.getName()));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/GiveCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/GiveCommand.java
new file mode 100644
index 00000000..9556d071
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/GiveCommand.java
@@ -0,0 +1,186 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import com.dumptruckman.minecraft.util.Logging;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.utils.REPatterns;
+import org.mvplugins.multiverse.core.world.MultiverseWorld;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.vavr.control.Try;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.mvplugins.multiverse.inventories.handleshare.SingleShareReader;
+import org.mvplugins.multiverse.inventories.handleshare.SingleShareWriter;
+import org.mvplugins.multiverse.inventories.profile.ProfileDataSource;
+import org.mvplugins.multiverse.inventories.profile.key.GlobalProfileKey;
+import org.mvplugins.multiverse.inventories.profile.key.ProfileType;
+import org.mvplugins.multiverse.inventories.profile.key.ProfileTypes;
+import org.mvplugins.multiverse.inventories.share.Sharables;
+import org.mvplugins.multiverse.inventories.util.PlayerStats;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@Service
+final class GiveCommand extends InventoriesCommand {
+
+ private final MultiverseInventories inventories;
+ private final ProfileDataSource profileDataSource;
+
+ @Inject
+ GiveCommand(
+ @NotNull MultiverseInventories inventories,
+ @NotNull ProfileDataSource profileDataSource
+ ) {
+ this.inventories = inventories;
+ this.profileDataSource = profileDataSource;
+ }
+
+ // TODO Better offline player parsing
+ @Subcommand("give")
+ @CommandPermission("multiverse.inventories.give")
+ @CommandCompletion("@players " +
+ "@mvworlds:scope=both " +
+ "@mvinvprofiletypes:checkPermissions=@mvinv-gamemode-profile-true|@materials:checkPermissions=@mvinv-gamemode-profile-false " +
+ "@materials:checkPermissions=@mvinv-gamemode-profile-true|@range:64,checkPermissions=@mvinv-gamemode-profile-false " +
+ "@range:64,checkPermissions=@mvinv-gamemode-profile-true|@empty " +
+ "@empty")
+ @Syntax(" [gamemode] - [amount]")
+ @Description("World and Group Information")
+ void onGiveCommand(
+ MVCommandIssuer issuer,
+
+ @Syntax("")
+ OfflinePlayer player,
+
+ @Syntax("")
+ MultiverseWorld world,
+
+ @Syntax("[gamemode]")
+ ProfileType profileType,
+
+ @Syntax("
- [amount]")
+ String item
+ ) {
+ ItemStack itemStack = parseItemFromString(issuer, item);
+ if (itemStack == null) {
+ return;
+ }
+ Logging.finer("Giving player " + player.getName() + " item: " + itemStack);
+
+ // Giving online player in same world
+ Player onlinePlayer = player.getPlayer();
+ if (onlinePlayer != null
+ && world.getName().equals(onlinePlayer.getWorld().getName())
+ && ProfileTypes.forPlayer(onlinePlayer).equals(profileType)) {
+ onlinePlayer.getInventory().addItem(itemStack);
+ issuer.sendInfo("Gave player %s %s %s in world %s."
+ .formatted(player.getName(), itemStack.getAmount(), itemStack, world.getName()));
+ return;
+ }
+
+ SingleShareReader.of(inventories, player, world.getName(), profileType, Sharables.INVENTORY)
+ .read()
+ .thenCompose(inventory -> updatePlayerInventory(issuer, player, world, profileType, inventory, itemStack))
+ .exceptionally(throwable -> {
+ issuer.sendError(throwable.getMessage());
+ return null;
+ });
+ }
+
+ private @Nullable ItemStack parseItemFromString(MVCommandIssuer issuer, String item) {
+ // Get amount
+ int amount = 1;
+ AtomicBoolean endIsAmount = new AtomicBoolean(false);
+ int lastSpace = item.lastIndexOf(' ');
+ if (lastSpace != -1) {
+ String amountString = item.substring(lastSpace + 1);
+ amount = Try.of(() -> Integer.parseInt(amountString))
+ .peek(ignore -> endIsAmount.set(true))
+ .getOrElse(1);
+ }
+ if (amount < 1) {
+ issuer.sendError("You have to give at least 1 item.");
+ return null;
+ }
+ if (amount > 6400) {
+ issuer.sendError("Cannot give more than 6400 items at once.");
+ return null;
+ }
+ // Remove amount string from item
+ if (endIsAmount.get()) {
+ item = item.substring(0, lastSpace);
+ }
+
+ // Get material
+ String[] split = REPatterns.get("\\[").split(item, 2);
+ String itemName = split[0];
+ Material material = Material.matchMaterial(itemName);
+ if (material == null) {
+ issuer.sendError("Invalid Material: " + split[0]);
+ return null;
+ }
+
+ // Create item and parse additional vanilla component data
+ ItemStack itemStack = new ItemStack(material, amount);
+ if (split.length < 2) {
+ return itemStack;
+ }
+ String additionalData = split[1];
+ return Try.of(() -> Bukkit.getUnsafe().modifyItemStack(itemStack, itemStack.getType().getKey() + "[" + additionalData))
+ .onFailure(throwable -> issuer.sendError(throwable.getMessage()))
+ .getOrNull();
+ }
+
+ private CompletableFuture updatePlayerInventory(
+ MVCommandIssuer issuer,
+ OfflinePlayer player,
+ MultiverseWorld world,
+ ProfileType profileType,
+ @Nullable ItemStack[] inventory,
+ @NotNull ItemStack itemStack
+ ) {
+ putItemInInventory(inventory, itemStack);
+ return SingleShareWriter.of(inventories, player, world.getName(), profileType, Sharables.INVENTORY)
+ .write(inventory, true)
+ .thenCompose(ignore -> player.isOnline()
+ ? CompletableFuture.completedFuture(null)
+ : profileDataSource.modifyGlobalProfile(GlobalProfileKey.of(player), profile -> profile.setLoadOnLogin(true)))
+ .thenRun(() -> issuer.sendInfo("Gave player %s %s %s in world %s."
+ .formatted(player.getName(), itemStack.getAmount(), itemStack.getI18NDisplayName(), world.getName())));
+ }
+
+ private void putItemInInventory(@Nullable ItemStack[] inventory, @NotNull ItemStack itemStack) {
+ if (inventory == null) {
+ inventory = new ItemStack[PlayerStats.INVENTORY_SIZE];
+ }
+ int amountLeft = itemStack.getAmount();
+ for (int i = 0; i < inventory.length; i++) {
+ if (inventory[i] == null || inventory[i].getType() == Material.AIR) {
+ int amountToGive = Math.min(amountLeft, itemStack.getMaxStackSize());
+ inventory[i] = itemStack.clone();
+ inventory[i].setAmount(amountToGive);
+ amountLeft -= amountToGive;
+ } else if (inventory[i].isSimilar(itemStack)) {
+ int amountToGive = Math.min(amountLeft, itemStack.getMaxStackSize() - inventory[i].getAmount());
+ inventory[i].setAmount(inventory[i].getAmount() + amountToGive);
+ amountLeft -= amountToGive;
+ }
+
+ if (amountLeft == 0) {
+ break;
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/GroupCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/GroupCommand.java
new file mode 100644
index 00000000..ec821f38
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/GroupCommand.java
@@ -0,0 +1,59 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.mvplugins.multiverse.inventories.commands.prompts.GroupControlPrompt;
+import org.bukkit.command.CommandSender;
+import org.bukkit.conversations.Conversable;
+import org.bukkit.conversations.Conversation;
+import org.bukkit.conversations.ConversationFactory;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+@Service
+class GroupCommand extends InventoriesCommand {
+
+ private final MultiverseInventories plugin;
+
+ @Inject
+ GroupCommand(@NotNull MultiverseInventories plugin) {
+ this.plugin = plugin;
+ }
+
+ @Subcommand("group")
+ @CommandPermission("multiverse.inventories.group")
+ @Description("Manage a world group with prompts!")
+ void onGroupCommand(@NotNull MVCommandIssuer issuer) {
+ if (!(issuer.getIssuer() instanceof Conversable conversable)) {
+ issuer.sendError(MVInvi18n.GROUP_NONCONVERSABLE);
+ return;
+ }
+ Conversation conversation = new ConversationFactory(plugin)
+ .withFirstPrompt(new GroupControlPrompt(plugin, issuer))
+ .withEscapeSequence("##")
+ .withModality(false).buildConversation(conversable);
+ conversation.begin();
+ }
+
+ @Service
+ private final static class LegacyAlias extends GroupCommand implements LegacyAliasCommand {
+ @Inject
+ LegacyAlias(MultiverseInventories plugin) {
+ super(plugin);
+ }
+
+ @Override
+ @CommandAlias("mvinvgroup|mvinvg")
+ void onGroupCommand(MVCommandIssuer issuer) {
+ super.onGroupCommand(issuer);
+ }
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/HelpCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/HelpCommand.java
new file mode 100644
index 00000000..54462e67
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/HelpCommand.java
@@ -0,0 +1,38 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.jetbrains.annotations.NotNull;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.external.acf.commands.CommandHelp;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+
+@Service
+final class HelpCommand extends InventoriesCommand {
+
+ private final MVCommandManager commandManager;
+
+ @Inject
+ HelpCommand(@NotNull MVCommandManager commandManager) {
+ this.commandManager = commandManager;
+ }
+
+ @org.mvplugins.multiverse.external.acf.commands.annotation.HelpCommand
+ @Subcommand("help")
+ @CommandPermission("multiverse.inventories.help")
+ @CommandCompletion("@commands:mvinv")
+ @Syntax("[filter] [page]")
+ @Description("Displays a list of available commands.")
+ void onUsageCommand(CommandHelp help) {
+ if (help.getIssuer().isPlayer()) {
+ // Prevent flooding the chat
+ help.setPerPage(4);
+ }
+ this.commandManager.showUsage(help);
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/InfoCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/InfoCommand.java
new file mode 100644
index 00000000..0ffc436c
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/InfoCommand.java
@@ -0,0 +1,130 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.inventories.profile.key.ContainerType;
+import org.mvplugins.multiverse.inventories.profile.container.ProfileContainerStoreProvider;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.bukkit.Bukkit;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Optional;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Single;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.inventories.profile.container.ProfileContainer;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import java.util.List;
+import java.util.Set;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+@Service
+class InfoCommand extends InventoriesCommand {
+
+ private final ProfileContainerStoreProvider profileContainerStoreProvider;
+ private final WorldGroupManager worldGroupManager;
+
+ @Inject
+ InfoCommand(
+ @NotNull ProfileContainerStoreProvider profileContainerStoreProvider,
+ @NotNull WorldGroupManager worldGroupManager
+ ) {
+ this.profileContainerStoreProvider = profileContainerStoreProvider;
+ this.worldGroupManager = worldGroupManager;
+ }
+
+ @Subcommand("info")
+ @CommandPermission("multiverse.inventories.info")
+ @CommandCompletion("@mvworlds")
+ @Syntax("")
+ @Description("World and Group Information")
+ void onInfoCommand(
+ @NotNull MVCommandIssuer issuer,
+
+ @Optional
+ @Single
+ @Syntax("")
+ @Description("World or Group")
+ @NotNull String name
+ ) {
+ if (name == null) {
+ if (!issuer.isPlayer()) {
+ issuer.sendError(MVInvi18n.INFO_ZEROARG);
+ return;
+ }
+ name = issuer.getPlayer().getWorld().getName();
+ }
+
+ ProfileContainer worldProfileContainer = profileContainerStoreProvider.getStore(ContainerType.WORLD).getContainer(name);
+ issuer.sendInfo(MVInvi18n.INFO_WORLD, replace("{world}").with(name));
+ if (worldProfileContainer != null && Bukkit.getWorld(worldProfileContainer.getContainerName()) != null) {
+ worldInfo(issuer, worldProfileContainer);
+ } else {
+ issuer.sendError(MVInvi18n.ERROR_NOWORLDPROFILE, replace("{world}").with(name));
+ }
+ WorldGroup worldGroup = worldGroupManager.getGroup(name);
+ issuer.sendInfo(MVInvi18n.INFO_GROUP, replace("{group}").with(name));
+ if (worldGroup != null) {
+ this.groupInfo(issuer, worldGroup);
+ } else {
+ issuer.sendError(MVInvi18n.ERROR_NOGROUP, replace("{group}").with(name));
+ }
+ }
+
+ private void groupInfo(MVCommandIssuer issuer, WorldGroup worldGroup) {
+ StringBuilder worldsString = new StringBuilder();
+ Set worlds = worldGroup.getWorlds();
+ if (worlds.isEmpty()) {
+ worldsString.append("N/A");
+ } else {
+ for (String world : worlds) {
+ if (!worldsString.toString().isEmpty()) {
+ worldsString.append(", ");
+ }
+ worldsString.append(world);
+ }
+ }
+ issuer.sendInfo(MVInvi18n.INFO_GROUP_INFO, replace("{worlds}").with(worldsString));
+ issuer.sendInfo(MVInvi18n.INFO_GROUP_INFOSHARES, replace("{shares}").with(worldGroup.getShares()));
+ }
+
+ private void worldInfo(MVCommandIssuer issuer, ProfileContainer worldProfileContainer) {
+ StringBuilder groupsString = new StringBuilder();
+ List worldGroups = worldGroupManager.getGroupsForWorld(worldProfileContainer.getContainerName());
+
+ if (worldGroups.isEmpty()) {
+ groupsString.append("N/A");
+ } else {
+ for (WorldGroup worldGroup : worldGroups) {
+ if (!groupsString.toString().isEmpty()) {
+ groupsString.append(", ");
+ }
+ groupsString.append(worldGroup.getName());
+ }
+ }
+ issuer.sendInfo(MVInvi18n.INFO_WORLD_INFO, replace("{groups}").with(groupsString));
+ }
+
+ @Service
+ private final static class LegacyAlias extends InfoCommand implements LegacyAliasCommand {
+ @Inject
+ LegacyAlias(ProfileContainerStoreProvider profileContainerStoreProvider, WorldGroupManager worldGroupManager) {
+ super(profileContainerStoreProvider, worldGroupManager);
+ }
+
+ @Override
+ @CommandAlias("mvinvinfo|mvinvi")
+ void onInfoCommand(MVCommandIssuer issuer, String name) {
+ super.onInfoCommand(issuer, name);
+ }
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/InventoriesCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/InventoriesCommand.java
new file mode 100644
index 00000000..34c50c2c
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/InventoriesCommand.java
@@ -0,0 +1,15 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.jvnet.hk2.annotations.Contract;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.core.command.MultiverseCommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+
+/**
+ * Base class for all multiverse inventories commands.
+ */
+@Contract
+@CommandAlias("mvinv")
+public abstract class InventoriesCommand extends MultiverseCommand {
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/ListCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/ListCommand.java
new file mode 100644
index 00000000..ae5f4444
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/ListCommand.java
@@ -0,0 +1,66 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import java.util.Collection;
+import java.util.List;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+@Service
+class ListCommand extends InventoriesCommand {
+
+ private final WorldGroupManager worldGroupManager;
+
+ @Inject
+ ListCommand(@NotNull WorldGroupManager worldGroupManager) {
+ this.worldGroupManager = worldGroupManager;
+ }
+
+ @Subcommand("list")
+ @CommandPermission("multiverse.inventories.list")
+ @Description("World and Group Information")
+ void onListCommand(@NotNull MVCommandIssuer issuer) {
+ Collection groups = worldGroupManager.getGroups();
+ String groupsString = "N/A";
+ if (!groups.isEmpty()) {
+ StringBuilder builder = new StringBuilder();
+ for (WorldGroup group : groups) {
+ if (!builder.toString().isEmpty()) {
+ builder.append(", ");
+ }
+ builder.append(group.getName());
+ }
+ groupsString = builder.toString();
+ }
+ issuer.sendInfo(MVInvi18n.LIST_GROUPS);
+ issuer.sendInfo(MVInvi18n.LIST_GROUPS_INFO, replace("{groups}").with(groupsString));
+ }
+
+ @Service
+ private final static class LegacyAlias extends ListCommand implements LegacyAliasCommand {
+ @Inject
+ LegacyAlias(WorldGroupManager worldGroupManager) {
+ super(worldGroupManager);
+ }
+
+ @Override
+ @CommandAlias("mvinvlist|mvinvl")
+ void onListCommand(MVCommandIssuer issuer) {
+ super.onListCommand(issuer);
+ }
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/MigrateCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/MigrateCommand.java
new file mode 100644
index 00000000..62965a1c
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/MigrateCommand.java
@@ -0,0 +1,69 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.jetbrains.annotations.NotNull;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
+import org.mvplugins.multiverse.core.command.queue.CommandQueuePayload;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Single;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.inventories.dataimport.DataImportManager;
+import org.mvplugins.multiverse.inventories.dataimport.DataImporter;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+@Service
+final class MigrateCommand extends InventoriesCommand {
+
+ private final DataImportManager dataImportManager;
+ private final CommandQueueManager commandQueueManager;
+
+ @Inject
+ MigrateCommand(
+ @NotNull DataImportManager dataImportManager,
+ @NotNull CommandQueueManager commandQueueManager
+ ) {
+ this.dataImportManager = dataImportManager;
+ this.commandQueueManager = commandQueueManager;
+ }
+
+ @Subcommand("migrate")
+ @Syntax("")
+ @CommandPermission("multiverse.inventories.migrate")
+ @CommandCompletion("@dataimporters")
+ @Description("Import inventories from MultiInv/WorldInventories/PerWorldInventory plugin.")
+ void onMigrateCommand(
+ MVCommandIssuer issuer,
+
+ @Single
+ @Syntax("")
+ String pluginName) {
+
+ dataImportManager.getImporter(pluginName)
+ .onEmpty(() -> issuer.sendError(MVInvi18n.MIGRATE_UNSUPPORTEDPLUGIN, replace("{plugin}").with(pluginName)))
+ .peek(dataImporter -> {
+ if (!dataImporter.isEnabled()) {
+ issuer.sendError(MVInvi18n.MIGRATE_PLUGINNOTENABLED, replace("{plugin}").with(pluginName));
+ return;
+ }
+ commandQueueManager.addToQueue(CommandQueuePayload.issuer(issuer)
+ .prompt(Message.of(MVInvi18n.MIGRATE_CONFIRMPROMPT, replace("{plugin}").with(pluginName)))
+ .action(() -> doDataImport(issuer, dataImporter)));
+ });
+ }
+
+ void doDataImport(MVCommandIssuer issuer, DataImporter dataImporter) {
+ if (dataImporter.importData()) {
+ issuer.sendInfo(MVInvi18n.MIGRATE_SUCCESS, replace("{plugin}").with(dataImporter.getPluginName()));
+ } else {
+ issuer.sendError(MVInvi18n.MIGRATE_FAILED, replace("{plugin}").with(dataImporter.getPluginName()));
+ }
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/ReloadCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/ReloadCommand.java
new file mode 100644
index 00000000..cbf16d52
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/ReloadCommand.java
@@ -0,0 +1,47 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+@Service
+class ReloadCommand extends InventoriesCommand {
+
+ private final MultiverseInventories plugin;
+
+ @Inject
+ ReloadCommand(@NotNull MultiverseInventories plugin) {
+ this.plugin = plugin;
+ }
+
+ @Subcommand("reload")
+ @CommandPermission("multiverse.inventories.reload")
+ @Description("Reloads config file")
+ void onReloadCommand(@NotNull MVCommandIssuer issuer) {
+ this.plugin.reloadConfig();
+ issuer.sendInfo(MVInvi18n.RELOAD_COMPLETE);
+ }
+
+ @Service
+ private final static class LegacyAlias extends ReloadCommand implements LegacyAliasCommand {
+ @Inject
+ LegacyAlias(MultiverseInventories plugin) {
+ super(plugin);
+ }
+
+ @Override
+ @CommandAlias("mvinvreload")
+ void onReloadCommand(MVCommandIssuer issuer) {
+ super.onReloadCommand(issuer);
+ }
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveDisabledSharesCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveDisabledSharesCommand.java
new file mode 100644
index 00000000..6ccf8c64
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveDisabledSharesCommand.java
@@ -0,0 +1,53 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.share.Shares;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+@Service
+final class RemoveDisabledSharesCommand extends InventoriesCommand {
+
+ private final WorldGroupManager worldGroupManager;
+
+ @Inject
+ RemoveDisabledSharesCommand(@NotNull WorldGroupManager worldGroupManager) {
+ this.worldGroupManager = worldGroupManager;
+ }
+
+ @Subcommand("remove-disabled-shares")
+ @CommandPermission("multiverse.inventories.removedisabledshares")
+ @CommandCompletion("@worldGroups @shares")
+ @Syntax(" ")
+ @Description("Remove one or more disabled shares from a group.")
+ void onRemoveSharesCommand(
+ MVCommandIssuer issuer,
+
+ @Syntax("")
+ @Description("Group you want to remove the shares from.")
+ WorldGroup group,
+
+ @Syntax("")
+ @Description("One or more sharables to remove.")
+ Shares shares
+ ) {
+ group.getDisabledShares().setSharing(shares, false);
+ worldGroupManager.updateGroup(group);
+ issuer.sendInfo(MVInvi18n.DISABLEDSHARES_NOWSHARING,
+ replace("{group}").with(group.getName()),
+ replace("{shares}").with(group.getDisabledShares().toStringList()));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveSharesCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveSharesCommand.java
new file mode 100644
index 00000000..326471ce
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveSharesCommand.java
@@ -0,0 +1,56 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.share.Sharables;
+import org.mvplugins.multiverse.inventories.share.Shares;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+@Service
+final class RemoveSharesCommand extends InventoriesCommand {
+ private final WorldGroupManager worldGroupManager;
+
+ @Inject
+ RemoveSharesCommand(@NotNull WorldGroupManager worldGroupManager) {
+ this.worldGroupManager = worldGroupManager;
+ }
+
+ @Subcommand("remove-shares")
+ @CommandPermission("multiverse.inventories.removeshares")
+ @CommandCompletion("@worldGroups @shares")
+ @Syntax(" ")
+ @Description("Remove one or more shares from a group.")
+ void onRemoveSharesCommand(
+ MVCommandIssuer issuer,
+
+ @Syntax("")
+ @Description("Group you want to remove the shares from.")
+ WorldGroup group,
+
+ @Syntax("")
+ @Description("One or more sharables to remove.")
+ Shares shares
+ ) {
+ group.getShares().setSharing(shares, false);
+ worldGroupManager.updateGroup(group);
+ var negativeshares = Sharables.allOf();
+ negativeshares.setSharing(group.getShares(), false);
+ issuer.sendInfo(MVInvi18n.SHARES_NOWSHARING,
+ replace("{group}").with(group.getName()),
+ replace("{shares}").with(group.getShares().toStringList()),
+ replace("{negativeshares}").with(negativeshares.toStringList()));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveWorldsCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveWorldsCommand.java
new file mode 100644
index 00000000..0840f9a1
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveWorldsCommand.java
@@ -0,0 +1,66 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
+import org.mvplugins.multiverse.core.world.MultiverseWorld;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Single;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+
+@Service
+final class RemoveWorldsCommand extends InventoriesCommand {
+
+ private final WorldGroupManager worldGroupManager;
+
+ @Inject
+ RemoveWorldsCommand(@NotNull WorldGroupManager worldGroupManager) {
+ this.worldGroupManager = worldGroupManager;
+ }
+
+ @Subcommand("remove-worlds")
+ @CommandPermission("multiverse.inventories.removeworlds")
+ @CommandCompletion("@worldGroups @worldGroupWorlds")
+ @Syntax(", ")
+ @Description("Adds a World to a World Group.")
+ void onRemoveWorldCommand(
+ MVCommandIssuer issuer,
+
+ @Syntax("")
+ @Description("Group you want to remove the world from.")
+ @NotNull WorldGroup group,
+
+ @Single
+ @Syntax("")
+ @Description("World name to remove.")
+ String worldNames
+ ) {
+ List worldNamesArr = Arrays.stream(worldNames.split(",")).toList();
+ if (!group.removeWorlds(worldNamesArr)) {
+ issuer.sendError(MVInvi18n.REMOVEWORLD_WORLDNOTINGROUP,
+ replace("{group}").with(group.getName()),
+ replace("{world}").with(worldNames));
+ return;
+ }
+ worldGroupManager.updateGroup(group);
+ issuer.sendInfo(MVInvi18n.REMOVEWORLD_WORLDREMOVED,
+ replace("{group}").with(group.getName()),
+ replace("{world}").with(worldNames));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/ToggleCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/ToggleCommand.java
new file mode 100644
index 00000000..a6e93e9e
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/ToggleCommand.java
@@ -0,0 +1,75 @@
+package org.mvplugins.multiverse.inventories.commands;
+
+import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.inventories.config.InventoriesConfig;
+import org.mvplugins.multiverse.inventories.share.Sharable;
+import org.mvplugins.multiverse.inventories.share.Shares;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Single;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+@Service
+class ToggleCommand extends InventoriesCommand {
+
+ private final InventoriesConfig inventoriesConfig;
+
+ @Inject
+ ToggleCommand(@NotNull InventoriesConfig inventoriesConfig) {
+ this.inventoriesConfig = inventoriesConfig;
+ }
+
+ @Subcommand("toggle")
+ @CommandPermission("multiverse.inventories.addshares")
+ @CommandCompletion("@sharables:scope=optional")
+ @Syntax("")
+ @Description("Toggles the usage of optional sharables")
+ void onToggleCommand(
+ @NotNull MVCommandIssuer issuer,
+
+ @Single
+ @Syntax("")
+ @Description("Share to toggle")
+ @NotNull Sharable> sharable
+ ) {
+ Shares optionalShares = inventoriesConfig.getActiveOptionalShares();
+ if (!sharable.isOptional()) {
+ issuer.sendError(MVInvi18n.TOGGLE_NOOPTIONALSHARES, replace("{share}").with(sharable.toString()));
+ return;
+ }
+ if (optionalShares.contains(sharable)) {
+ optionalShares.remove(sharable);
+ issuer.sendInfo(MVInvi18n.TOGGLE_NOWNOTUSINGOPTIONAL, replace("{share}").with(sharable.getNames()[0]));
+ } else {
+ optionalShares.add(sharable);
+ issuer.sendInfo(MVInvi18n.TOGGLE_NOWUSINGOPTIONAL, replace("{share}").with(sharable.getNames()[0]));
+ }
+ inventoriesConfig.setActiveOptionalShares(optionalShares);
+ inventoriesConfig.save();
+ }
+
+ @Service
+ private final static class LegacyAlias extends ToggleCommand implements LegacyAliasCommand {
+ @Inject
+ LegacyAlias(InventoriesConfig inventoriesConfig) {
+ super(inventoriesConfig);
+ }
+
+ @Override
+ @CommandAlias("mvinvtoggle")
+ void onToggleCommand(MVCommandIssuer issuer, Sharable> sharable) {
+ super.onToggleCommand(issuer, sharable);
+ }
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/BulkEditCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/BulkEditCommand.java
new file mode 100644
index 00000000..e071d9ed
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/BulkEditCommand.java
@@ -0,0 +1,46 @@
+package org.mvplugins.multiverse.inventories.commands.bulkedit;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jvnet.hk2.annotations.Contract;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.utils.StringFormatter;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.inventories.commands.InventoriesCommand;
+import org.mvplugins.multiverse.inventories.profile.bulkedit.BulkEditAction;
+import org.mvplugins.multiverse.inventories.profile.bulkedit.BulkEditCreator;
+import org.mvplugins.multiverse.inventories.profile.bulkedit.BulkEditResult;
+
+@Contract
+@ApiStatus.Internal
+public abstract class BulkEditCommand extends InventoriesCommand {
+
+ protected final BulkEditCreator bulkEditCreator;
+
+ @Inject
+ protected BulkEditCommand(BulkEditCreator bulkEditCreator) {
+ this.bulkEditCreator = bulkEditCreator;
+ }
+
+ protected void outputActionSummary(MVCommandIssuer issuer, BulkEditAction> bulkEditAction) {
+ issuer.sendMessage("Summary of affected profiles:");
+ bulkEditAction.getActionSummary().forEach((key, value) ->
+ issuer.sendMessage(" %s: %s".formatted(key, value.size() > 10
+ ? value.size()
+ : StringFormatter.join(value, ", "))));
+
+ }
+
+ protected void runBulkEditAction(MVCommandIssuer issuer, BulkEditAction> bulkEditAction) {
+ issuer.sendMessage("Starting bulk edit action...");
+ bulkEditAction.execute()
+ .thenAccept(result -> outputResult(issuer, result));
+ }
+
+ protected void outputResult(MVCommandIssuer issuer, BulkEditResult bulkEditResult) {
+ issuer.sendMessage("Successfully processed %d profiles!".formatted(bulkEditResult.getSuccessCount()));
+ if (bulkEditResult.getFailureCount() > 0) {
+ issuer.sendError("Failed to process %d profiles! See log for details.".formatted(bulkEditResult.getFailureCount()));
+ }
+ issuer.sendMessage("Bulk edit action completed in %.4f ms.".formatted(bulkEditResult.getTimeTaken()));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/globalprofile/ClearCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/globalprofile/ClearCommand.java
new file mode 100644
index 00000000..7be2c960
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/globalprofile/ClearCommand.java
@@ -0,0 +1,85 @@
+package org.mvplugins.multiverse.inventories.commands.bulkedit.globalprofile;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.flag.CommandFlag;
+import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
+import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
+import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
+import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
+import org.mvplugins.multiverse.core.command.queue.CommandQueuePayload;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.commands.InventoriesCommand;
+import org.mvplugins.multiverse.inventories.commands.bulkedit.BulkEditCommand;
+import org.mvplugins.multiverse.inventories.profile.ProfileDataSource;
+import org.mvplugins.multiverse.inventories.profile.bulkedit.BulkEditAction;
+import org.mvplugins.multiverse.inventories.profile.bulkedit.BulkEditCreator;
+import org.mvplugins.multiverse.inventories.profile.key.GlobalProfileKey;
+
+import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
+
+@Service
+final class ClearCommand extends BulkEditCommand {
+
+ private final CommandQueueManager commandQueueManager;
+ private final Flags flags;
+
+ @Inject
+ ClearCommand(
+ @NotNull BulkEditCreator bulkEditCreator,
+ @NotNull CommandQueueManager commandQueueManager,
+ @NotNull Flags flags
+ ) {
+ super(bulkEditCreator);
+ this.commandQueueManager = commandQueueManager;
+ this.flags = flags;
+ }
+
+ @Subcommand("bulkedit globalprofile clear")
+ @CommandPermission("multiverse.inventories.bulkedit")
+ @CommandCompletion("@mvinvplayernames @flags:groupName=" + Flags.NAME)
+ @Syntax(" [--clear-all-player-profiles]")
+ void onCommand(
+ MVCommandIssuer issuer,
+
+ @Syntax("")
+ GlobalProfileKey[] globalProfileKeys,
+
+ @Syntax("[--clear-all-playerprofiles]")
+ String[] flagArray
+ ) {
+ ParsedCommandFlags parsedFlags = flags.parse(flagArray);
+
+ BulkEditAction> bulkEditAction = bulkEditCreator.globalProfileClear(
+ globalProfileKeys,
+ parsedFlags.hasFlag(flags.clearAllPlayerProfiles)
+ );
+
+ outputActionSummary(issuer, bulkEditAction);
+
+ commandQueueManager.addToQueue(CommandQueuePayload.issuer(issuer)
+ .prompt(Message.of("Are you sure you want to clear the selected global profiles?"))
+ .action(() -> runBulkEditAction(issuer, bulkEditAction)));
+ }
+
+ @Service
+ private static final class Flags extends FlagBuilder {
+ private static final String NAME = "mvinvbulkeditglobalprofileclear";
+
+ @Inject
+ private Flags(@NotNull CommandFlagsManager flagsManager) {
+ super(NAME, flagsManager);
+ }
+
+ private final CommandFlag clearAllPlayerProfiles = flag(CommandFlag.builder("--clear-all-player-profiles")
+ .addAlias("-a")
+ .build());
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/globalprofile/ModifyCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/globalprofile/ModifyCommand.java
new file mode 100644
index 00000000..bd419200
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/globalprofile/ModifyCommand.java
@@ -0,0 +1,69 @@
+package org.mvplugins.multiverse.inventories.commands.bulkedit.globalprofile;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
+import org.mvplugins.multiverse.core.command.queue.CommandQueuePayload;
+import org.mvplugins.multiverse.core.config.handle.PropertyModifyAction;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.inventories.commands.InventoriesCommand;
+import org.mvplugins.multiverse.inventories.profile.ProfileDataSource;
+import org.mvplugins.multiverse.inventories.profile.key.GlobalProfileKey;
+
+import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Service
+final class ModifyCommand extends InventoriesCommand {
+
+ private final CommandQueueManager commandQueueManager;
+ private final ProfileDataSource profileDataSource;
+
+ @Inject
+ ModifyCommand(CommandQueueManager commandQueueManager, ProfileDataSource profileDataSource) {
+ this.commandQueueManager = commandQueueManager;
+ this.profileDataSource = profileDataSource;
+ }
+
+ @Subcommand("bulkedit globalprofile modify")
+ @CommandPermission("multiverse.inventories.bulkedit")
+ @CommandCompletion("load-on-login|last-world @empty @mvinvplayernames")
+ @Syntax(" ")
+ void onCommand(
+ MVCommandIssuer issuer,
+
+ @Syntax("")
+ String property,
+
+ @Syntax("")
+ String value,
+
+ @Syntax("")
+ GlobalProfileKey[] profileKeys
+ ) {
+ commandQueueManager.addToQueue(CommandQueuePayload.issuer(issuer)
+ .prompt(Message.of("Are you sure you want to modify %s to %s for %d players?".formatted(property, value, profileKeys.length)))
+ .action(() -> doModify(issuer, property, value, profileKeys)));
+ }
+
+ private void doModify(MVCommandIssuer issuer, String property, String value, GlobalProfileKey[] profileKeys) {
+ AtomicInteger counter = new AtomicInteger(0);
+ CompletableFuture[] futures = Arrays.stream(profileKeys)
+ .map(profileKey ->
+ profileDataSource.modifyGlobalProfile(profileKey, globalProfile ->
+ globalProfile.getStringPropertyHandle()
+ .modifyPropertyString(property, value, PropertyModifyAction.SET)
+ .onSuccess(ignore -> counter.incrementAndGet())
+ .onFailure(throwable -> issuer.sendError("Failed to modify %s for %s. %s".formatted(property, profileKey, throwable.getMessage())))))
+ .toArray(CompletableFuture[]::new);
+
+ CompletableFuture.allOf(futures)
+ .thenRun(() -> issuer.sendMessage("Successfully modified %s to %s for %d players.".formatted(property, value, counter.get())));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/ClearCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/ClearCommand.java
new file mode 100644
index 00000000..ee32445e
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/ClearCommand.java
@@ -0,0 +1,68 @@
+package org.mvplugins.multiverse.inventories.commands.bulkedit.playerprofile;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
+import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
+import org.mvplugins.multiverse.core.command.queue.CommandQueuePayload;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.commands.bulkedit.BulkEditCommand;
+import org.mvplugins.multiverse.inventories.profile.bulkedit.BulkEditAction;
+import org.mvplugins.multiverse.inventories.profile.bulkedit.BulkEditCreator;
+import org.mvplugins.multiverse.inventories.profile.bulkedit.PlayerProfilesPayload;
+import org.mvplugins.multiverse.inventories.profile.key.ContainerKey;
+import org.mvplugins.multiverse.inventories.profile.key.GlobalProfileKey;
+import org.mvplugins.multiverse.inventories.profile.key.ProfileType;
+
+@Service
+final class ClearCommand extends BulkEditCommand {
+
+ private final CommandQueueManager commandQueueManager;
+ private final IncludeGroupsWorldsFlag flags;
+
+ @Inject
+ ClearCommand(
+ @NotNull BulkEditCreator bulkEditCreator,
+ @NotNull CommandQueueManager commandQueueManager,
+ @NotNull IncludeGroupsWorldsFlag flags
+ ) {
+ super(bulkEditCreator);
+ this.commandQueueManager = commandQueueManager;
+ this.flags = flags;
+ }
+
+ @Subcommand("bulkedit playerprofile clear")
+ @CommandPermission("multiverse.inventories.bulkedit")
+ @CommandCompletion("@mvinvplayernames @empty @mvinvprofiletypes:multiple @flags:groupName=" + IncludeGroupsWorldsFlag.NAME)
+ @Syntax(" [profile-type] [--include-groups-worlds]")
+ void onCommand(
+ MVCommandIssuer issuer,
+ GlobalProfileKey[] globalProfileKeys,
+ ContainerKey[] containerKeys,
+ ProfileType[] profileTypes,
+ String[] flagArray
+ ) {
+ ParsedCommandFlags parsedFlags = flags.parse(flagArray);
+
+ BulkEditAction> bulkEditAction = bulkEditCreator.playerProfileClear(
+ new PlayerProfilesPayload(
+ globalProfileKeys,
+ containerKeys,
+ profileTypes,
+ parsedFlags.hasFlag(flags.includeGroupsWorlds)
+ )
+ );
+
+ outputActionSummary(issuer, bulkEditAction);
+
+ commandQueueManager.addToQueue(CommandQueuePayload.issuer(issuer)
+ .prompt(Message.of("Are you sure you want to clear the selected profiles?"))
+ .action(() -> runBulkEditAction(issuer, bulkEditAction)));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/DeleteCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/DeleteCommand.java
new file mode 100644
index 00000000..7308e7be
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/DeleteCommand.java
@@ -0,0 +1,72 @@
+package org.mvplugins.multiverse.inventories.commands.bulkedit.playerprofile;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
+import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
+import org.mvplugins.multiverse.core.command.queue.CommandQueuePayload;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.core.utils.StringFormatter;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.commands.bulkedit.BulkEditCommand;
+import org.mvplugins.multiverse.inventories.profile.bulkedit.BulkEditAction;
+import org.mvplugins.multiverse.inventories.profile.bulkedit.BulkEditCreator;
+import org.mvplugins.multiverse.inventories.profile.bulkedit.PlayerProfilesPayload;
+import org.mvplugins.multiverse.inventories.profile.key.ContainerKey;
+import org.mvplugins.multiverse.inventories.profile.key.GlobalProfileKey;
+import org.mvplugins.multiverse.inventories.profile.key.ProfileType;
+import org.mvplugins.multiverse.inventories.share.Sharable;
+
+@Service
+final class DeleteCommand extends BulkEditCommand {
+
+ private final CommandQueueManager commandQueueManager;
+ private final IncludeGroupsWorldsFlag flags;
+
+ @Inject
+ DeleteCommand(
+ @NotNull BulkEditCreator bulkEditCreator,
+ @NotNull CommandQueueManager commandQueueManager,
+ @NotNull IncludeGroupsWorldsFlag flags
+ ) {
+ super(bulkEditCreator);
+ this.commandQueueManager = commandQueueManager;
+ this.flags = flags;
+ }
+
+ @Subcommand("bulkedit playerprofile delete")
+ @CommandPermission("multiverse.inventories.bulkedit")
+ @CommandCompletion("@shares @mvinvplayernames @empty @mvinvprofiletypes:multiple @flags:groupName=" + IncludeGroupsWorldsFlag.NAME)
+ @Syntax(" [profile-type] [--include-groups-worlds]")
+ void onCommand(
+ MVCommandIssuer issuer,
+ Sharable sharable,
+ GlobalProfileKey[] globalProfileKeys,
+ ContainerKey[] containerKeys,
+ ProfileType[] profileTypes,
+ String[] flagArray
+ ) {
+ ParsedCommandFlags parsedFlags = flags.parse(flagArray);
+
+ BulkEditAction> bulkEditAction = bulkEditCreator.playerProfileDeleteSharable(
+ new PlayerProfilesPayload(
+ globalProfileKeys,
+ containerKeys,
+ profileTypes,
+ parsedFlags.hasFlag(flags.includeGroupsWorlds)
+ ),
+ sharable
+ );
+
+ outputActionSummary(issuer, bulkEditAction);
+
+ commandQueueManager.addToQueue(CommandQueuePayload.issuer(issuer)
+ .prompt(Message.of("Are you sure you want to delete %s from the selected profiles?".formatted(sharable.getNames()[0])))
+ .action(() -> runBulkEditAction(issuer, bulkEditAction)));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/IncludeGroupsWorldsFlag.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/IncludeGroupsWorldsFlag.java
new file mode 100644
index 00000000..b344cb48
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/IncludeGroupsWorldsFlag.java
@@ -0,0 +1,21 @@
+package org.mvplugins.multiverse.inventories.commands.bulkedit.playerprofile;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.flag.CommandFlag;
+import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
+import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+
+@Service
+final class IncludeGroupsWorldsFlag extends FlagBuilder {
+ static final String NAME = "mvinvincludegroupsworlds";
+
+ @Inject
+ private IncludeGroupsWorldsFlag(CommandFlagsManager flagsManager) {
+ super(NAME, flagsManager);
+ }
+
+ final CommandFlag includeGroupsWorlds = flag(CommandFlag.builder("--include-groups-worlds")
+ .addAlias("-i")
+ .build());
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/MigrateInventorySerializationCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/MigrateInventorySerializationCommand.java
new file mode 100644
index 00000000..593695ad
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/MigrateInventorySerializationCommand.java
@@ -0,0 +1,100 @@
+package org.mvplugins.multiverse.inventories.commands.bulkedit.playerprofile;
+
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
+import org.mvplugins.multiverse.core.command.queue.CommandQueuePayload;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.inventories.commands.InventoriesCommand;
+import org.mvplugins.multiverse.inventories.config.InventoriesConfig;
+import org.mvplugins.multiverse.inventories.profile.GlobalProfile;
+import org.mvplugins.multiverse.inventories.profile.ProfileDataSource;
+import org.mvplugins.multiverse.inventories.profile.key.GlobalProfileKey;
+import org.mvplugins.multiverse.inventories.profile.key.ProfileKey;
+import org.mvplugins.multiverse.inventories.profile.key.ProfileTypes;
+import org.mvplugins.multiverse.inventories.profile.key.ContainerType;
+
+import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicLong;
+
+@Service
+final class MigrateInventorySerializationCommand extends InventoriesCommand {
+
+ private final CommandQueueManager commandQueueManager;
+ private final ProfileDataSource profileDataSource;
+ private final InventoriesConfig inventoriesConfig;
+
+ @Inject
+ MigrateInventorySerializationCommand(
+ @NotNull CommandQueueManager commandQueueManager,
+ @NotNull ProfileDataSource profileDataSource,
+ @NotNull InventoriesConfig inventoriesConfig
+ ) {
+ this.commandQueueManager = commandQueueManager;
+ this.profileDataSource = profileDataSource;
+ this.inventoriesConfig = inventoriesConfig;
+ }
+
+ @Subcommand("bulkedit migrate inventory-serialization nbt")
+ @CommandPermission("multiverse.inventories.bulkedit")
+ void onNbtCommand(MVCommandIssuer issuer) {
+ commandQueueManager.addToQueue(CommandQueuePayload.issuer(issuer)
+ .prompt(Message.of("Are you sure you want to migrate all player data to NBT?"))
+ .action(() -> doMigration(issuer, true)));
+ }
+
+ @Subcommand("bulkedit migrate inventory-serialization bukkit")
+ @CommandPermission("multiverse.inventories.bulkedit")
+ void onBukkitCommand(MVCommandIssuer issuer) {
+ commandQueueManager.addToQueue(CommandQueuePayload.issuer(issuer)
+ .prompt(Message.of("Are you sure you want to migrate all player data to old Bukkit serialization?"))
+ .action(() -> doMigration(issuer, false)));
+ }
+
+ private void doMigration(MVCommandIssuer issuer, boolean useByteSerialization) {
+ inventoriesConfig.setUseByteSerializationForInventoryData(useByteSerialization);
+ inventoriesConfig.save();
+
+ long startTime = System.nanoTime();
+ AtomicLong profileCounter = new AtomicLong(0);
+ CompletableFuture.allOf(profileDataSource.listGlobalProfileUUIDs()
+ .stream()
+ .map(playerUUID -> profileDataSource.getGlobalProfile(GlobalProfileKey.of(playerUUID, ""))
+ .thenCompose(profile -> run(profile, profileCounter))
+ .exceptionally(throwable -> {
+ issuer.sendMessage("Error updating player " + playerUUID + ": " + throwable.getMessage());
+ return null;
+ }))
+ .toArray(CompletableFuture[]::new))
+ .thenRun(() -> {
+ long timeDuration = (System.nanoTime() - startTime) / 1000000;
+ issuer.sendMessage("Updated " + profileCounter.get() + " player profiles.");
+ issuer.sendMessage("Bulk edit completed in " + timeDuration + " ms.");
+ });
+ }
+
+ private CompletableFuture run(GlobalProfile profile, AtomicLong profileCounter) {
+ return CompletableFuture.allOf(Arrays.stream(ContainerType.values())
+ .flatMap(containerType -> profileDataSource.listContainerDataNames(containerType).stream()
+ .flatMap(dataName -> ProfileTypes.getTypes().stream()
+ .map(profileType -> profileDataSource.getPlayerProfile(ProfileKey.of(
+ containerType,
+ dataName,
+ profileType,
+ profile.getPlayerUUID(),
+ profile.getLastKnownName()
+ )).thenCompose(playerProfile -> {
+ if (playerProfile.getData().isEmpty()) {
+ return CompletableFuture.completedFuture(null);
+ }
+ profileCounter.incrementAndGet();
+ return profileDataSource.updatePlayerProfile(playerProfile);
+ }))))
+ .toArray(CompletableFuture[]::new));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/MigratePlayerNameCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/MigratePlayerNameCommand.java
new file mode 100644
index 00000000..e4aec8ad
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/bulkedit/playerprofile/MigratePlayerNameCommand.java
@@ -0,0 +1,47 @@
+package org.mvplugins.multiverse.inventories.commands.bulkedit.playerprofile;
+
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
+import org.mvplugins.multiverse.core.command.queue.CommandQueuePayload;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand;
+import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax;
+import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.external.vavr.control.Try;
+import org.mvplugins.multiverse.inventories.commands.InventoriesCommand;
+import org.mvplugins.multiverse.inventories.profile.ProfileDataSource;
+
+final class MigratePlayerNameCommand extends InventoriesCommand {
+
+ private final CommandQueueManager commandQueueManager;
+ private final ProfileDataSource profileDataSource;
+
+ MigratePlayerNameCommand(
+ @NotNull CommandQueueManager commandQueueManager,
+ @NotNull ProfileDataSource profileDataSource) {
+ this.commandQueueManager = commandQueueManager;
+ this.profileDataSource = profileDataSource;
+ }
+
+ @Subcommand("bulkedit migrate player-name")
+ @CommandPermission("multiverse.inventories.bulkedit")
+ @Syntax(" ")
+ @Description("Only use this if automatic migration failed for some reason.")
+ void onCommand(
+ MVCommandIssuer issuer,
+ String oldName,
+ String newName
+ ) {
+ commandQueueManager.addToQueue(CommandQueuePayload.issuer(issuer)
+ .prompt(Message.of("Are you sure you want to migrate all player data for %s to %s? This action cannot be undone."
+ .formatted(oldName, newName)))
+ .action(() -> doMigration(issuer, oldName, newName)));
+ }
+
+ private void doMigration(MVCommandIssuer issuer, String oldName, String newName) {
+ Try.run(() -> profileDataSource.migratePlayerProfileName(oldName, newName))
+ .onFailure(e -> issuer.sendMessage("Failed to migrate player data for " + oldName + ". " + e.getMessage()));
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/package-info.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/package-info.java
new file mode 100644
index 00000000..513b441b
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * This package contains all Commands.
+ */
+package org.mvplugins.multiverse.inventories.commands;
+
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupControlPrompt.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupControlPrompt.java
new file mode 100644
index 00000000..b3c44fdf
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupControlPrompt.java
@@ -0,0 +1,37 @@
+package org.mvplugins.multiverse.inventories.commands.prompts;
+
+import org.bukkit.ChatColor;
+import org.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.bukkit.conversations.ConversationContext;
+import org.bukkit.conversations.Prompt;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+public final class GroupControlPrompt extends InventoriesPrompt {
+
+ public GroupControlPrompt(final MultiverseInventories plugin, final MVCommandIssuer issuer) {
+ super(plugin, issuer);
+ }
+
+ @NotNull
+ @Override
+ Message getPromptMessage(@NotNull final ConversationContext conversationContext) {
+ return Message.of(MVInvi18n.GROUP_COMMANDPROMPT);
+ }
+
+ @Override
+ public Prompt acceptInput(@NotNull final ConversationContext conversationContext, final String input) {
+ if (input.equalsIgnoreCase("delete")) {
+ return new GroupDeletePrompt(plugin, issuer);
+ } else if (input.equalsIgnoreCase("create")) {
+ return new GroupCreatePrompt(plugin, issuer);
+ } else if (input.equalsIgnoreCase("edit")) {
+ return new GroupEditPrompt(plugin, issuer);
+ } else {
+ issuer.sendError(MVInvi18n.GROUP_INVALIDOPTION);
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupCreatePrompt.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupCreatePrompt.java
new file mode 100644
index 00000000..e2cf9306
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupCreatePrompt.java
@@ -0,0 +1,42 @@
+package org.mvplugins.multiverse.inventories.commands.prompts;
+
+import org.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.bukkit.conversations.ConversationContext;
+import org.bukkit.conversations.Prompt;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+final class GroupCreatePrompt extends InventoriesPrompt {
+
+ public GroupCreatePrompt(final MultiverseInventories plugin, final MVCommandIssuer issuer) {
+ super(plugin, issuer);
+ }
+
+ @NotNull
+ @Override
+ Message getPromptMessage(@NotNull final ConversationContext conversationContext) {
+ return Message.of(MVInvi18n.GROUP_CREATEPROMPT);
+ }
+
+ @Override
+ public Prompt acceptInput(@NotNull final ConversationContext conversationContext, final String s) {
+ final WorldGroup group = worldGroupManager.getGroup(s);
+ if (group == null) {
+ if (s.isEmpty() || !s.matches("^[a-zA-Z0-9][a-zA-Z0-9_]*$")) {
+ issuer.sendError(MVInvi18n.GROUP_INVALIDNAME);
+ return this;
+ }
+ final WorldGroup newGroup = worldGroupManager.newEmptyGroup(s);
+ return new GroupWorldsPrompt(plugin, issuer, newGroup,
+ new GroupSharesPrompt(plugin, issuer, newGroup, Prompt.END_OF_CONVERSATION, true), true);
+ } else {
+ issuer.sendError(MVInvi18n.GROUP_EXISTS, replace("{group}").with(s));
+ }
+ return Prompt.END_OF_CONVERSATION;
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupDeletePrompt.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupDeletePrompt.java
new file mode 100644
index 00000000..a21022ba
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupDeletePrompt.java
@@ -0,0 +1,47 @@
+package org.mvplugins.multiverse.inventories.commands.prompts;
+
+import org.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.bukkit.ChatColor;
+import org.bukkit.conversations.ConversationContext;
+import org.bukkit.conversations.Prompt;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+final class GroupDeletePrompt extends InventoriesPrompt {
+
+ public GroupDeletePrompt(final MultiverseInventories plugin, final MVCommandIssuer issuer) {
+ super(plugin, issuer);
+ }
+
+ @NotNull
+ @Override
+ Message getPromptMessage(@NotNull final ConversationContext conversationContext) {
+ final StringBuilder builder = new StringBuilder();
+ for (WorldGroup group : worldGroupManager.getGroups()) {
+ if (builder.isEmpty()) {
+ builder.append(ChatColor.WHITE);
+ } else {
+ builder.append(ChatColor.GOLD).append(", ").append(ChatColor.WHITE);
+ }
+ builder.append(group.getName());
+ }
+ return Message.of(MVInvi18n.GROUP_DELETEPROMPT, replace("{groups}").with(builder.toString()));
+ }
+
+ @Override
+ public Prompt acceptInput(@NotNull final ConversationContext conversationContext, final String input) {
+ final WorldGroup group = worldGroupManager.getGroup(input);
+ if (group == null) {
+ issuer.sendError(MVInvi18n.ERROR_NOGROUP, replace("{group}").with(input));
+ } else {
+ worldGroupManager.removeGroup(group);
+ issuer.sendInfo(MVInvi18n.GROUP_REMOVED, replace("{group}").with(input));
+ }
+ return Prompt.END_OF_CONVERSATION;
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupEditPrompt.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupEditPrompt.java
new file mode 100644
index 00000000..b700f608
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupEditPrompt.java
@@ -0,0 +1,46 @@
+package org.mvplugins.multiverse.inventories.commands.prompts;
+
+import org.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.bukkit.ChatColor;
+import org.bukkit.conversations.ConversationContext;
+import org.bukkit.conversations.Prompt;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+final class GroupEditPrompt extends InventoriesPrompt {
+
+ public GroupEditPrompt(final MultiverseInventories plugin, final MVCommandIssuer issuer) {
+ super(plugin, issuer);
+ }
+
+ @NotNull
+ @Override
+ public Message getPromptMessage(@NotNull final ConversationContext conversationContext) {
+ final StringBuilder builder = new StringBuilder();
+ for (WorldGroup group : worldGroupManager.getGroups()) {
+ if (builder.isEmpty()) {
+ builder.append(ChatColor.WHITE);
+ } else {
+ builder.append(ChatColor.GOLD).append(", ").append(ChatColor.WHITE);
+ }
+ builder.append(group.getName());
+ }
+ return Message.of(MVInvi18n.GROUP_EDITPROMPT, replace("{groups}").with(builder.toString()));
+ }
+
+ @Override
+ public Prompt acceptInput(@NotNull final ConversationContext conversationContext, final String input) {
+ final WorldGroup group = worldGroupManager.getGroup(input);
+ if (group == null) {
+ issuer.sendError(MVInvi18n.ERROR_NOGROUP, replace("{group}").with(input));
+ } else {
+ return new GroupModifyPrompt(plugin, issuer, group);
+ }
+ return Prompt.END_OF_CONVERSATION;
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupModifyPrompt.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupModifyPrompt.java
new file mode 100644
index 00000000..f60ec7f8
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupModifyPrompt.java
@@ -0,0 +1,41 @@
+package org.mvplugins.multiverse.inventories.commands.prompts;
+
+import org.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.bukkit.conversations.ConversationContext;
+import org.bukkit.conversations.Prompt;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+final class GroupModifyPrompt extends InventoriesPrompt {
+
+ protected final WorldGroup group;
+
+ public GroupModifyPrompt(final MultiverseInventories plugin, final MVCommandIssuer issuer,
+ final WorldGroup group) {
+ super(plugin, issuer);
+ this.group = group;
+ }
+
+ @NotNull
+ @Override
+ public Message getPromptMessage(@NotNull final ConversationContext conversationContext) {
+ return Message.of(MVInvi18n.GROUP_MODIFYPROMPT, replace("{group}").with(group.getName()));
+ }
+
+ @Override
+ public Prompt acceptInput(@NotNull final ConversationContext conversationContext, final String input) {
+ if ("worlds".equalsIgnoreCase(input)) {
+ return new GroupWorldsPrompt(plugin, issuer, group, this, false);
+ } else if (input.equalsIgnoreCase("shares")) {
+ return new GroupSharesPrompt(plugin, issuer, group, this, false);
+ } else {
+ issuer.sendError(MVInvi18n.GROUP_INVALIDOPTION);
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupSharesPrompt.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupSharesPrompt.java
new file mode 100644
index 00000000..408778ec
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupSharesPrompt.java
@@ -0,0 +1,88 @@
+package org.mvplugins.multiverse.inventories.commands.prompts;
+
+import org.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.mvplugins.multiverse.inventories.share.Sharable;
+import org.mvplugins.multiverse.inventories.share.Sharables;
+import org.mvplugins.multiverse.inventories.share.Shares;
+import org.bukkit.ChatColor;
+import org.bukkit.conversations.ConversationContext;
+import org.bukkit.conversations.Prompt;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+final class GroupSharesPrompt extends InventoriesPrompt {
+
+ protected final WorldGroup group;
+ protected final Prompt nextPrompt;
+ protected final boolean isCreating;
+ protected final Shares shares;
+
+ public GroupSharesPrompt(final MultiverseInventories plugin, final MVCommandIssuer issuer,
+ final WorldGroup group, final Prompt nextPrompt,
+ final boolean creatingGroup) {
+ super(plugin, issuer);
+ this.group = group;
+ this.nextPrompt = nextPrompt;
+ this.isCreating = creatingGroup;
+ this.shares = Sharables.fromShares(group.getShares());
+ }
+
+ @NotNull
+ @Override
+ public Message getPromptMessage(@NotNull final ConversationContext conversationContext) {
+ final StringBuilder builder = new StringBuilder();
+ for (final Sharable sharable : shares) {
+ if (builder.isEmpty()) {
+ builder.append(ChatColor.WHITE);
+ } else {
+ builder.append(ChatColor.GOLD).append(", ").append(ChatColor.WHITE);
+ }
+ builder.append(sharable.toString());
+ }
+ return Message.of(MVInvi18n.GROUP_SHARESPROMPT,
+ replace("{group}").with(group.getName()),
+ replace("{shares}").with(builder.toString()));
+ }
+
+ @Override
+ public Prompt acceptInput(@NotNull final ConversationContext conversationContext, final String input) {
+ if ("@".equals(input)) {
+ group.getShares().clear();
+ group.getShares().addAll(this.shares);
+ worldGroupManager.updateGroup(group);
+ if (isCreating) {
+ issuer.sendInfo(MVInvi18n.GROUP_CREATIONCOMPLETE, replace("{group}").with(group.getName()));
+ } else {
+ issuer.sendInfo(MVInvi18n.GROUP_UPDATED);
+ }
+ issuer.sendInfo(MVInvi18n.INFO_GROUP, replace("{group}").with(group.getName()));
+ issuer.sendInfo(MVInvi18n.INFO_GROUP_INFO, replace("{worlds}").with(group.getWorlds()));
+ issuer.sendInfo(MVInvi18n.INFO_GROUP_INFOSHARES, replace("{shares}").with(group.getShares()));
+ worldGroupManager.checkForConflicts(issuer);
+ return nextPrompt;
+ }
+
+ boolean negative = false;
+ Shares shares = Sharables.lookup(input.toLowerCase());
+ if (shares == null && input.startsWith("-") && input.length() > 1) {
+ negative = true;
+ shares = Sharables.lookup(input.toLowerCase().substring(1));
+ }
+
+ if (shares == null) {
+ issuer.sendError(MVInvi18n.ERROR_NOSHARESSPECIFIED);
+ return this;
+ }
+ if (negative) {
+ this.shares.removeAll(shares);
+ return this;
+ }
+ this.shares.addAll(shares);
+ return this;
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupWorldsPrompt.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupWorldsPrompt.java
new file mode 100644
index 00000000..0ce588c0
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupWorldsPrompt.java
@@ -0,0 +1,97 @@
+package org.mvplugins.multiverse.inventories.commands.prompts;
+
+import org.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.World;
+import org.bukkit.conversations.ConversationContext;
+import org.bukkit.conversations.Prompt;
+import org.mvplugins.multiverse.inventories.util.MVInvi18n;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
+
+final class GroupWorldsPrompt extends InventoriesPrompt {
+
+ protected final WorldGroup group;
+ protected final Prompt nextPrompt;
+ protected final boolean isCreating;
+ protected final Set worlds;
+
+ public GroupWorldsPrompt(final MultiverseInventories plugin, final MVCommandIssuer issuer,
+ final WorldGroup group, final Prompt nextPrompt,
+ final boolean creatingGroup) {
+ super(plugin, issuer);
+ this.group = group;
+ this.nextPrompt = nextPrompt;
+ this.isCreating = creatingGroup;
+ this.worlds = new HashSet(group.getWorlds());
+ }
+
+ @NotNull
+ @Override
+ public Message getPromptMessage(@NotNull final ConversationContext conversationContext) {
+ final StringBuilder builder = new StringBuilder();
+ for (final String world : worlds) {
+ if (builder.length() == 0) {
+ builder.append(ChatColor.WHITE);
+ } else {
+ builder.append(ChatColor.GOLD).append(", ").append(ChatColor.WHITE);
+ }
+ builder.append(world);
+ }
+ return Message.of(MVInvi18n.GROUP_WORLDSPROMPT,
+ replace("{group}").with(group.getName()),
+ replace("{worlds}").with(builder.toString()));
+ }
+
+ @Override
+ public Prompt acceptInput(@NotNull final ConversationContext conversationContext, final String input) {
+ if (input.equals("@")) {
+ if (worlds.isEmpty()) {
+ issuer.sendInfo(MVInvi18n.GROUP_WORLDSEMPTY);
+ return this;
+ }
+ group.removeAllWorlds(false);
+ group.addWorlds(worlds, false);
+ if (!isCreating) {
+ worldGroupManager.updateGroup(group);
+ issuer.sendInfo(MVInvi18n.GROUP_UPDATED);
+ issuer.sendInfo(MVInvi18n.INFO_GROUP, replace("{group}").with(group.getName()));
+ issuer.sendInfo(MVInvi18n.INFO_GROUP_INFO, replace("{worlds}").with(group.getWorlds()));
+ issuer.sendInfo(MVInvi18n.INFO_GROUP_INFOSHARES, replace("{shares}").with(group.getShares()));
+ }
+ return nextPrompt;
+ }
+
+ boolean negative = false;
+ World world = Bukkit.getWorld(input);
+ if (world == null && input.startsWith("-") && input.length() > 1) {
+ negative = true;
+ world = Bukkit.getWorld(input.substring(1));
+ }
+
+ if (world == null) {
+ issuer.sendError(MVInvi18n.ERROR_NOWORLD, replace("{world}").with(input));
+ return this;
+ }
+ if (negative) {
+ if (!worlds.contains(world.getName())) {
+ issuer.sendError(MVInvi18n.REMOVEWORLD_WORLDNOTINGROUP,
+ replace("{world}").with(input),
+ replace("{group}").with(group.getName()));
+ return this;
+ }
+ worlds.remove(world.getName());
+ return this;
+ }
+ worlds.add(world.getName());
+ return this;
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/InventoriesPrompt.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/InventoriesPrompt.java
new file mode 100644
index 00000000..1a85eb3f
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/InventoriesPrompt.java
@@ -0,0 +1,40 @@
+package org.mvplugins.multiverse.inventories.commands.prompts;
+
+import org.bukkit.ChatColor;
+import org.jetbrains.annotations.NotNull;
+import org.mvplugins.multiverse.core.command.MVCommandIssuer;
+import org.mvplugins.multiverse.core.command.MVCommandManager;
+import org.mvplugins.multiverse.core.locale.PluginLocales;
+import org.mvplugins.multiverse.core.locale.message.Message;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.bukkit.conversations.ConversationContext;
+import org.bukkit.conversations.Prompt;
+import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
+
+abstract class InventoriesPrompt implements Prompt {
+
+ protected final MultiverseInventories plugin;
+ protected final PluginLocales locales;
+ protected final WorldGroupManager worldGroupManager;
+ protected final MVCommandIssuer issuer;
+
+ InventoriesPrompt(final MultiverseInventories plugin, final MVCommandIssuer issuer) {
+ this.plugin = plugin;
+ this.locales = plugin.getServiceLocator().getService(MVCommandManager.class).getLocales();
+ this.issuer = issuer;
+ this.worldGroupManager = this.plugin.getServiceLocator().getService(WorldGroupManager.class);
+ }
+
+ abstract Message getPromptMessage(@NotNull ConversationContext conversationContext);
+
+ @NotNull
+ @Override
+ public String getPromptText(@NotNull ConversationContext context) {
+ return ChatColor.translateAlternateColorCodes('&', getPromptMessage(context).formatted(locales, issuer));
+ }
+
+ @Override
+ public boolean blocksForInput(@NotNull final ConversationContext conversationContext) {
+ return true;
+ }
+}
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/package-info.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/package-info.java
new file mode 100644
index 00000000..474860af
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/package-info.java
@@ -0,0 +1 @@
+package org.mvplugins.multiverse.inventories.commands.prompts;
\ No newline at end of file
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfig.java b/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfig.java
new file mode 100644
index 00000000..7694c636
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfig.java
@@ -0,0 +1,283 @@
+package org.mvplugins.multiverse.inventories.config;
+
+import com.dumptruckman.minecraft.util.Logging;
+import org.jvnet.hk2.annotations.Service;
+import org.mvplugins.multiverse.core.config.handle.CommentedConfigurationHandle;
+import org.mvplugins.multiverse.core.config.handle.StringPropertyHandle;
+import org.mvplugins.multiverse.core.config.migration.ConfigMigrator;
+import org.mvplugins.multiverse.core.config.migration.action.MoveMigratorAction;
+import org.mvplugins.multiverse.core.config.migration.VersionMigrator;
+import org.mvplugins.multiverse.external.jakarta.inject.Inject;
+import org.mvplugins.multiverse.external.vavr.control.Try;
+import org.mvplugins.multiverse.inventories.MultiverseInventories;
+import org.mvplugins.multiverse.inventories.share.Sharable;
+import org.mvplugins.multiverse.inventories.share.Shares;
+import org.bukkit.configuration.file.FileConfiguration;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+
+/**
+ * Provides methods for interacting with the configuration of Multiverse-Inventories.
+ */
+@Service
+public final class InventoriesConfig {
+
+ public static final String CONFIG_FILENAME = "config.yml";
+
+ private final InventoriesConfigNodes configNodes;
+ private final CommentedConfigurationHandle configHandle;
+ private final StringPropertyHandle stringPropertyHandle;
+
+ @Inject
+ InventoriesConfig(MultiverseInventories inventories) throws IOException {
+ this.configNodes = new InventoriesConfigNodes();
+ var configPath = Path.of(inventories.getDataFolder().getPath(), CONFIG_FILENAME);
+ this.configHandle = CommentedConfigurationHandle.builder(configPath, this.configNodes.getNodes())
+ .logger(Logging.getLogger())
+ .migrator(ConfigMigrator.builder(this.configNodes.version)
+ .addVersionMigrator(VersionMigrator.builder(5.0)
+ .addAction(MoveMigratorAction.of("settings.first_run", "first-run"))
+ .addAction(MoveMigratorAction.of("settings.use_bypass", "share-handling.enable-bypass-permissions"))
+ .addAction(MoveMigratorAction.of("settings.default_ungrouped_worlds", "share-handling.default-ungrouped-worlds"))
+ .addAction(MoveMigratorAction.of("settings.save_load_on_log_in_out", "performance.apply-playerdata-on-join"))
+ .addAction(MoveMigratorAction.of("settings.use_game_mode_profiles", "share-handling.enable-gamemode-share-handling"))
+ .addAction(MoveMigratorAction.of("shares.optionals_for_ungrouped_worlds", "share-handling.use-optionals-for-ungrouped-worlds"))
+ .addAction(MoveMigratorAction.of("shares.use_optionals", "share-handling.active-optional-shares"))
+ .build())
+ .build())
+ .build();
+ this.stringPropertyHandle = new StringPropertyHandle(this.configHandle);
+ }
+
+ public Try load() {
+ return this.configHandle.load();
+ }
+
+ public FileConfiguration getConfig() {
+ return this.configHandle.getConfig();
+ }
+
+ public StringPropertyHandle getStringPropertyHandle() {
+ return stringPropertyHandle;
+ }
+
+ /**
+ * @return True if we should check for bypass permissions.
+ */
+ public boolean getEnableBypassPermissions() {
+ return this.configHandle.get(configNodes.enableBypassPermissions);
+ }
+
+ /**
+ * @param useBypass Whether or not to check for bypass permissions.
+ */
+ public Try setEnableBypassPermissions(boolean useBypass) {
+ return this.configHandle.set(configNodes.enableBypassPermissions, useBypass);
+ }
+
+ /**
+ * @return True if using separate data for game modes.
+ */
+ public boolean getEnableGamemodeShareHandling() {
+ return this.configHandle.get(configNodes.enableGamemodeShareHandling);
+ }
+
+ /**
+ * @param useGameModeProfile whether to use separate data for game modes.
+ */
+ public Try setEnableGamemodeShareHandling(boolean useGameModeProfile) {
+ return this.configHandle.set(configNodes.enableGamemodeShareHandling, useGameModeProfile);
+ }
+
+ /**
+ * @return true if worlds with no group should be considered part of the default group.
+ */
+ public boolean getDefaultUngroupedWorlds() {
+ return this.configHandle.get(configNodes.defaultUngroupedWorlds);
+ }
+
+ /**
+ * @param useDefaultGroup Set this to true to use the default group for ungrouped worlds.
+ */
+ public Try setDefaultUngroupedWorlds(boolean useDefaultGroup) {
+ return this.configHandle.set(configNodes.defaultUngroupedWorlds, useDefaultGroup);
+ }
+
+ /**
+ * Whether Multiverse-Inventories will utilize optional shares in worlds that are not grouped.
+ *
+ * @return true if should utilize optional shares in worlds that are not grouped.
+ */
+ public boolean getUseOptionalsForUngroupedWorlds() {
+ return this.configHandle.get(configNodes.useOptionalsForUngroupedWorlds);
+ }
+
+ /**
+ * Sets whether Multiverse-Inventories will utilize optional shares in worlds that are not grouped.
+ *
+ * @param usingOptionalsForUngrouped true if should utilize optional shares in worlds that are not grouped.
+ */
+ public Try setUseOptionalsForUngroupedWorlds(final boolean usingOptionalsForUngrouped) {
+ return this.configHandle.set(configNodes.useOptionalsForUngroupedWorlds, usingOptionalsForUngrouped);
+ }
+
+ /**
+ * @return A list of optional {@link Sharable}s to be treated as
+ * regular {@link Sharable}s throughout the code.
+ * A {@link Sharable} marked as optional is ignored if it is not
+ * contained in this list.
+ */
+ public Shares getActiveOptionalShares() {
+ return this.configHandle.get(configNodes.activeOptionalShares);
+ }
+
+ /**
+ * Sets the optional shares to be used.
+ *
+ * @param shares The optional shares to be used.
+ * @return True if successful.
+ */
+ public Try setActiveOptionalShares(Shares shares) {
+ return this.configHandle.set(configNodes.activeOptionalShares, shares);
+ }
+
+ public boolean getUseImprovedRespawnLocationDetection() {
+ return this.configHandle.get(configNodes.useImprovedRespawnLocationDetection);
+ }
+
+ public Try setUseImprovedRespawnLocationDetection(boolean useImprovedRespawnLocationDetection) {
+ return this.configHandle.set(configNodes.useImprovedRespawnLocationDetection, useImprovedRespawnLocationDetection);
+ }
+
+ public boolean getResetLastLocationOnDeath() {
+ return this.configHandle.get(configNodes.resetLastLocationOnDeath);
+ }
+
+ public Try setResetLastLocationOnDeath(boolean resetLastLocationOnDeath) {
+ return this.configHandle.set(configNodes.resetLastLocationOnDeath, resetLastLocationOnDeath);
+ }
+
+ public boolean getApplyLastLocationForAllTeleports() {
+ return this.configHandle.get(configNodes.applyLastLocationForAllTeleports);
+ }
+
+ public Try setApplyLastLocationForAllTeleports(boolean applyLastLocationForAllTeleports) {
+ return this.configHandle.set(configNodes.applyLastLocationForAllTeleports, applyLastLocationForAllTeleports);
+ }
+
+ public boolean getUseByteSerializationForInventoryData() {
+ return this.configHandle.get(configNodes.useByteSerializationForInventoryData);
+ }
+
+ public Try setUseByteSerializationForInventoryData(boolean useByteSerializationForInventoryData) {
+ return this.configHandle.set(configNodes.useByteSerializationForInventoryData, useByteSerializationForInventoryData);
+ }
+
+ public boolean getApplyPlayerdataOnJoin() {
+ return this.configHandle.get(configNodes.applyPlayerdataOnJoin);
+ }
+
+ public Try setApplyPlayerdataOnJoin(boolean applyPlayerdataOnJoin) {
+ return this.configHandle.set(configNodes.applyPlayerdataOnJoin, applyPlayerdataOnJoin);
+ }
+
+ public boolean getAlwaysWriteWorldProfile() {
+ return this.configHandle.get(configNodes.alwaysWriteWorldProfile);
+ }
+
+ public Try setAlwaysWriteWorldProfile(boolean alwaysWriteWorldProfile) {
+ return this.configHandle.set(configNodes.alwaysWriteWorldProfile, alwaysWriteWorldProfile);
+ }
+
+ public List getPreloadDataOnJoinWorlds() {
+ return this.configHandle.get(configNodes.preloadDataOnJoinWorlds);
+ }
+
+ public Try setPreloadDataOnJoinWorlds(List preloadDataOnJoinWorlds) {
+ return this.configHandle.set(configNodes.preloadDataOnJoinWorlds, preloadDataOnJoinWorlds);
+ }
+
+ public List getPreloadDataOnJoinGroups() {
+ return this.configHandle.get(configNodes.preloadDataOnJoinGroups);
+ }
+
+ public Try setPreloadDataOnJoinGroups(List preloadDataOnJoinGroups) {
+ return this.configHandle.set(configNodes.preloadDataOnJoinGroups, preloadDataOnJoinGroups);
+ }
+
+ public int getPlayerFileCacheSize() {
+ return this.configHandle.get(configNodes.playerFileCacheSize);
+ }
+
+ public Try setPlayerFileCacheSize(int playerFileCacheSize) {
+ return this.configHandle.set(configNodes.playerFileCacheSize, playerFileCacheSize);
+ }
+
+ public int getPlayerFileCacheExpiry() {
+ return this.configHandle.get(configNodes.playerFileCacheExpiry);
+ }
+
+ public Try setPlayerFileCacheExpiry(int playerFileCacheExpiry) {
+ return this.configHandle.set(configNodes.playerFileCacheExpiry, playerFileCacheExpiry);
+ }
+
+ public int getPlayerProfileCacheSize() {
+ return this.configHandle.get(configNodes.playerProfileCacheSize);
+ }
+
+ public Try setPlayerProfileCacheSize(int playerProfileCacheSize) {
+ return this.configHandle.set(configNodes.playerProfileCacheSize, playerProfileCacheSize);
+ }
+
+ public int getPlayerProfileCacheExpiry() {
+ return this.configHandle.get(configNodes.playerProfileCacheExpiry);
+ }
+
+ public Try setPlayerProfileCacheExpiry(int playerProfileCacheExpiry) {
+ return this.configHandle.set(configNodes.playerProfileCacheExpiry, playerProfileCacheExpiry);
+ }
+
+ public int getGlobalProfileCacheSize() {
+ return this.configHandle.get(configNodes.globalProfileCacheSize);
+ }
+
+ public Try setGlobalProfileCacheSize(int globalProfileCacheSize) {
+ return this.configHandle.set(configNodes.globalProfileCacheSize, globalProfileCacheSize);
+ }
+
+ public int getGlobalProfileCacheExpiry() {
+ return this.configHandle.get(configNodes.globalProfileCacheExpiry);
+ }
+
+ public Try setGlobalProfileCacheExpiry(int globalProfileCacheExpiry) {
+ return this.configHandle.set(configNodes.globalProfileCacheExpiry, globalProfileCacheExpiry);
+ }
+
+ /**
+ * Tells whether this is the first time the plugin has run as set by a config flag.
+ *
+ * @return True if first_run is set to true in config.
+ */
+ public boolean getFirstRun() {
+ return this.configHandle.get(configNodes.firstRun);
+ }
+
+ /**
+ * Sets the first_run flag in the config so that the plugin no longer thinks it is the first run.
+ *
+ * @param firstRun What to set the flag to in the config.
+ */
+ public Try setFirstRun(boolean firstRun) {
+ return this.configHandle.set(configNodes.firstRun, firstRun);
+ }
+
+ /**
+ * Saves the configuration file to disk.
+ */
+ public Try save() {
+ return this.configHandle.save();
+ }
+}
+
diff --git a/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfigNodes.java b/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfigNodes.java
new file mode 100644
index 00000000..bbf6af36
--- /dev/null
+++ b/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfigNodes.java
@@ -0,0 +1,239 @@
+package org.mvplugins.multiverse.inventories.config;
+
+import org.mvplugins.multiverse.core.config.node.ConfigHeaderNode;
+import org.mvplugins.multiverse.core.config.node.ConfigNode;
+import org.mvplugins.multiverse.core.config.node.ListConfigNode;
+import org.mvplugins.multiverse.core.config.node.Node;
+import org.mvplugins.multiverse.core.config.node.NodeGroup;
+import org.mvplugins.multiverse.core.config.node.serializer.NodeSerializer;
+import org.mvplugins.multiverse.inventories.share.Sharables;
+import org.mvplugins.multiverse.inventories.share.Shares;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+final class InventoriesConfigNodes {
+
+ private final NodeGroup nodes = new NodeGroup();
+
+ InventoriesConfigNodes() {
+ }
+
+ NodeGroup getNodes() {
+ return nodes;
+ }
+
+ private