diff --git a/pom.xml b/pom.xml
index 93352f6c5..c26752ede 100644
--- a/pom.xml
+++ b/pom.xml
@@ -287,10 +287,6 @@
bukkit
org.bukkit
-
- commons-io
- commons-io
-
diff --git a/src/main/java/org/maxgamer/quickshop/File/FileEnvelope.java b/src/main/java/org/maxgamer/quickshop/File/FileEnvelope.java
index 0960ffc1f..7697c828f 100644
--- a/src/main/java/org/maxgamer/quickshop/File/FileEnvelope.java
+++ b/src/main/java/org/maxgamer/quickshop/File/FileEnvelope.java
@@ -1,15 +1,24 @@
package org.maxgamer.quickshop.File;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.maxgamer.quickshop.Mock.MckFileConfiguration;
import org.maxgamer.quickshop.Util.Copied;
+import org.maxgamer.quickshop.Util.Location.LocationOf;
+import org.maxgamer.quickshop.Util.Location.StringOf;
+import org.maxgamer.quickshop.Util.Util;
import java.io.File;
import java.io.InputStream;
+import java.util.List;
import java.util.Objects;
+import java.util.Optional;
public abstract class FileEnvelope implements IFile {
@@ -79,7 +88,7 @@ public abstract class FileEnvelope implements IFile {
fileConfiguration.save(file);
} catch (Exception exception) {
- throw new RuntimeException(exception);
+ throw new IllegalStateException(exception);
}
}
@@ -89,9 +98,140 @@ public abstract class FileEnvelope implements IFile {
return fileConfiguration.get(path);
}
+ @NotNull
+ @Override
+ public Object get(@NotNull String path, @NotNull Object fallback) {
+ final Object object = fileConfiguration.get(path, fallback);
+
+ if (object == null) {
+ return fallback;
+ }
+
+ return object;
+ }
+
+ @NotNull
+ @Override
+ @SuppressWarnings("unchecked")
+ public T getOrSet(@NotNull String path, @NotNull T fallback) {
+ final T object = (T) fileConfiguration.get(path, null);
+
+ if (object != null) {
+ return object;
+ }
+
+ set(path, fallback);
+
+ return fallback;
+ }
+
+ @NotNull
+ @Override
+ public Location getLocation(@NotNull String path) {
+ return new LocationOf(
+ getString(path).orElse("")
+ ).value();
+ }
+
+ @Override
+ public void setLocation(@NotNull String path, @NotNull Location location) {
+ set(
+ path,
+ new StringOf(location).asString()
+ );
+ }
+
+ @NotNull
+ @Override
+ public ItemStack getCustomItemStack(@NotNull String path) {
+ try {
+ return Util.deserialize(path);
+ } catch (Exception exception) {
+ return new ItemStack(Material.AIR);
+ }
+ }
+
+ @Override
+ public void setCustomItemStack(@NotNull String path, @NotNull ItemStack itemStack) {
+ fileConfiguration.set(path, Util.serialize(itemStack));
+ }
+
+ @NotNull
+ @Override
+ public Optional getString(@NotNull String path) {
+ return Optional.ofNullable(fileConfiguration.getString(path));
+ }
+
@Override
public void set(@NotNull String path, @NotNull Object object) {
fileConfiguration.set(path, object);
+ save();
+ }
+
+ @NotNull
+ @Override
+ public List getStringList(@NotNull String path) {
+ return fileConfiguration.getStringList(path);
+ }
+
+ @Override
+ public int getInt(@NotNull String path) {
+ return fileConfiguration.getInt(path);
+ }
+
+ @Override
+ public double getDouble(@NotNull String path) {
+ return fileConfiguration.getDouble(path);
+ }
+
+ @Override
+ public long getLong(@NotNull String path) {
+ return fileConfiguration.getLong(path);
+ }
+
+ @Override
+ public byte getByte(@NotNull String path) {
+ return (byte) fileConfiguration.getInt(path);
+ }
+
+ @Override
+ public short getShort(@NotNull String path) {
+ return (short) fileConfiguration.getInt(path);
+ }
+
+ @Override
+ public boolean getBoolean(@NotNull String path) {
+ return fileConfiguration.getBoolean(path);
+ }
+
+ @NotNull
+ @Override
+ public ConfigurationSection createSection(@NotNull String path) {
+ final ConfigurationSection configurationSection = fileConfiguration.createSection(path);
+
+ save();
+
+ return configurationSection;
+ }
+
+ @NotNull
+ @Override
+ public ConfigurationSection getSection(@NotNull String path) {
+ final ConfigurationSection configurationSection = fileConfiguration.getConfigurationSection(path);
+
+ return configurationSection == null ? new MckFileConfiguration() : configurationSection;
+ }
+
+ @NotNull
+ @Override
+ public ConfigurationSection getOrCreateSection(@NotNull String path) {
+ ConfigurationSection section = getSection(path);
+
+ if (section instanceof MckFileConfiguration) {
+ section = createSection(path);
+ }
+
+ return section;
}
}
diff --git a/src/main/java/org/maxgamer/quickshop/File/IFile.java b/src/main/java/org/maxgamer/quickshop/File/IFile.java
index e30ee6a08..b2e429952 100644
--- a/src/main/java/org/maxgamer/quickshop/File/IFile.java
+++ b/src/main/java/org/maxgamer/quickshop/File/IFile.java
@@ -1,24 +1,211 @@
package org.maxgamer.quickshop.File;
+import org.bukkit.Location;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.InputStream;
+import java.util.List;
+import java.util.Optional;
public interface IFile {
+ /**
+ * Creates yml file on the path
+ */
void create();
@NotNull
InputStream getInputStream();
+ /**
+ * Reloads file
+ */
void reload();
+ /**
+ * Saves file
+ */
void save();
+ /**
+ * Gets the object
+ *
+ * @param path object path to get
+ * @return if path does not exist returns null
+ */
@Nullable
Object get(@NotNull String path);
- void set(@NotNull String path, @NotNull Object object);
+ /**
+ * Gets the object with fallback
+ *
+ * @param path object path to get
+ * @param fallback fallback object to get if path does not exist
+ * @return if path does not exist returns fallback object else the path object
+ */
+ @NotNull
+ Object get(@NotNull String path, @NotNull Object fallback);
+
+ /**
+ * Gets or sets the object
+ *
+ * @param path object path to get
+ * @param fallback fallback object to get if path does not exist
+ * @param object type
+ * @return if path does not exist returns and set the path with fallback object
+ */
+ @NotNull
+ T getOrSet(@NotNull final String path, @NotNull T fallback);
+
+ /**
+ * Gets location
+ *
+ * @param path location path to get
+ * @return {@link Location}
+ */
+ @NotNull
+ Location getLocation(@NotNull final String path);
+
+ /**
+ * Sets location into the path
+ *
+ * @param path location path to set
+ * @param location {@link Location}
+ */
+ void setLocation(@NotNull final String path, @NotNull final Location location);
+
+ /**
+ * Pattern:
+ *
+ * path:
+ * (material): 'DIAMOND'
+ * [amount]: 1
+ * [data]: 0
+ * [display-name]: 'Diamond Sword'
+ * [enchants]:
+ * DAMAGE_ALL: 10
+ * FIRE_ASPECT: 2
+ * [lore]:
+ * - 'Lore 1'
+ * - 'Lore 2'
+ *
+ * @param path itemstack path to get
+ * @return {@link ItemStack}
+ */
+ @NotNull
+ ItemStack getCustomItemStack(@NotNull final String path);
+
+ /**
+ * Sets custom itemstack to path
+ *
+ * @param path itemstack path to set
+ * @param itemStack {@link ItemStack}
+ */
+ void setCustomItemStack(@NotNull final String path, @NotNull final ItemStack itemStack);
+
+ /**
+ * Gets string
+ *
+ * @param path string path to get
+ * @return {@link String}
+ */
+ @NotNull
+ Optional getString(@NotNull final String path);
+
+ /**
+ * Sets object to path
+ *
+ * @param path object path to set
+ * @param object {@link Object}
+ */
+ void set(@NotNull final String path, @NotNull final Object object);
+
+ /**
+ * Gets string list
+ *
+ * @param path string list path to get
+ * @return string list
+ */
+ @NotNull
+ List getStringList(@NotNull final String path);
+
+ /**
+ * Gets int
+ *
+ * @param path integer path to get
+ * @return {@link Integer}
+ */
+ int getInt(@NotNull final String path);
+
+ /**
+ * Gets double
+ *
+ * @param path double path to get
+ * @return {@link Double}
+ */
+ double getDouble(@NotNull final String path);
+
+ /**
+ * Gets long
+ *
+ * @param path long path to get
+ * @return {@link Integer}
+ */
+ long getLong(@NotNull String path);
+
+ /**
+ * Gets byte
+ *
+ * @param path byte path to get
+ * @return {@link Byte}
+ */
+ byte getByte(@NotNull final String path);
+
+ /**
+ * Gets short
+ *
+ * @param path short path to get
+ * @return {@link Short}
+ */
+ short getShort(@NotNull String path);
+
+ /**
+ * Gets boolean
+ *
+ * @param path boolean path to get
+ * @return {@link Boolean}
+ */
+ boolean getBoolean(@NotNull final String path);
+
+ /**
+ * Creates configuration section into path
+ *
+ * @param path configuration section path to create
+ * @return {@link ConfigurationSection}
+ */
+ @NotNull
+ ConfigurationSection createSection(@NotNull String path);
+
+ /**
+ * Gets configuration section from path
+ *
+ * @param path configurations section path to get
+ * @return if there isn't section returns {@link MckFileConfiguration}
+ */
+ @NotNull
+ ConfigurationSection getSection(@NotNull final String path);
+
+ /**
+ * Gets configuration section from path
+ * if there is no section It will create
+ *
+ * @param path configurations section path to get
+ * @return {@link ConfigurationSection}
+ */
+ @NotNull
+ ConfigurationSection getOrCreateSection(@NotNull final String path);
}
diff --git a/src/main/java/org/maxgamer/quickshop/Util/Location/LocationOf.java b/src/main/java/org/maxgamer/quickshop/Util/Location/LocationOf.java
new file mode 100644
index 000000000..a36158683
--- /dev/null
+++ b/src/main/java/org/maxgamer/quickshop/Util/Location/LocationOf.java
@@ -0,0 +1,39 @@
+package org.maxgamer.quickshop.Util.Location;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public final class LocationOf {
+
+ @NotNull
+ private static final Pattern PATTERN =
+ Pattern.compile("((?[^:/]+)[:/])?(?[\\-0-9.]+),(?[\\-0-9.]+),(?[\\-0-9.]+)(:(?[\\-0-9.]+):(?[\\-0-9.]+))?");
+
+ @NotNull
+ private final String text;
+
+ public LocationOf(@NotNull String text) {
+ this.text = text;
+ }
+
+ @NotNull
+ public Location value() {
+ final Matcher match = PATTERN.matcher(text.replaceAll("_", "\\."));
+
+ if (match.matches())
+ return new Location(
+ Bukkit.getWorld(match.group("world")),
+ Double.parseDouble(match.group("x")),
+ Double.parseDouble(match.group("y")),
+ Double.parseDouble(match.group("z")),
+ match.group("yaw") != null ? Float.parseFloat(match.group("yaw")) : 0F,
+ match.group("pitch") != null ? Float.parseFloat(match.group("pitch")) : 0F
+ );
+
+ throw new IllegalStateException("Location string has wrong style!");
+ }
+}
diff --git a/src/main/java/org/maxgamer/quickshop/Util/Location/StringOf.java b/src/main/java/org/maxgamer/quickshop/Util/Location/StringOf.java
new file mode 100644
index 000000000..8800a1b07
--- /dev/null
+++ b/src/main/java/org/maxgamer/quickshop/Util/Location/StringOf.java
@@ -0,0 +1,51 @@
+package org.maxgamer.quickshop.Util.Location;
+
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Locale;
+
+public final class StringOf {
+
+ @NotNull
+ private final Location location;
+
+ @NotNull
+ private final World world;
+
+ public StringOf(@NotNull Location location) {
+ if (location.getWorld() == null) {
+ throw new IllegalStateException("World of the location cannot be null!");
+ }
+
+ this.location = location;
+ this.world = location.getWorld();
+ }
+
+ @NotNull
+ public String asString() {
+ String s = world.getName() + ":";
+
+ s += String.format(
+ Locale.ENGLISH,
+ "%.2f,%.2f,%.2f",
+ location.getX(), location.getY(), location.getZ()
+ );
+
+ if (location.getYaw() != 0f || location.getPitch() != 0f) {
+ s += String.format(
+ Locale.ENGLISH,
+ ":%.2f:%.2f",
+ location.getYaw(), location.getPitch()
+ );
+ }
+ return s;
+ }
+
+ @NotNull
+ public String asKey() {
+ return asString().replaceAll(":", "/").replaceAll("\\.", "_");
+ }
+
+}
diff --git a/src/main/java/org/maxgamer/quickshop/Util/Util.java b/src/main/java/org/maxgamer/quickshop/Util/Util.java
index 61a39ade0..983936bc4 100644
--- a/src/main/java/org/maxgamer/quickshop/Util/Util.java
+++ b/src/main/java/org/maxgamer/quickshop/Util/Util.java
@@ -990,6 +990,20 @@ public class Util {
return text;
}
+ /**
+ * Parse colors for the List.
+ *
+ * @param list the list
+ * @return parsed list
+ */
+ public static List parseColours(@NotNull List list) {
+ final List newList = new ArrayList<>();
+
+ list.forEach(s -> newList.add(parseColours(s)));
+
+ return newList;
+ }
+
/**
* Converts a name like IRON_INGOT into Iron Ingot to improve readability
*
diff --git a/src/test/java/org/maxgamer/quickshop/File/FileEnvelopeTest.java b/src/test/java/org/maxgamer/quickshop/File/FileEnvelopeTest.java
new file mode 100644
index 000000000..bc321e6ca
--- /dev/null
+++ b/src/test/java/org/maxgamer/quickshop/File/FileEnvelopeTest.java
@@ -0,0 +1,257 @@
+package org.maxgamer.quickshop.File;
+
+import be.seeseemelk.mockbukkit.MockBukkit;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.inventory.ItemStack;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.maxgamer.quickshop.Mock.MckFileConfiguration;
+import org.maxgamer.quickshop.QuickShopTest;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class FileEnvelopeTest {
+
+ private final List test = new ArrayList<>();
+ private QuickShopTest plugin;
+ private IFile json;
+ private IFile yaml;
+
+ @BeforeEach
+ void start() {
+ MockBukkit.mock();
+ plugin = MockBukkit.load(QuickShopTest.class);
+ json = new JSONFile(plugin, "messages");
+ json.create();
+ yaml = new YAMLFile(plugin, "messages");
+ yaml.create();
+ test.add("test");
+ json.set("test.list", test);
+ yaml.set("test.list", test);
+ json.set("test.int", 13);
+ yaml.set("test.int", 13);
+ json.set("test.boolean", true);
+ yaml.set("test.boolean", true);
+ json.set("test.short", (short) 1);
+ yaml.set("test.short", (short) 1);
+ json.set("test.long", (long) 1);
+ yaml.set("test.long", (long) 1);
+ json.set("test.byte", (byte) 1);
+ yaml.set("test.byte", (byte) 1);
+ json.set("test.double", (double) 1);
+ yaml.set("test.double", (double) 1);
+ }
+
+ @Test
+ void get() {
+ assertEquals(
+ "{0}",
+ json.get("signs.item")
+ );
+ assertEquals(
+ "{0}",
+ yaml.get("signs.item")
+ );
+ }
+
+ @Test
+ void getString() {
+ final Optional optionalS = json.getString("shop-staff-cleared");
+ final Optional optionalSS = yaml.getString("shop-staff-cleared");
+
+ if (!optionalS.isPresent() || !optionalSS.isPresent()) {
+ throw new IllegalArgumentException("There no path called 'shop-staff-cleared'");
+ }
+
+ assertEquals(
+ "&aSuccessfully removed all staff for your shop.",
+ optionalS.get()
+ );
+ assertEquals(
+ "&aSuccessfully removed all staff for your shop.",
+ optionalSS.get()
+ );
+ }
+
+ @Test
+ void set() {
+ json.set("test.test", "test");
+ yaml.set("test.test", "test");
+ assertEquals(
+ "{0}",
+ json.get("signs.item")
+ );
+ assertEquals(
+ "{0}",
+ yaml.get("signs.item")
+ );
+ }
+
+ @Test
+ void create() {
+ json.create();
+ yaml.create();
+ }
+
+ @Test
+ void save() {
+ json.save();
+ yaml.save();
+ }
+
+ @Test
+ void getWithFallback() {
+ assertEquals(
+ "&aSuccessfully removed all staff for your shop.",
+ json.get("shop-staff-cleared", "test")
+ );
+ assertEquals(
+ "&aSuccessfully removed all staff for your shop.",
+ yaml.get("shop-staff-cleared", "test")
+ );
+ }
+
+ @Test
+ void getOrSet() {
+ assertEquals(
+ "test",
+ json.getOrSet("test.test123", "test")
+ );
+ assertEquals(
+ "test",
+ yaml.getOrSet("test.test123", "test")
+ );
+ assertEquals(
+ "test",
+ json.getOrSet("test.test123", "test")
+ );
+ assertEquals(
+ "test",
+ yaml.getOrSet("test.test123", "test")
+ );
+ }
+
+ @Test
+ void getStringList() {
+ assertEquals(
+ test,
+ json.getStringList("test.list")
+ );
+ assertEquals(
+ test,
+ yaml.getStringList("test.list")
+ );
+ }
+
+ @Test
+ void getInt() {
+ assertEquals(
+ 13,
+ json.getInt("test.int")
+ );
+ assertEquals(
+ 13,
+ yaml.getInt("test.int")
+ );
+ }
+
+ @Test
+ void getDouble() {
+ assertEquals(
+ 1,
+ json.getDouble("test.short")
+ );
+ assertEquals(
+ 1,
+ yaml.getDouble("test.short")
+ );
+ }
+
+ @Test
+ void getLong() {
+ assertEquals(
+ 1,
+ json.getLong("test.short")
+ );
+ assertEquals(
+ 1,
+ yaml.getLong("test.short")
+ );
+ }
+
+ @Test
+ void getByte() {
+ assertEquals(
+ (byte) 1,
+ json.getByte("test.short")
+ );
+ assertEquals(
+ (byte) 1,
+ yaml.getByte("test.short")
+ );
+ }
+
+ @Test
+ void getShort() {
+ assertEquals(
+ (short) 1,
+ json.getShort("test.short")
+ );
+ assertEquals(
+ (short) 1,
+ yaml.getShort("test.short")
+ );
+ }
+
+ @Test
+ void getBoolean() {
+ assertTrue(
+ json.getBoolean("test.boolean")
+ );
+ assertTrue(
+ yaml.getBoolean("test.boolean")
+ );
+ }
+
+ @Test
+ void createSection() {
+ json.createSection("test.section");
+ yaml.createSection("test.section");
+ }
+
+ @Test
+ void getSection() {
+ assertTrue(
+ () -> !(json.getSection("test.section") instanceof MckFileConfiguration)
+ );
+ assertTrue(
+ () -> !(yaml.getSection("test.section") instanceof MckFileConfiguration)
+ );
+ }
+
+ @Test
+ void getOrCreateSection() {
+ assertTrue(
+ () -> !(json.getOrCreateSection("test.section") instanceof MckFileConfiguration)
+ );
+ assertTrue(
+ () -> !(yaml.getOrCreateSection("test.section") instanceof MckFileConfiguration)
+ );
+ }
+
+ @AfterEach
+ void stop() {
+ json.save();
+ yaml.save();
+ MockBukkit.unload();
+ }
+
+}
diff --git a/src/test/java/org/maxgamer/quickshop/File/JSONFileTest.java b/src/test/java/org/maxgamer/quickshop/File/JSONFileTest.java
deleted file mode 100644
index 9f2fba7b2..000000000
--- a/src/test/java/org/maxgamer/quickshop/File/JSONFileTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.maxgamer.quickshop.File;
-
-import be.seeseemelk.mockbukkit.MockBukkit;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.maxgamer.quickshop.QuickShopTest;
-import static org.junit.jupiter.api.Assertions.*;
-
-final class JSONFileTest {
-
- private QuickShopTest plugin;
- private IFile json;
-
- @BeforeEach
- void start() {
- MockBukkit.mock();
- plugin = MockBukkit.load(QuickShopTest.class);
- json = new JSONFile(plugin, "messages");
- json.create();
- }
-
- @Test
- void get() {
- assertEquals(
- json.get("signs.item"),
- "{0}"
- );
- }
-
- @Test
- void set() {
- json.set("test.test", "test");
- assertEquals(
- json.get("signs.item"),
- "{0}"
- );
- }
-
- @AfterEach
- void stop() {
- json.save();
- MockBukkit.unload();
- }
-
-}
\ No newline at end of file
diff --git a/src/test/java/org/maxgamer/quickshop/File/YAMLFileTest.java b/src/test/java/org/maxgamer/quickshop/File/YAMLFileTest.java
deleted file mode 100644
index 0e8770cde..000000000
--- a/src/test/java/org/maxgamer/quickshop/File/YAMLFileTest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.maxgamer.quickshop.File;
-
-import be.seeseemelk.mockbukkit.MockBukkit;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.maxgamer.quickshop.QuickShopTest;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-final class YAMLFileTest {
-
- private QuickShopTest plugin;
- private IFile yaml;
-
- @BeforeEach
- void start() {
- MockBukkit.mock();
- plugin = MockBukkit.load(QuickShopTest.class);
- yaml = new YAMLFile(plugin, "messages");
-
- yaml.create();
- }
-
- @Test
- void get() {
- assertEquals(
- yaml.get("signs.item"),
- "{0}"
- );
- }
-
- @Test
- void set() {
- yaml.set("test.test", "test");
- assertEquals(
- yaml.get("test.test"),
- "test"
- );
- }
-
- @AfterEach
- void stop() {
- yaml.save();
- MockBukkit.unload();
- }
-
-}
\ No newline at end of file