diff --git a/.gitignore b/.gitignore index fda2f4a052..f025c1e196 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /.settings/ /.idea/ /.vscode/ +/data-store/ dependency-reduced-pom.xml diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/GPSNetwork.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/GPSNetwork.java index d2d9a3c1ee..47574fb2ca 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/GPSNetwork.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/GPSNetwork.java @@ -331,7 +331,7 @@ public void addWaypoint(@Nonnull Player p, @Nonnull String name, @Nonnull Locati } } - profile.addWaypoint(new Waypoint(profile, id, event.getLocation(), event.getName())); + profile.addWaypoint(new Waypoint(p.getUniqueId(), id, event.getLocation(), event.getName())); SoundEffect.GPS_NETWORK_ADD_WAYPOINT.playFor(p); Slimefun.getLocalization().sendMessage(p, "gps.waypoint.added", true); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/Waypoint.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/Waypoint.java index 13c8b42561..0cf37b9ed4 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/Waypoint.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/Waypoint.java @@ -1,11 +1,13 @@ package io.github.thebusybiscuit.slimefun4.api.gps; import java.util.Objects; +import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World.Environment; import org.bukkit.entity.Player; @@ -30,7 +32,7 @@ */ public class Waypoint { - private final PlayerProfile profile; + private final UUID uuid; private final String id; private final String name; private final Location location; @@ -48,26 +50,40 @@ public class Waypoint { * The name of this {@link Waypoint} */ @ParametersAreNonnullByDefault - public Waypoint(PlayerProfile profile, String id, Location loc, String name) { - Validate.notNull(profile, "Profile must never be null!"); + public Waypoint(UUID uuid, String id, Location loc, String name) { + Validate.notNull(uuid, "UUID must never be null!"); Validate.notNull(id, "id must never be null!"); Validate.notNull(loc, "Location must never be null!"); Validate.notNull(name, "Name must never be null!"); - this.profile = profile; + this.uuid = uuid; this.id = id; this.location = loc; this.name = name; } /** - * This returns the owner of the {@link Waypoint}. + * This returns the owner {@link UUID} of the {@link Waypoint}. * + * @return The corresponding owner {@link UUID} + */ + @Nonnull + public UUID getUuid() { + return this.uuid; + } + + /** + * This returns the owner of the {@link Waypoint}. + * * @return The corresponding {@link PlayerProfile} + * + * @deprecated Use {@link #getUuid()} instead */ @Nonnull + @Deprecated public PlayerProfile getOwner() { - return profile; + // This is jank and should never actually return null + return PlayerProfile.find(Bukkit.getOfflinePlayer(uuid)).orElse(null); } /** @@ -126,7 +142,7 @@ public ItemStack getIcon() { */ @Override public int hashCode() { - return Objects.hash(profile.getUUID(), id, name, location); + return Objects.hash(this.uuid, this.id, this.name, this.location); } /** @@ -139,7 +155,9 @@ public boolean equals(Object obj) { } Waypoint waypoint = (Waypoint) obj; - return profile.getUUID().equals(waypoint.getOwner().getUUID()) && id.equals(waypoint.getId()) && location.equals(waypoint.getLocation()) && name.equals(waypoint.getName()); + return this.uuid.equals(waypoint.getUuid()) + && id.equals(waypoint.getId()) + && location.equals(waypoint.getLocation()) + && name.equals(waypoint.getName()); } - } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java index ce62d21046..02ca4b0a2b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java @@ -1,6 +1,5 @@ package io.github.thebusybiscuit.slimefun4.api.player; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -11,8 +10,6 @@ import java.util.Set; import java.util.UUID; import java.util.function.Consumer; -import java.util.logging.Level; -import java.util.stream.Collectors; import java.util.stream.IntStream; import javax.annotation.Nonnull; @@ -22,7 +19,6 @@ import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; @@ -30,6 +26,7 @@ import org.bukkit.inventory.ItemStack; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import io.github.bakedlibs.dough.common.ChatColors; import io.github.bakedlibs.dough.common.CommonPatterns; @@ -68,7 +65,6 @@ public class PlayerProfile { private boolean dirty = false; private boolean markedForDeletion = false; - private final List waypoints = new ArrayList<>(); private final Map backpacks = new HashMap<>(); private final GuideHistory guideHistory = new GuideHistory(this); @@ -83,22 +79,6 @@ protected PlayerProfile(@Nonnull OfflinePlayer p, PlayerData data) { configFile = new Config("data-storage/Slimefun/Players/" + uuid.toString() + ".yml"); waypointsFile = new Config("data-storage/Slimefun/waypoints/" + uuid.toString() + ".yml"); - - loadProfileData(); - } - - private void loadProfileData() { - for (String key : waypointsFile.getKeys()) { - try { - if (waypointsFile.contains(key + ".world") && Bukkit.getWorld(waypointsFile.getString(key + ".world")) != null) { - String waypointName = waypointsFile.getString(key + ".name"); - Location loc = waypointsFile.getLocation(key); - waypoints.add(new Waypoint(this, key, loc, waypointName)); - } - } catch (Exception x) { - Slimefun.logger().log(Level.WARNING, x, () -> "Could not load Waypoint \"" + key + "\" for Player \"" + name + '"'); - } - } } /** @@ -176,9 +156,9 @@ public void setResearched(@Nonnull Research research, boolean unlock) { dirty = true; if (unlock) { - data.getResearches().add(research.getKey()); + data.addResearch(research); } else { - data.getResearches().remove(research.getKey()); + data.removeResearch(research); } } @@ -196,7 +176,7 @@ public boolean hasUnlocked(@Nullable Research research) { return true; } - return !research.isEnabled() || data.getResearches().contains(research.getKey()); + return !research.isEnabled() || data.getResearches().contains(research); } /** @@ -222,10 +202,7 @@ public boolean hasUnlockedEverything() { * @return A {@code Hashset} of all Researches this {@link Player} has unlocked */ public @Nonnull Set getResearches() { - return Slimefun.getRegistry().getResearches() - .stream() - .filter((research) -> data.getResearches().contains(research.getKey())) - .collect(Collectors.toUnmodifiableSet()); + return ImmutableSet.copyOf(this.data.getResearches()); } /** @@ -235,7 +212,7 @@ public boolean hasUnlockedEverything() { * @return A {@link List} containing every {@link Waypoint} */ public @Nonnull List getWaypoints() { - return ImmutableList.copyOf(waypoints); + return ImmutableList.copyOf(this.data.getWaypoints()); } /** @@ -246,21 +223,7 @@ public boolean hasUnlockedEverything() { * The {@link Waypoint} to add */ public void addWaypoint(@Nonnull Waypoint waypoint) { - Validate.notNull(waypoint, "Cannot add a 'null' waypoint!"); - - for (Waypoint wp : waypoints) { - if (wp.getId().equals(waypoint.getId())) { - throw new IllegalArgumentException("A Waypoint with that id already exists for this Player"); - } - } - - if (waypoints.size() < 21) { - waypoints.add(waypoint); - - waypointsFile.setValue(waypoint.getId(), waypoint.getLocation()); - waypointsFile.setValue(waypoint.getId() + ".name", waypoint.getName()); - markDirty(); - } + this.data.addWaypoint(waypoint); } /** @@ -271,12 +234,7 @@ public void addWaypoint(@Nonnull Waypoint waypoint) { * The {@link Waypoint} to remove */ public void removeWaypoint(@Nonnull Waypoint waypoint) { - Validate.notNull(waypoint, "Cannot remove a 'null' waypoint!"); - - if (waypoints.remove(waypoint)) { - waypointsFile.setValue(waypoint.getId(), null); - markDirty(); - } + this.data.removeWaypoint(waypoint); } /** diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/storage/backend/legacy/LegacyStorage.java b/src/main/java/io/github/thebusybiscuit/slimefun4/storage/backend/legacy/LegacyStorage.java index 21afa54a42..beb65dacd1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/storage/backend/legacy/LegacyStorage.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/storage/backend/legacy/LegacyStorage.java @@ -1,10 +1,14 @@ package io.github.thebusybiscuit.slimefun4.storage.backend.legacy; import io.github.bakedlibs.dough.config.Config; +import io.github.thebusybiscuit.slimefun4.api.gps.Waypoint; import io.github.thebusybiscuit.slimefun4.api.researches.Research; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.storage.Storage; import io.github.thebusybiscuit.slimefun4.storage.data.PlayerData; + +import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.NamespacedKey; import com.google.common.annotations.Beta; @@ -14,6 +18,7 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; +import java.util.logging.Level; @Beta public class LegacyStorage implements Storage { @@ -22,36 +27,57 @@ public class LegacyStorage implements Storage { public PlayerData loadPlayerData(@Nonnull UUID uuid) { Config playerFile = new Config("data-storage/Slimefun/Players/" + uuid + ".yml"); // Not too sure why this is it's own file - Config waypointFile = new Config("data-storage/Slimefun/waypoints/" + uuid + ".yml"); - - Set researches = new HashSet<>(); + Config waypointsFile = new Config("data-storage/Slimefun/waypoints/" + uuid + ".yml"); + // Load research + Set researches = new HashSet<>(); for (Research research : Slimefun.getRegistry().getResearches()) { if (playerFile.contains("researches." + research.getID())) { - researches.add(research.getKey()); + researches.add(research); + } + } + + // Load waypoints + Set waypoints = new HashSet<>(); + for (String key : waypointsFile.getKeys()) { + try { + if (waypointsFile.contains(key + ".world") && Bukkit.getWorld(waypointsFile.getString(key + ".world")) != null) { + String waypointName = waypointsFile.getString(key + ".name"); + Location loc = waypointsFile.getLocation(key); + waypoints.add(new Waypoint(uuid, key, loc, waypointName)); + } + } catch (Exception x) { + Slimefun.logger().log(Level.WARNING, x, () -> "Could not load Waypoint \"" + key + "\" for Player \"" + uuid + '"'); } } // TODO: // * Backpacks - // * Waypoints? - return new PlayerData(researches); + return new PlayerData(researches, waypoints); } @Override public void savePlayerData(@Nonnull UUID uuid, @Nonnull PlayerData data) { - Config file = new Config("data-storage/Slimefun/Players/" + uuid + ".yml"); + Config playerFile = new Config("data-storage/Slimefun/Players/" + uuid + ".yml"); + // Not too sure why this is it's own file + Config waypointsFile = new Config("data-storage/Slimefun/waypoints/" + uuid + ".yml"); - for (NamespacedKey key : data.getResearches()) { - // Legacy data uses IDs, we'll look these up - Optional research = Slimefun.getRegistry().getResearches().stream() - .filter((rs) -> key == rs.getKey()) - .findFirst(); + // Save research + for (Research research : data.getResearches()) { + // Legacy data uses IDs + playerFile.setValue("researches." + research.getID(), true); + } - research.ifPresent(value -> file.setValue("researches." + value.getID(), true)); + // Save waypoints + for (Waypoint waypoint : data.getWaypoints()) { + // Legacy data uses IDs + waypointsFile.setValue(waypoint.getId(), waypoint.getLocation()); + waypointsFile.setValue(waypoint.getId() + ".name", waypoint.getName()); } - file.save(); + // Save files + playerFile.save(); + waypointsFile.save(); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/storage/data/PlayerData.java b/src/main/java/io/github/thebusybiscuit/slimefun4/storage/data/PlayerData.java index e7ab51dd42..b07bf7e395 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/storage/data/PlayerData.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/storage/data/PlayerData.java @@ -1,26 +1,70 @@ package io.github.thebusybiscuit.slimefun4.storage.data; import com.google.common.annotations.Beta; -import org.bukkit.NamespacedKey; + +import io.github.thebusybiscuit.slimefun4.api.gps.Waypoint; +import io.github.thebusybiscuit.slimefun4.api.researches.Research; import java.util.HashSet; import java.util.Set; +import javax.annotation.Nonnull; + +import org.apache.commons.lang.Validate; + /** * The data which backs {@link io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile} * * This API is still experimental, it may change without notice. */ +// TODO: Should we keep this in PlayerProfile? @Beta public class PlayerData { - private final Set researches = new HashSet<>(); + private final Set researches = new HashSet<>(); + private final Set waypoints = new HashSet<>(); - public PlayerData(Set researches) { + public PlayerData(Set researches, Set waypoints) { this.researches.addAll(researches); } - public Set getResearches() { + public Set getResearches() { return researches; } + + public void addResearch(@Nonnull Research research) { + Validate.notNull(research, "Cannot add a 'null' research!"); + researches.add(research); + } + + public void removeResearch(@Nonnull Research research) { + Validate.notNull(research, "Cannot remove a 'null' research!"); + researches.remove(research); + } + + public Set getWaypoints() { + return waypoints; + } + + public void addWaypoint(@Nonnull Waypoint waypoint) { + Validate.notNull(waypoint, "Cannot add a 'null' waypoint!"); + + for (Waypoint wp : waypoints) { + if (wp.getId().equals(waypoint.getId())) { + throw new IllegalArgumentException("A Waypoint with that id already exists for this Player"); + } + } + + // TODO: Figure out why we limit this to 21, it's a weird number + if (waypoints.size() >= 21) { + return; // Also, not sure why this doesn't throw but the one above does... + } + + waypoints.add(waypoint); + } + + public void removeWaypoint(@Nonnull Waypoint waypoint) { + Validate.notNull(waypoint, "Cannot remove a 'null' waypoint!"); + waypoints.remove(waypoint); + } } diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/api/gps/TestWaypoints.java b/src/test/java/io/github/thebusybiscuit/slimefun4/api/gps/TestWaypoints.java index d115135ba7..a0de64b14f 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/api/gps/TestWaypoints.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/api/gps/TestWaypoints.java @@ -1,5 +1,9 @@ package io.github.thebusybiscuit.slimefun4.api.gps; +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; import org.bukkit.entity.Player; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; @@ -19,16 +23,20 @@ class TestWaypoints { private static ServerMock server; private static Slimefun plugin; + private static File dataFolder; @BeforeAll public static void load() { server = MockBukkit.mock(); plugin = MockBukkit.load(Slimefun.class); + dataFolder = new File("data-storage/Slimefun/waypoints"); + dataFolder.mkdirs(); } @AfterAll - public static void unload() { + public static void unload() throws IOException { MockBukkit.unmock(); + FileUtils.deleteDirectory(dataFolder); } @Test @@ -38,9 +46,8 @@ void testAddWaypointToProfile() throws InterruptedException { PlayerProfile profile = TestUtilities.awaitProfile(player); Assertions.assertTrue(profile.getWaypoints().isEmpty()); - Waypoint waypoint = new Waypoint(profile, "hello", player.getLocation(), "HELLO"); + Waypoint waypoint = new Waypoint(player.getUniqueId(), "hello", player.getLocation(), "HELLO"); profile.addWaypoint(waypoint); - Assertions.assertTrue(profile.isDirty()); Assertions.assertThrows(IllegalArgumentException.class, () -> profile.addWaypoint(null)); @@ -55,7 +62,7 @@ void testRemoveWaypointFromProfile() throws InterruptedException { Player player = server.addPlayer(); PlayerProfile profile = TestUtilities.awaitProfile(player); - Waypoint waypoint = new Waypoint(profile, "hello", player.getLocation(), "HELLO"); + Waypoint waypoint = new Waypoint(player.getUniqueId(), "hello", player.getLocation(), "HELLO"); profile.addWaypoint(waypoint); Assertions.assertEquals(1, profile.getWaypoints().size()); @@ -76,7 +83,7 @@ void testWaypointAlreadyExisting() throws InterruptedException { Player player = server.addPlayer(); PlayerProfile profile = TestUtilities.awaitProfile(player); - Waypoint waypoint = new Waypoint(profile, "test", player.getLocation(), "Testing"); + Waypoint waypoint = new Waypoint(player.getUniqueId(), "test", player.getLocation(), "Testing"); profile.addWaypoint(waypoint); Assertions.assertEquals(1, profile.getWaypoints().size()); @@ -91,7 +98,7 @@ void testTooManyWaypoints() throws InterruptedException { PlayerProfile profile = TestUtilities.awaitProfile(player); for (int i = 0; i < 99; i++) { - Waypoint waypoint = new Waypoint(profile, String.valueOf(i), player.getLocation(), "Test"); + Waypoint waypoint = new Waypoint(player.getUniqueId(), String.valueOf(i), player.getLocation(), "Test"); profile.addWaypoint(waypoint); } @@ -114,11 +121,10 @@ void testWaypointEvent() throws InterruptedException { @DisplayName("Test equal Waypoints being equal") void testWaypointComparison() throws InterruptedException { Player player = server.addPlayer(); - PlayerProfile profile = TestUtilities.awaitProfile(player); - Waypoint waypoint = new Waypoint(profile, "waypoint", player.getLocation(), "Test"); - Waypoint same = new Waypoint(profile, "waypoint", player.getLocation(), "Test"); - Waypoint different = new Waypoint(profile, "waypoint_nope", player.getLocation(), "Test2"); + Waypoint waypoint = new Waypoint(player.getUniqueId(), "waypoint", player.getLocation(), "Test"); + Waypoint same = new Waypoint(player.getUniqueId(), "waypoint", player.getLocation(), "Test"); + Waypoint different = new Waypoint(player.getUniqueId(), "waypoint_nope", player.getLocation(), "Test2"); Assertions.assertEquals(waypoint, same); Assertions.assertEquals(waypoint.hashCode(), same.hashCode()); @@ -131,10 +137,9 @@ void testWaypointComparison() throws InterruptedException { @DisplayName("Test Deathpoints being recognized as Deathpoints") void testIsDeathpoint() throws InterruptedException { Player player = server.addPlayer(); - PlayerProfile profile = TestUtilities.awaitProfile(player); - Waypoint waypoint = new Waypoint(profile, "waypoint", player.getLocation(), "Some Waypoint"); - Waypoint deathpoint = new Waypoint(profile, "deathpoint", player.getLocation(), "player:death I died"); + Waypoint waypoint = new Waypoint(player.getUniqueId(), "waypoint", player.getLocation(), "Some Waypoint"); + Waypoint deathpoint = new Waypoint(player.getUniqueId(), "deathpoint", player.getLocation(), "player:death I died"); Assertions.assertFalse(waypoint.isDeathpoint()); Assertions.assertTrue(deathpoint.isDeathpoint()); diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/storage/backend/TestLegacyBackend.java b/src/test/java/io/github/thebusybiscuit/slimefun4/storage/backend/TestLegacyBackend.java index 1e4f639de3..1cfaecd2e1 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/storage/backend/TestLegacyBackend.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/storage/backend/TestLegacyBackend.java @@ -70,7 +70,7 @@ void testLoadingBasicPlayerData() throws IOException { // Check if the data is correct Assertions.assertEquals(10, data.getResearches().size()); for (int i = 0; i < 10; i++) { - Assertions.assertTrue(data.getResearches().contains(Slimefun.getRegistry().getResearches().get(i).getKey())); + Assertions.assertTrue(data.getResearches().contains(Slimefun.getRegistry().getResearches().get(i))); } } @@ -99,7 +99,7 @@ void testSavingBasicPlayerData() throws IOException, InterruptedException, Execu PlayerData assertion = storage.loadPlayerData(uuid); Assertions.assertEquals(10, assertion.getResearches().size()); for (int i = 0; i < 10; i++) { - Assertions.assertTrue(assertion.getResearches().contains(Slimefun.getRegistry().getResearches().get(i).getKey())); + Assertions.assertTrue(assertion.getResearches().contains(Slimefun.getRegistry().getResearches().get(i))); } } diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/test/mocks/MockProfile.java b/src/test/java/io/github/thebusybiscuit/slimefun4/test/mocks/MockProfile.java index eac8483b1d..6e083e40f9 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/test/mocks/MockProfile.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/test/mocks/MockProfile.java @@ -12,7 +12,7 @@ public class MockProfile extends PlayerProfile { public MockProfile(@Nonnull OfflinePlayer p) { - this(p, new PlayerData(Set.of())); + this(p, new PlayerData(Set.of(), Set.of())); } public MockProfile(@Nonnull OfflinePlayer p, @Nonnull PlayerData data) {