From 566956fc544507e4c30ac378d08b24f031cad8f1 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 30 Jun 2024 14:56:31 -0700 Subject: [PATCH 1/9] Version 2.4.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6efe8b389..da107d0bd 100644 --- a/pom.xml +++ b/pom.xml @@ -88,7 +88,7 @@ -LOCAL - 2.4.0 + 2.4.1 bentobox-world https://sonarcloud.io ${project.basedir}/lib From 0ffa213fd2b3d4ca46cd4ca1957cc91c86fecd48 Mon Sep 17 00:00:00 2001 From: tastybento Date: Mon, 1 Jul 2024 08:46:17 -0700 Subject: [PATCH 2/9] Adds more island cache methods. Adds tests. --- .../bentobox/managers/island/IslandCache.java | 21 ++- .../bentobox/managers/island/IslandGrid.java | 3 + .../managers/island/IslandCacheTest.java | 151 +++++++++++++++++- 3 files changed, 172 insertions(+), 3 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java b/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java index acfdabc8f..f5edc3c8f 100644 --- a/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java +++ b/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java @@ -445,7 +445,7 @@ public class IslandCache { } /** - * Get the island by unique id + * Get the island by unique id. The Island will be cached if it is not already. * * @param uniqueId unique id of the Island. * @return island or null if none found @@ -479,6 +479,16 @@ public class IslandCache { return island; } + /** + * Removes the island from the cache to ensure it is reloaded from the database next time. + * @param uniqueId unique id of the Island. + * @return true if the island was in the cache, false otherwise. + * @since 2.4.1 + */ + public boolean expireIslandById(@NonNull String uniqueId) { + return islandsById.containsKey(uniqueId) && islandsById.put(uniqueId, null) != null; + } + /** * Place the island into the cache map * @param island island @@ -540,4 +550,13 @@ public class IslandCache { return this.islandsById.containsKey(uniqueId); } + /** + * Returns if this island is cached. + * @param uniqueId - unique id of island + * @return true if this island is caches, false if not, or if the island is unknown + */ + public boolean isIslandCached(String uniqueId) { + return islandsById.get(uniqueId) != null; + } + } diff --git a/src/main/java/world/bentobox/bentobox/managers/island/IslandGrid.java b/src/main/java/world/bentobox/bentobox/managers/island/IslandGrid.java index 0893a7f09..d7d7b2c43 100644 --- a/src/main/java/world/bentobox/bentobox/managers/island/IslandGrid.java +++ b/src/main/java/world/bentobox/bentobox/managers/island/IslandGrid.java @@ -1,6 +1,7 @@ package world.bentobox.bentobox.managers.island; import java.util.Map.Entry; + import java.util.TreeMap; import world.bentobox.bentobox.database.objects.Island; @@ -33,8 +34,10 @@ class IslandGrid { TreeMap zEntry = grid.get(island.getMinX()); if (zEntry.containsKey(island.getMinZ())) { if (island.getUniqueId().equals(zEntry.get(island.getMinZ()))) { + // If it is the same island then it's okay return true; } + // Island overlap, report error return false; } else { // Add island diff --git a/src/test/java/world/bentobox/bentobox/managers/island/IslandCacheTest.java b/src/test/java/world/bentobox/bentobox/managers/island/IslandCacheTest.java index 2a8410ec7..f99961a4f 100644 --- a/src/test/java/world/bentobox/bentobox/managers/island/IslandCacheTest.java +++ b/src/test/java/world/bentobox/bentobox/managers/island/IslandCacheTest.java @@ -140,7 +140,7 @@ public class IslandCacheTest extends AbstractCommonSetup { // database must be mocked here db = mock(Database.class); - when(db.loadObject(anyString())).thenReturn(island); + when(db.loadObject("uniqueId")).thenReturn(island); when(db.saveObjectAsync(any())).thenReturn(CompletableFuture.completedFuture(true)); // New cache @@ -346,9 +346,13 @@ public class IslandCacheTest extends AbstractCommonSetup { // Fill the cache ic.addIsland(island); ic.setIslandById(island); + assertTrue(ic.isIslandCached("uniqueId")); + // Remove it ic.deleteIslandFromCache(island); - // TODO need to verify + + // verify + assertFalse(ic.isIslandCached("uniqueId")); } /** @@ -466,4 +470,147 @@ public class IslandCacheTest extends AbstractCommonSetup { assertTrue(ic.getIslands(owner).isEmpty()); } + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#addIsland(world.bentobox.bentobox.database.objects.Island)}. + */ + @Test + public void testAddIslandIslandNullWorld() { + // Null world + when(island.getWorld()).thenReturn(null); + assertFalse(ic.addIsland(island)); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#addIsland(world.bentobox.bentobox.database.objects.Island)}. + */ + @Test + public void testAddIslandIslandNullCenter() { + // Try to add an island with a null center + when(island.getCenter()).thenReturn(null); + assertFalse(ic.addIsland(island)); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#addIsland(world.bentobox.bentobox.database.objects.Island)}. + */ + @Test + public void testAddIslandIslandDuplicate() { + assertTrue(ic.addIsland(island)); + assertTrue(ic.addIsland(island)); // Okay to add + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#addIsland(world.bentobox.bentobox.database.objects.Island, boolean)}. + */ + @Test + public void testAddIslandIslandBooleanNullWorld() { + // Null world + when(island.getWorld()).thenReturn(null); + assertFalse(ic.addIsland(island, true)); + assertFalse(ic.isIslandCached("uniqueId")); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#addIsland(world.bentobox.bentobox.database.objects.Island, boolean)}. + */ + @Test + public void testAddIslandIslandBooleanNullCenter() { + // Try to add an island with a null center + when(island.getCenter()).thenReturn(null); + assertFalse(ic.addIsland(island, true)); + assertFalse(ic.isIslandCached("uniqueId")); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#addIsland(world.bentobox.bentobox.database.objects.Island, boolean)}. + */ + @Test + public void testAddIslandIslandBooleanDuplicate() { + // Duplicate + assertTrue(ic.addIsland(island, true)); + assertTrue(ic.addIsland(island, true)); + // Overlapping + Island island2 = mock(Island.class); + when(island2.getUniqueId()).thenReturn("different"); + assertFalse(ic.addIsland(island2, true)); + } + + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#loadIsland(java.lang.String)}. + */ + @Test + public void testLoadIsland() { + assertNull(ic.loadIsland("")); + assertNotNull(ic.loadIsland("uniqueId")); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#getCachedIslands()}. + */ + @Test + public void testGetCachedIslands() { + assertTrue(ic.getCachedIslands().isEmpty()); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#getIslandById(java.lang.String)}. + */ + @Test + public void testGetIslandByIdString() { + assertNotNull(ic.getIslandById("uniqueId")); + assertTrue(ic.isIslandCached("uniqueId")); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#getIslandById(java.lang.String, boolean)}. + */ + @Test + public void testGetIslandByIdStringBoolean() { + assertNotNull(ic.getIslandById("uniqueId", false)); + assertFalse(ic.isIslandCached("uniqueId")); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#expireIslandById(java.lang.String)}. + */ + @Test + public void testExpireIslandById() { + // Fill the cache + ic.addIsland(island); + ic.setIslandById(island); + assertTrue(ic.isIslandCached("uniqueId")); + // Remove it + ic.expireIslandById("uniqueId"); + // verify + assertFalse(ic.isIslandCached("uniqueId")); + + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#setIslandById(world.bentobox.bentobox.database.objects.Island)}. + */ + @Test + public void testSetIslandById() { + assertFalse(ic.isIslandId("uniqueId")); + ic.setIslandById(island); + assertTrue(ic.isIslandId("uniqueId")); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#isIslandId(java.lang.String)}. + */ + @Test + public void testIsIslandId() { + assertFalse(ic.isIslandId("uniqueId")); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#isIslandCached(java.lang.String)}. + */ + @Test + public void testIsIslandCached() { + assertFalse(ic.isIslandCached("uniqueId")); + } + } From ff1438f3a395adac0cabb2bdf47164a459b579a1 Mon Sep 17 00:00:00 2001 From: tastybento Date: Tue, 2 Jul 2024 08:47:09 -0700 Subject: [PATCH 3/9] Add onDisable override method to Pladdon --- .../java/world/bentobox/bentobox/api/addons/Pladdon.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/world/bentobox/bentobox/api/addons/Pladdon.java b/src/main/java/world/bentobox/bentobox/api/addons/Pladdon.java index af11005db..0909c51d0 100644 --- a/src/main/java/world/bentobox/bentobox/api/addons/Pladdon.java +++ b/src/main/java/world/bentobox/bentobox/api/addons/Pladdon.java @@ -32,6 +32,14 @@ public abstract class Pladdon extends JavaPlugin { } } + @Override + public void onDisable() { + Addon addon = getAddon(); + if (addon != null) { + addon.onDisable(); + } + } + protected void moveJar() { getLogger().severe(getFile().getName() + " must be in the " + ADDONS_FOLDER + " folder! Trying to move it there..."); File addons = new File(getFile().getParent(), ADDONS_FOLDER); From 5e0d80e5147f073a28e07de596187c967bfc726f Mon Sep 17 00:00:00 2001 From: tastybento Date: Tue, 2 Jul 2024 11:35:26 -0700 Subject: [PATCH 4/9] Don't make constants that depend on Bukkit --- src/main/java/world/bentobox/bentobox/util/Util.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/util/Util.java b/src/main/java/world/bentobox/bentobox/util/Util.java index 7679b3bcf..2ee05e934 100644 --- a/src/main/java/world/bentobox/bentobox/util/Util.java +++ b/src/main/java/world/bentobox/bentobox/util/Util.java @@ -63,11 +63,6 @@ public class Util { private static PasteHandler pasteHandler = null; private static WorldRegenerator regenerator = null; - // Bukkit method that was added in 2011 - // Example value: 1.20.4-R0.1-SNAPSHOT - private static final String bukkitVersion = "v" + Bukkit.getBukkitVersion().replace('.', '_').replace('-', '_'); - private static final String pluginPackageName = plugin.getClass().getPackage().getName(); - private Util() {} /** @@ -721,6 +716,10 @@ public class Util { */ public static WorldRegenerator getRegenerator() { if (regenerator == null) { + // Bukkit method that was added in 2011 + // Example value: 1.20.4-R0.1-SNAPSHOT + final String bukkitVersion = "v" + Bukkit.getBukkitVersion().replace('.', '_').replace('-', '_'); + final String pluginPackageName = plugin.getClass().getPackage().getName(); WorldRegenerator handler; try { Class clazz = Class.forName(pluginPackageName + ".nms." + bukkitVersion + ".WorldRegeneratorImpl"); From 6bb148ec7616c86f35fa39d0e285f385b01f1dc7 Mon Sep 17 00:00:00 2001 From: TreemanK Date: Wed, 3 Jul 2024 13:06:47 +1000 Subject: [PATCH 5/9] fix: typo --- src/main/java/world/bentobox/bentobox/lists/Flags.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/world/bentobox/bentobox/lists/Flags.java b/src/main/java/world/bentobox/bentobox/lists/Flags.java index 33d4bbf16..d0f5c75b5 100644 --- a/src/main/java/world/bentobox/bentobox/lists/Flags.java +++ b/src/main/java/world/bentobox/bentobox/lists/Flags.java @@ -283,7 +283,7 @@ public final class Flags { public static final Flag HURT_ANIMALS = new Flag.Builder("HURT_ANIMALS", Material.STONE_SWORD).listener(new HurtingListener()).mode(Flag.Mode.ADVANCED).build(); public static final Flag HURT_MONSTERS = new Flag.Builder("HURT_MONSTERS", Material.WOODEN_SWORD).mode(Flag.Mode.BASIC).build(); public static final Flag HURT_VILLAGERS = new Flag.Builder("HURT_VILLAGERS", Material.GOLDEN_SWORD).mode(Flag.Mode.ADVANCED).build(); - public static final Flag HURT_TAMED_ANIMALS = new Flag.Builder("HURT_TAMABLE_ENTITIES", Material.DIAMOND_SWORD).mode(Flag.Mode.ADVANCED).build(); + public static final Flag HURT_TAMED_ANIMALS = new Flag.Builder("HURT_TAMED_ANIMALS", Material.DIAMOND_SWORD).mode(Flag.Mode.ADVANCED).build(); // Leashes public static final Flag LEASH = new Flag.Builder("LEASH", Material.LEAD).listener(new LeashListener()).build(); From 755452cd3c76597fb9fd2fa8da6f4b61c6d5f853 Mon Sep 17 00:00:00 2001 From: tastybento Date: Wed, 3 Jul 2024 15:43:17 -0700 Subject: [PATCH 6/9] Added support for serializing Pairs --- .../json/BentoboxTypeAdapterFactory.java | 4 ++ .../json/adapters/PairTypeAdapter.java | 41 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/main/java/world/bentobox/bentobox/database/json/adapters/PairTypeAdapter.java diff --git a/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java b/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java index a8faa19e1..9f90a4793 100644 --- a/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java +++ b/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java @@ -25,9 +25,11 @@ import world.bentobox.bentobox.database.json.adapters.FlagTypeAdapter; import world.bentobox.bentobox.database.json.adapters.ItemStackTypeAdapter; import world.bentobox.bentobox.database.json.adapters.LocationTypeAdapter; import world.bentobox.bentobox.database.json.adapters.MaterialTypeAdapter; +import world.bentobox.bentobox.database.json.adapters.PairTypeAdapter; import world.bentobox.bentobox.database.json.adapters.PotionEffectTypeAdapter; import world.bentobox.bentobox.database.json.adapters.VectorTypeAdapter; import world.bentobox.bentobox.database.json.adapters.WorldTypeAdapter; +import world.bentobox.bentobox.util.Pair; /** @@ -74,6 +76,8 @@ public class BentoboxTypeAdapterFactory implements TypeAdapterFactory { return (TypeAdapter) new WorldTypeAdapter(); } else if (Vector.class.isAssignableFrom(rawType)) { return (TypeAdapter) new VectorTypeAdapter(); + } else if (Pair.class.isAssignableFrom(rawType)) { + return (TypeAdapter) new PairTypeAdapter<>(); } else if (ConfigurationSerializable.class.isAssignableFrom(rawType)) { // This covers a lot of Bukkit objects return (TypeAdapter) new BukkitObjectTypeAdapter(gson.getAdapter(Map.class)); diff --git a/src/main/java/world/bentobox/bentobox/database/json/adapters/PairTypeAdapter.java b/src/main/java/world/bentobox/bentobox/database/json/adapters/PairTypeAdapter.java new file mode 100644 index 000000000..20d0fe7cb --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/database/json/adapters/PairTypeAdapter.java @@ -0,0 +1,41 @@ +package world.bentobox.bentobox.database.json.adapters; + +import java.io.IOException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import world.bentobox.bentobox.util.Pair; + +// Custom TypeAdapter for Pair +public class PairTypeAdapter extends TypeAdapter> { + + @Override + public void write(JsonWriter out, Pair pair) throws IOException { + if (pair == null || pair.getKey() == null || pair.getValue() == null) { + return; + } + out.beginArray(); + out.value(new Gson().toJson(pair.getKey())); + out.value(new Gson().toJson(pair.getValue())); + out.endArray(); + } + + @Override + public Pair read(JsonReader in) throws IOException { + in.beginArray(); + Type typeX = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + X x = new Gson().fromJson(in.nextString(), typeX); + Type typeZ = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]; + Z z = new Gson().fromJson(in.nextString(), typeZ); + in.endArray(); + if (x == null || z == null) { + return null; + } + return new Pair<>(x, z); + } +} \ No newline at end of file From f4604b4c270e83a2620fc733188127ace7959001 Mon Sep 17 00:00:00 2001 From: tastybento Date: Wed, 3 Jul 2024 16:39:43 -0700 Subject: [PATCH 7/9] Fix to make it work --- .../json/BentoboxTypeAdapterFactory.java | 9 +++- .../json/adapters/PairTypeAdapter.java | 45 +++++++++++-------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java b/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java index 9f90a4793..e7aca2f8b 100644 --- a/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java +++ b/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java @@ -1,5 +1,7 @@ package world.bentobox.bentobox.database.json; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.Map; import org.bukkit.Location; @@ -77,7 +79,12 @@ public class BentoboxTypeAdapterFactory implements TypeAdapterFactory { } else if (Vector.class.isAssignableFrom(rawType)) { return (TypeAdapter) new VectorTypeAdapter(); } else if (Pair.class.isAssignableFrom(rawType)) { - return (TypeAdapter) new PairTypeAdapter<>(); + // Add Pair handling here with type safety + Type pairType = type.getType(); + ParameterizedType parameterizedType = (ParameterizedType) pairType; + Type xType = parameterizedType.getActualTypeArguments()[0]; + Type zType = parameterizedType.getActualTypeArguments()[1]; + return (TypeAdapter) new PairTypeAdapter<>(xType, zType); } else if (ConfigurationSerializable.class.isAssignableFrom(rawType)) { // This covers a lot of Bukkit objects return (TypeAdapter) new BukkitObjectTypeAdapter(gson.getAdapter(Map.class)); diff --git a/src/main/java/world/bentobox/bentobox/database/json/adapters/PairTypeAdapter.java b/src/main/java/world/bentobox/bentobox/database/json/adapters/PairTypeAdapter.java index 20d0fe7cb..ae36aa815 100644 --- a/src/main/java/world/bentobox/bentobox/database/json/adapters/PairTypeAdapter.java +++ b/src/main/java/world/bentobox/bentobox/database/json/adapters/PairTypeAdapter.java @@ -1,7 +1,6 @@ package world.bentobox.bentobox.database.json.adapters; import java.io.IOException; -import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import com.google.gson.Gson; @@ -11,31 +10,41 @@ import com.google.gson.stream.JsonWriter; import world.bentobox.bentobox.util.Pair; -// Custom TypeAdapter for Pair public class PairTypeAdapter extends TypeAdapter> { + private final Type xType; + private final Type zType; + + public PairTypeAdapter(Type xType, Type zType) { + this.xType = xType; + this.zType = zType; + } @Override public void write(JsonWriter out, Pair pair) throws IOException { - if (pair == null || pair.getKey() == null || pair.getValue() == null) { - return; - } - out.beginArray(); - out.value(new Gson().toJson(pair.getKey())); - out.value(new Gson().toJson(pair.getValue())); - out.endArray(); + out.beginObject(); + out.name("x"); + Gson gson = new Gson(); + gson.toJson(pair.getKey(), xType, out); + out.name("z"); + gson.toJson(pair.getValue(), zType, out); + out.endObject(); } @Override public Pair read(JsonReader in) throws IOException { - in.beginArray(); - Type typeX = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; - X x = new Gson().fromJson(in.nextString(), typeX); - Type typeZ = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]; - Z z = new Gson().fromJson(in.nextString(), typeZ); - in.endArray(); - if (x == null || z == null) { - return null; + X x = null; + Z z = null; + + in.beginObject(); + while (in.hasNext()) { + String name = in.nextName(); + if (name.equals("x")) { + x = new Gson().fromJson(in, xType); + } else if (name.equals("z")) { + z = new Gson().fromJson(in, zType); + } } + in.endObject(); return new Pair<>(x, z); } -} \ No newline at end of file +} From cb2d0e7efdd9aa1258b5f218ce63d763f65eacd0 Mon Sep 17 00:00:00 2001 From: tastybento Date: Fri, 5 Jul 2024 10:19:21 -0700 Subject: [PATCH 8/9] Add cache for name lookup --- .../bentobox/managers/PlayersManager.java | 14 +++- .../bentobox/managers/PlayersManagerTest.java | 64 +++++++++++++++++-- 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/managers/PlayersManager.java b/src/main/java/world/bentobox/bentobox/managers/PlayersManager.java index 957f1a37c..47c27bea9 100644 --- a/src/main/java/world/bentobox/bentobox/managers/PlayersManager.java +++ b/src/main/java/world/bentobox/bentobox/managers/PlayersManager.java @@ -3,6 +3,7 @@ package world.bentobox.bentobox.managers; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -30,7 +31,7 @@ public class PlayersManager { private Database handler; private final Database names; private final Map playerCache = new ConcurrentHashMap<>(); - + private final @NonNull List nameCache; private final Set inTeleport; // this needs databasing /** @@ -46,6 +47,7 @@ public class PlayersManager { handler = new Database<>(plugin, Players.class); // Set up the names database names = new Database<>(plugin, Names.class); + nameCache = names.loadObjects(); inTeleport = new HashSet<>(); } @@ -139,7 +141,7 @@ public class PlayersManager { // Not used } } - return names.loadObjects().stream().filter(n -> n.getUniqueId().equalsIgnoreCase(name)).findFirst() + return nameCache.stream().filter(n -> n.getUniqueId().equalsIgnoreCase(name)).findFirst() .map(Names::getUuid).orElse(null); } @@ -148,10 +150,18 @@ public class PlayersManager { * @param user - the User */ public void setPlayerName(@NonNull User user) { + // Ignore any bots + if (user.getUniqueId() == null) { + return; + } Players player = getPlayer(user.getUniqueId()); player.setPlayerName(user.getName()); handler.saveObject(player); + // Update names Names newName = new Names(user.getName(), user.getUniqueId()); + // Add to cache + nameCache.removeIf(name -> user.getUniqueId().equals(name.getUuid())); + nameCache.add(newName); // Add to names database names.saveObjectAsync(newName); } diff --git a/src/test/java/world/bentobox/bentobox/managers/PlayersManagerTest.java b/src/test/java/world/bentobox/bentobox/managers/PlayersManagerTest.java index 2313e9488..00d19a6c5 100644 --- a/src/test/java/world/bentobox/bentobox/managers/PlayersManagerTest.java +++ b/src/test/java/world/bentobox/bentobox/managers/PlayersManagerTest.java @@ -9,6 +9,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -71,7 +72,7 @@ import world.bentobox.bentobox.util.Util; * */ @RunWith(PowerMockRunner.class) -@PrepareForTest({ Bukkit.class, BentoBox.class, User.class, Util.class, Logger.class, DatabaseSetup.class, }) +@PrepareForTest({ Bukkit.class, BentoBox.class, User.class, Util.class, Logger.class, DatabaseSetup.class }) public class PlayersManagerTest { private static AbstractDatabaseHandler handler; @@ -685,12 +686,65 @@ public class PlayersManagerTest { } /** - * Test method for - * {@link world.bentobox.bentobox.managers.PlayersManager#shutdown()}. + * Test method for {@link world.bentobox.bentobox.managers.PlayersManager#getPlayer(java.util.UUID)}. */ @Test - public void testShutdown() { - pm.shutdown(); // Clears cache + public void testGetPlayer() { + Players p = pm.getPlayer(uuid); + assertNotNull(p); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.PlayersManager#loadPlayer(java.util.UUID)}. + */ + @Test + public void testLoadPlayer() { + assertNotNull(pm.loadPlayer(uuid)); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.PlayersManager#getName(java.util.UUID)}. + */ + @Test + public void testGetName() { + assertEquals("", pm.getName(uuid)); + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.PlayersManager#cleanLeavingPlayer(org.bukkit.World, world.bentobox.bentobox.api.user.User, boolean, world.bentobox.bentobox.database.objects.Island)}. + */ + @Test + public void testCleanLeavingPlayer() { + when(user.isOnline()).thenReturn(true); + when(iwm.isOnLeaveResetEnderChest(world)).thenReturn(true); + when(iwm.isOnLeaveResetInventory(world)).thenReturn(true); + when(iwm.isOnLeaveResetMoney(world)).thenReturn(true); + pm.cleanLeavingPlayer(world, user, false, island); + PowerMockito.verifyStatic(Util.class); + Util.runCommands(user, "", plugin.getIWM().getOnLeaveCommands(world), "leave"); + verify(world).getEntitiesByClass(Tameable.class); + verify(inv).clear(); // Enderchest cleared + verify(plugin).getVault(); // Clear money + PowerMockito.verifyStatic(Util.class); + Util.resetHealth(p); + verify(p).setFoodLevel(20); + verify(p).setLevel(0); + verify(p).setExp(0); + // Player total XP (not displayed) + verify(p).setTotalExperience(0); + + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.PlayersManager#savePlayer(java.util.UUID)}. + * @throws IntrospectionException + * @throws InvocationTargetException + * @throws IllegalAccessException + */ + @Test + public void testSavePlayer() throws IllegalAccessException, InvocationTargetException, IntrospectionException { + pm.savePlayer(uuid); + verify(handler, atLeastOnce()).saveObject(any()); } } From a8f01f746e885747f49737ed2e6a2e4cdf787141 Mon Sep 17 00:00:00 2001 From: tastybento Date: Fri, 5 Jul 2024 10:19:37 -0700 Subject: [PATCH 9/9] Add a UUID Fetcher class in Utils - not used right now --- .../bentobox/bentobox/util/UUIDFetcher.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/main/java/world/bentobox/bentobox/util/UUIDFetcher.java diff --git a/src/main/java/world/bentobox/bentobox/util/UUIDFetcher.java b/src/main/java/world/bentobox/bentobox/util/UUIDFetcher.java new file mode 100644 index 000000000..7f49695ee --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/util/UUIDFetcher.java @@ -0,0 +1,65 @@ +package world.bentobox.bentobox.util; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URI; +import java.util.UUID; + +import org.eclipse.jdt.annotation.Nullable; +import org.jetbrains.annotations.NotNull; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +/** + * Fetches UUID for a player name from the Internet + * @since 1.24.1 + */ +public class UUIDFetcher { + private static final String API_URL = "https://playerdb.co/api/player/minecraft/%s"; + + @Nullable + public static UUID getUUID(@NotNull String name) { + name = name.toLowerCase(); // Had some issues with upper-case letters in the username, so I added this to make sure that doesn't happen. + + try { + HttpURLConnection connection = (HttpURLConnection) URI.create(String.format(API_URL, name)).toURL() + .openConnection(); + + connection.setUseCaches(false); + connection.setDefaultUseCaches(false); + connection.addRequestProperty("User-Agent", "Mozilla/5.0"); + connection.addRequestProperty("Cache-Control", "no-cache, no-store, must-revalidate"); + connection.addRequestProperty("Pragma", "no-cache"); + connection.setReadTimeout(5000); + + // These connection parameters need to be set or the API won't accept the connection. + + try (BufferedReader bufferedReader = new BufferedReader( + new InputStreamReader(connection.getInputStream()))) { + StringBuilder response = new StringBuilder(); + String line; + + while ((line = bufferedReader.readLine()) != null) + response.append(line); + + final JsonElement parsed = JsonParser.parseString(response.toString()); + + if (parsed == null || !parsed.isJsonObject()) { + return null; + } + + JsonObject data = parsed.getAsJsonObject(); // Read the returned JSON data. + + return UUID.fromString(data.get("data").getAsJsonObject().get("player").getAsJsonObject().get("id") // Grab the UUID. + .getAsString()); + } + } catch (Exception ignored) { + // Ignoring exception since this is usually caused by non-existent usernames. + } + + return null; + } +} \ No newline at end of file