1.6.3: Implement FastOfflinePlayer with Postgres integration and unit tests
- Added initial FastOfflinePlayer implementation: serialize(), deserialize(), getName(), getUniqueID(). - Populated initial FastOfflinePlayer database using jasync Postgres. - Added unit tests covering all FastOfflinePlayer functions.
This commit is contained in:
1 parent
7c5630ea7b
commit
0ba116b1ab
14 files changed
+832
-417
No files matched your search
@@ -1,3 +1,8 @@
|
||||
**1.6.3:**
|
||||
- Initial implementation of FastOfflinePlayer: serialize(), deserialize(), getName(), getUniqueID().
|
||||
- Populate initial FastOfflinePlayer database with jasync Postgres.
|
||||
- Unit testing for complete FastOfflinePlayer functions.
|
||||
|
||||
**1.6.2:**
|
||||
- Fix console logging API.
|
||||
|
||||
|
||||
+12
-4
@@ -8,9 +8,10 @@ plugins {
|
||||
id("com.gradleup.shadow") version "8.3.6" // Import Shadow plugin.
|
||||
id("checkstyle") // Import Checkstyle plugin.
|
||||
eclipse // Import Eclipse plugin.
|
||||
kotlin("jvm") version "2.1.21" // Import Kotlin JVM plugin.
|
||||
}
|
||||
|
||||
/* ------------------------------- JDK --------------------------------- */
|
||||
/* --------------------------- JDK / Kotlin ---------------------------- */
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17 // Compile with JDK 17 compatibility.
|
||||
toolchain { // Select Java toolchain.
|
||||
@@ -19,6 +20,8 @@ java {
|
||||
}
|
||||
}
|
||||
|
||||
kotlin { jvmToolchain(17) }
|
||||
|
||||
/* ----------------------------- Metadata ------------------------------ */
|
||||
group = "net.trueog.utilities-og" // Declare bundle identifier.
|
||||
|
||||
@@ -51,9 +54,14 @@ dependencies {
|
||||
compileOnly("de.tr7zw:item-nbt-api-plugin:2.11.2") // Import NBT API.
|
||||
compileOnly("io.github.miniplaceholders:miniplaceholders-api:2.2.3") // Import MiniPlaceholders API.
|
||||
compileOnly("net.luckperms:api:5.4") // Import LuckPerms API.
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.13.3") // Import JUnit 5 API.
|
||||
testImplementation("com.github.seeseemelk:MockBukkit-v1.19:2.29.0") // Import MockBukkit 1.19.
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher") // Import JUnit's engine.
|
||||
implementation(kotlin("stdlib")) // Import and package Kotlin standard library.
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") // Import and package Kotlin async library.
|
||||
implementation("com.github.jasync-sql:jasync-postgresql:2.2.4") // Import and package Jasync API.
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.13.3") // Add JUnit API to testing environment.
|
||||
testImplementation("org.mockito:mockito-core:5.18.0") // Add Mockito API to testing environment.
|
||||
testImplementation("com.github.seeseemelk:MockBukkit-v1.19:2.29.0") // Add MockBukkit API to testing environment.
|
||||
testImplementation(kotlin("stdlib")) // Add Kotlin to testing environment.
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher") // Add JUnit engine to the testing runtime.
|
||||
}
|
||||
|
||||
/* ---------------------- Reproducible jars ---------------------------- */
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
// Authors: NotAlexNoyle.
|
||||
package net.trueog.utilitiesog;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
@@ -15,21 +21,77 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import com.github.jasync.sql.db.Connection;
|
||||
|
||||
// FAST async Postgres and cache based re-implementation of Bukkit's OfflinePlayer.
|
||||
// Designed for 1.19.4, OfflinePlayer behavior may be different on other versions.
|
||||
// TODO: Add in-game integration testing.
|
||||
public class FastOfflinePlayer implements OfflinePlayer {
|
||||
|
||||
UUID uuid;
|
||||
// Container for player UUID (always available).
|
||||
private final UUID uuid;
|
||||
// Container for player username (requires lookup).
|
||||
private String cachedName;
|
||||
// Container for safe concurrent updates to async futures.
|
||||
private final AtomicReference<CompletableFuture<String>> lookup = new AtomicReference<>();
|
||||
// Fake Postgres connection without using UtilitiesOG.java.
|
||||
private static volatile Supplier<Connection> connectionSupplier;
|
||||
|
||||
// Test-only supplier hook.
|
||||
static void overrideConnectionSupplierForTests(Supplier<Connection> supplier) {
|
||||
|
||||
// Enable the test supplier.
|
||||
connectionSupplier = supplier;
|
||||
|
||||
}
|
||||
|
||||
// Supply a connection to jasync Postgres.
|
||||
private Connection connection() {
|
||||
|
||||
// If a test supplier is available, do this...
|
||||
final Supplier<Connection> s = connectionSupplier;
|
||||
if (s != null) {
|
||||
|
||||
// Return the test supplier.
|
||||
return s.get();
|
||||
|
||||
}
|
||||
|
||||
// Return the real provider.
|
||||
return UtilitiesOG.getPostgres();
|
||||
|
||||
}
|
||||
|
||||
// Runs after each individual unit test.
|
||||
static void resetConnectionSupplierForTests() {
|
||||
|
||||
// Reset the jasync Postgres connection supplier.
|
||||
connectionSupplier = null;
|
||||
|
||||
}
|
||||
|
||||
// Class constructor.
|
||||
public FastOfflinePlayer(UUID inputtedUUID) {
|
||||
|
||||
uuid = inputtedUUID;
|
||||
// Cache the provided UUID.
|
||||
this.uuid = inputtedUUID;
|
||||
|
||||
}
|
||||
|
||||
// Internal constructor for deserialization.
|
||||
private FastOfflinePlayer(@NotNull UUID uuid, @Nullable String username) {
|
||||
|
||||
// Pass the provided UUID.
|
||||
this.uuid = uuid;
|
||||
// Pass the username (will be set to 'usernameLookupError' if not found).
|
||||
this.cachedName = username;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOp() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return false;
|
||||
|
||||
}
|
||||
@@ -37,48 +99,153 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public void setOp(boolean value) {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
// Fast re-implementation of OfflinePlayer.serialize() from Bukkit API.
|
||||
@Override
|
||||
public @NotNull Map<String, Object> serialize() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
UtilitiesOG.config().set("players." + getUniqueId(), this);
|
||||
UtilitiesOG.getPlugin().saveConfig();
|
||||
return null;
|
||||
// Construct a map to hold player data.
|
||||
final Map<String, Object> map = new LinkedHashMap<>();
|
||||
|
||||
// Add the player data to the map.
|
||||
map.put("name", getName());
|
||||
|
||||
// Return the combined serialized object.
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
// Fast re-implementation of OfflinePlayer.deserialize() from Bukkit API.
|
||||
public static @NotNull FastOfflinePlayer deserialize(@NotNull UUID uuid, @NotNull Map<String, Object> values) {
|
||||
|
||||
// Extract the player name from the serialized map as a String.
|
||||
final String name = (String) values.get("name");
|
||||
|
||||
// Return the UUID from cache.
|
||||
return new FastOfflinePlayer(uuid, name);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnline() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// Fast re-implementation of OfflinePlayer.getName() from Bukkit API.
|
||||
@Override
|
||||
public @Nullable String getName() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
// If the name is already in the cache, do this...
|
||||
if (cachedName != null) {
|
||||
|
||||
// Return the name from cache instead of querying the database.
|
||||
return cachedName;
|
||||
|
||||
}
|
||||
|
||||
// Get existing lookup future if present.
|
||||
CompletableFuture<String> future = lookup.get();
|
||||
|
||||
// If there is no existing lookup future, do this...
|
||||
if (future == null) {
|
||||
|
||||
// Create new jasync Postgres query for username.
|
||||
CompletableFuture<String> created = connection()
|
||||
.sendPreparedStatement("SELECT username FROM offline_players WHERE uuid = $1 LIMIT 1;",
|
||||
Collections.singletonList(uuid))
|
||||
// On success, cache and return username.
|
||||
.thenApply(res ->
|
||||
{
|
||||
|
||||
// If the query returned rows, do this...
|
||||
if (!res.getRows().isEmpty()) {
|
||||
|
||||
// Extract the "username" value from the first row.
|
||||
final String name = res.getRows().get(0).getString("username");
|
||||
|
||||
// Store the retrieved username in the cache.
|
||||
cachedName = name;
|
||||
|
||||
// Return the retrieved username.
|
||||
return name;
|
||||
|
||||
}
|
||||
|
||||
// If no rows are found, return null.
|
||||
return null;
|
||||
|
||||
})
|
||||
|
||||
// If there was an error with finding the name, do this...
|
||||
.exceptionally(ex ->
|
||||
{
|
||||
|
||||
// Set a placeholder name to avoid a crash.
|
||||
cachedName = "usernameLookupError";
|
||||
|
||||
UtilitiesOG.logToConsole(InternalFunctions.getPrefix(),
|
||||
"ERROR: FastOfflinePlayer getName() failed!" + ex.getMessage());
|
||||
|
||||
// Return the placeholder name.
|
||||
return cachedName;
|
||||
|
||||
});
|
||||
|
||||
// Attempt to set the lookup future only if it is currently null.
|
||||
if (!lookup.compareAndSet(null, created)) {
|
||||
|
||||
// If another thread already set the future, use the existing one instead.
|
||||
created = lookup.get();
|
||||
|
||||
}
|
||||
|
||||
// Store created future.
|
||||
future = created;
|
||||
|
||||
}
|
||||
|
||||
// Return cached name (may still be null until async query completes).
|
||||
return cachedName;
|
||||
|
||||
}
|
||||
|
||||
// Non-cached version of getName() for testing
|
||||
public @NotNull CompletableFuture<@Nullable String> getNameAsync() {
|
||||
|
||||
// If cached name exists, return it as completed future
|
||||
if (cachedName != null) {
|
||||
|
||||
return CompletableFuture.completedFuture(cachedName);
|
||||
|
||||
}
|
||||
|
||||
// Ensure lookup starts by calling getName()
|
||||
getName();
|
||||
|
||||
// Return lookup future
|
||||
return lookup.get();
|
||||
|
||||
}
|
||||
|
||||
// Fast re-implementation OfflinePlayer.getUniqueId() from Bukkit API.
|
||||
@Override
|
||||
public @NotNull UUID getUniqueId() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
// Pass on UUID from constructor.
|
||||
return uuid;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PlayerProfile getPlayerProfile() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -86,7 +253,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public boolean isBanned() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return false;
|
||||
|
||||
}
|
||||
@@ -94,21 +261,21 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public boolean isWhitelisted() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWhitelisted(boolean value) {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Player getPlayer() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -116,7 +283,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public long getFirstPlayed() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -131,7 +298,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public long getLastPlayed() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return getLastSeen();
|
||||
|
||||
}
|
||||
@@ -139,7 +306,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public boolean hasPlayedBefore() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return false;
|
||||
|
||||
}
|
||||
@@ -147,7 +314,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public @Nullable Location getBedSpawnLocation() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -155,7 +322,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public long getLastLogin() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -163,45 +330,45 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public long getLastSeen() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementStatistic(@NotNull Statistic statistic) throws IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decrementStatistic(@NotNull Statistic statistic) throws IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementStatistic(@NotNull Statistic statistic, int amount) throws IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decrementStatistic(@NotNull Statistic statistic, int amount) throws IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatistic(@NotNull Statistic statistic, int newValue) throws IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatistic(@NotNull Statistic statistic) throws IllegalArgumentException {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -210,7 +377,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
public void incrementStatistic(@NotNull Statistic statistic, @NotNull Material material)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@@ -218,14 +385,14 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
public void decrementStatistic(@NotNull Statistic statistic, @NotNull Material material)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatistic(@NotNull Statistic statistic, @NotNull Material material) throws IllegalArgumentException {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -234,7 +401,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
public void incrementStatistic(@NotNull Statistic statistic, @NotNull Material material, int amount)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@@ -242,7 +409,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
public void decrementStatistic(@NotNull Statistic statistic, @NotNull Material material, int amount)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@@ -250,7 +417,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
public void setStatistic(@NotNull Statistic statistic, @NotNull Material material, int newValue)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@@ -258,7 +425,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
public void incrementStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@@ -266,7 +433,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
public void decrementStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@@ -275,7 +442,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -284,26 +451,26 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
public void incrementStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType, int amount)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decrementStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType, int amount) {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType, int newValue) {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Location getLastDeathLocation() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -311,7 +478,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public boolean getAllowFlight() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return false;
|
||||
|
||||
}
|
||||
@@ -319,40 +486,40 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public void setAllowFlight(boolean flight) {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlying() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlying(boolean value) {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlySpeed(float value) throws IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWalkSpeed(float value) throws IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFlySpeed() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -360,7 +527,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public float getWalkSpeed() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -368,7 +535,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public @Nullable Location getLocation() {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -376,7 +543,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public boolean teleportOffline(@NotNull Location destination) {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return false;
|
||||
|
||||
}
|
||||
@@ -384,7 +551,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public boolean teleportOffline(@NotNull Location destination, @NotNull TeleportCause cause) {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return false;
|
||||
|
||||
}
|
||||
@@ -392,7 +559,7 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@Override
|
||||
public @NotNull CompletableFuture<Boolean> teleportOfflineAsync(@NotNull Location destination) {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -402,9 +569,9 @@ public class FastOfflinePlayer implements OfflinePlayer {
|
||||
@NotNull TeleportCause cause)
|
||||
{
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub.
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,59 @@
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
// Authors: NotAlexNoyle.
|
||||
package net.trueog.utilitiesog;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.sk89q.worldguard.protection.flags.StateFlag;
|
||||
|
||||
// Makes functions in the main class accessible internally without cluttering up suggestions for UtilitiesOG API users.
|
||||
public class InternalFunctions {
|
||||
|
||||
public static FileConfiguration getConfig() {
|
||||
|
||||
return UtilitiesOG.config();
|
||||
|
||||
}
|
||||
|
||||
// Getter for the plugin prefix.
|
||||
public static String getPrefix() {
|
||||
|
||||
return UtilitiesOG.prefix();
|
||||
|
||||
}
|
||||
|
||||
// Getter for the config.yml object.
|
||||
public static FileConfiguration getConfig() {
|
||||
|
||||
return UtilitiesOG.config();
|
||||
|
||||
}
|
||||
|
||||
// Getter for the plugin object.
|
||||
public static Plugin getPlugin() {
|
||||
|
||||
return UtilitiesOG.plugin();
|
||||
|
||||
}
|
||||
|
||||
// Getter for the NoFlippy state flag.
|
||||
public static StateFlag getFlippyFlag() {
|
||||
|
||||
return UtilitiesOG.flippyFlag();
|
||||
|
||||
}
|
||||
|
||||
// Getter for the phantom disabled players file.
|
||||
// TODO: Replace with database.
|
||||
public static File getPhantomDisabledPlayersFile() {
|
||||
|
||||
return UtilitiesOG.phantomDisabledPlayersFile();
|
||||
|
||||
}
|
||||
|
||||
// Getter for the phantom preferences object.
|
||||
public static YamlConfiguration getPhantomPreferences() {
|
||||
|
||||
return UtilitiesOG.phantomPreferences();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,12 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import com.github.jasync.sql.db.pool.ConnectionPool;
|
||||
import com.github.jasync.sql.db.postgresql.PostgreSQLConnection;
|
||||
import com.github.jasync.sql.db.postgresql.PostgreSQLConnectionBuilder;
|
||||
import com.sk89q.worldguard.protection.flags.StateFlag;
|
||||
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
@@ -48,16 +51,17 @@ import net.trueog.utilitiesog.utils.TextUtils;
|
||||
public final class UtilitiesOG extends JavaPlugin {
|
||||
|
||||
private File file;
|
||||
private static UtilitiesOG plugin;
|
||||
private static Plugin instance;
|
||||
private static FileConfiguration config;
|
||||
private static File phantomPreferencesFile;
|
||||
private static YamlConfiguration phantomPreferences;
|
||||
private static StateFlag FlippyFlag;
|
||||
private static ConnectionPool<PostgreSQLConnection> POOL;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
||||
plugin = this;
|
||||
instance = this;
|
||||
|
||||
this.file = new File(this.getDataFolder(), "config.yml");
|
||||
if (!this.file.exists()) {
|
||||
@@ -67,6 +71,9 @@ public final class UtilitiesOG extends JavaPlugin {
|
||||
}
|
||||
|
||||
config = this.getConfig();
|
||||
|
||||
POOL = initPsql();
|
||||
|
||||
phantomPreferencesFile = new File(this.getDataFolder(), "phantomDisabledUsers.yml");
|
||||
|
||||
try {
|
||||
@@ -117,7 +124,7 @@ public final class UtilitiesOG extends JavaPlugin {
|
||||
final User user = luckPerms.getUserManager().getUser(player.getUniqueId());
|
||||
if (user == null) {
|
||||
|
||||
getPlugin().getLogger().info("ERROR: MiniPlaceholder processing error. Player: " + player.getName()
|
||||
getLogger().info("ERROR: MiniPlaceholder processing error. Player: " + player.getName()
|
||||
+ " has no User object in LuckPerms!");
|
||||
|
||||
return player.getName();
|
||||
@@ -128,7 +135,7 @@ public final class UtilitiesOG extends JavaPlugin {
|
||||
final Group group = luckPerms.getGroupManager().getGroup(primaryGroup);
|
||||
if (group == null) {
|
||||
|
||||
getPlugin().getLogger().info("ERROR: MiniPlaceholder processing error. User: " + player.getName()
|
||||
getLogger().info("ERROR: MiniPlaceholder processing error. User: " + player.getName()
|
||||
+ " has no Group assignment in LuckPerms!");
|
||||
|
||||
return player.getName();
|
||||
@@ -266,6 +273,12 @@ public final class UtilitiesOG extends JavaPlugin {
|
||||
|
||||
}
|
||||
|
||||
static Plugin plugin() {
|
||||
|
||||
return instance;
|
||||
|
||||
}
|
||||
|
||||
// Unified method for sending a message to a player with placeholders processed.
|
||||
public static void trueogMessage(Player player, String message) {
|
||||
|
||||
@@ -341,33 +354,24 @@ public final class UtilitiesOG extends JavaPlugin {
|
||||
// Global placeholder without arguments.
|
||||
public static void registerGlobalPlaceholder(String name, Supplier<String> valueSupplier) {
|
||||
|
||||
PlaceholderUtils.trueogRegisterMiniPlaceholder(name, placeholder -> {
|
||||
|
||||
placeholder.setGlobalPlaceholder(valueSupplier);
|
||||
|
||||
});
|
||||
PlaceholderUtils.trueogRegisterMiniPlaceholder(name,
|
||||
placeholder -> placeholder.setGlobalPlaceholder(valueSupplier));
|
||||
|
||||
}
|
||||
|
||||
// Global placeholder with arguments.
|
||||
public static void registerGlobalPlaceholder(String name, Function<List<String>, String> valueFunction) {
|
||||
|
||||
PlaceholderUtils.trueogRegisterMiniPlaceholder(name, placeholder -> {
|
||||
|
||||
placeholder.setGlobalPlaceholder(valueFunction);
|
||||
|
||||
});
|
||||
PlaceholderUtils.trueogRegisterMiniPlaceholder(name,
|
||||
placeholder -> placeholder.setGlobalPlaceholder(valueFunction));
|
||||
|
||||
}
|
||||
|
||||
// Audience placeholder without arguments.
|
||||
public static void registerAudiencePlaceholder(String name, Function<Player, String> valueFunction) {
|
||||
|
||||
PlaceholderUtils.trueogRegisterMiniPlaceholder(name, placeholder -> {
|
||||
|
||||
placeholder.setAudiencePlaceholder(valueFunction);
|
||||
|
||||
});
|
||||
PlaceholderUtils.trueogRegisterMiniPlaceholder(name,
|
||||
placeholder -> placeholder.setAudiencePlaceholder(valueFunction));
|
||||
|
||||
}
|
||||
|
||||
@@ -376,22 +380,16 @@ public final class UtilitiesOG extends JavaPlugin {
|
||||
BiFunction<Player, List<String>, String> valueFunction)
|
||||
{
|
||||
|
||||
PlaceholderUtils.trueogRegisterMiniPlaceholder(name, placeholder -> {
|
||||
|
||||
placeholder.setAudiencePlaceholder(valueFunction);
|
||||
|
||||
});
|
||||
PlaceholderUtils.trueogRegisterMiniPlaceholder(name,
|
||||
placeholder -> placeholder.setAudiencePlaceholder(valueFunction));
|
||||
|
||||
}
|
||||
|
||||
// Relational placeholder without arguments.
|
||||
public static void registerRelationalPlaceholder(String name, BiFunction<Player, Player, String> valueFunction) {
|
||||
|
||||
PlaceholderUtils.trueogRegisterMiniPlaceholder(name, placeholder -> {
|
||||
|
||||
placeholder.setRelationalPlaceholder(valueFunction);
|
||||
|
||||
});
|
||||
PlaceholderUtils.trueogRegisterMiniPlaceholder(name,
|
||||
placeholder -> placeholder.setRelationalPlaceholder(valueFunction));
|
||||
|
||||
}
|
||||
|
||||
@@ -400,11 +398,8 @@ public final class UtilitiesOG extends JavaPlugin {
|
||||
TriFunction<Player, Player, List<String>, String> valueFunction)
|
||||
{
|
||||
|
||||
PlaceholderUtils.trueogRegisterMiniPlaceholder(name, placeholder -> {
|
||||
|
||||
placeholder.setRelationalPlaceholder(valueFunction);
|
||||
|
||||
});
|
||||
PlaceholderUtils.trueogRegisterMiniPlaceholder(name,
|
||||
placeholder -> placeholder.setRelationalPlaceholder(valueFunction));
|
||||
|
||||
}
|
||||
|
||||
@@ -422,15 +417,25 @@ public final class UtilitiesOG extends JavaPlugin {
|
||||
|
||||
}
|
||||
|
||||
public static UtilitiesOG getPlugin() {
|
||||
// Initialize postgres connection;
|
||||
private ConnectionPool<PostgreSQLConnection> initPsql() {
|
||||
|
||||
return plugin;
|
||||
// Reads the values from config.yml;
|
||||
final String baseUrl = getConfig().getString("postgresUrl"); // e.g. jdbc:postgresql://localhost:5432/diamond
|
||||
final String user = getConfig().getString("postgresUser"); // e.g. postgres
|
||||
final String password = getConfig().getString("postgresPassword"); // e.g. postgresPassword
|
||||
|
||||
// Appends credentials to the URL (only if they are not already present)
|
||||
final String jdbcUrl = "%s?user=%s&password=%s".formatted(baseUrl, user, password);
|
||||
|
||||
// Create postgres connection.
|
||||
return PostgreSQLConnectionBuilder.createConnectionPool(jdbcUrl);
|
||||
|
||||
}
|
||||
|
||||
public static BukkitTask runTaskAsynchronously(final Runnable run) {
|
||||
public static ConnectionPool<PostgreSQLConnection> getPostgres() {
|
||||
|
||||
return getPlugin().getServer().getScheduler().runTaskAsynchronously(getPlugin(), run);
|
||||
return POOL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import net.trueog.utilitiesog.InternalFunctions;
|
||||
// Import libraries.
|
||||
import net.trueog.utilitiesog.UtilitiesOG;
|
||||
import net.trueog.utilitiesog.utils.TextUtils;
|
||||
@@ -30,7 +31,7 @@ public class ToggleCrammingCommand implements CommandExecutor {
|
||||
if (player.hasPermission(toggleCrammingPermission)) {
|
||||
|
||||
// Fetch config file from data folder.
|
||||
final FileConfiguration config = UtilitiesOG.getPlugin().getConfig();
|
||||
final FileConfiguration config = InternalFunctions.getPlugin().getConfig();
|
||||
|
||||
// Flip the true/false value to the opposite of what it currently is.
|
||||
config.set("doEntityCramming", !config.getBoolean("doEntityCramming"));
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
// Authors: christianniehaus, NotAlexNoyle.
|
||||
package net.trueog.utilitiesog.listeners;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
import com.github.jasync.sql.db.QueryResult;
|
||||
|
||||
import net.trueog.utilitiesog.UtilitiesOG;
|
||||
|
||||
// A class for storing and caching FastOfflinePlayers during player join and player leave.
|
||||
public class FastOfflinePlayerListener {
|
||||
|
||||
// When a player joins the server, do this...
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
|
||||
// Get the player from the event.
|
||||
final Player player = event.getPlayer();
|
||||
|
||||
// Add or update player data in the offline player database.
|
||||
upsertOrUpdatePlayer(player);
|
||||
|
||||
// Inform the player of the result.
|
||||
UtilitiesOG.trueogMessage(player, "Your data is cached!");
|
||||
|
||||
}
|
||||
|
||||
// Insert new user or update user metadata in one query depending on need.
|
||||
private CompletableFuture<QueryResult> upsertOrUpdatePlayer(Player player) {
|
||||
|
||||
// Direct postgres query for inserting and/or updating a player.
|
||||
final String sql = "INSERT INTO offline_players (uuid, username) " + "VALUES ($1, $2) "
|
||||
+ "ON CONFLICT (uuid) DO UPDATE " + " SET username = EXCLUDED.username, "
|
||||
+ " last_seen = NOW();";
|
||||
|
||||
// Add player UUID and player name key-value pair to database.
|
||||
return query(sql, player.getUniqueId(), player.getName());
|
||||
|
||||
}
|
||||
|
||||
// Send an async query using jasync Postgres.
|
||||
private CompletableFuture<QueryResult> query(String sql, Object... params) {
|
||||
|
||||
// Gift wrap around jasync’s sendPreparedStatement.
|
||||
return UtilitiesOG.getPostgres().sendPreparedStatement(sql, Arrays.asList(params));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+5
-5
@@ -1,12 +1,14 @@
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
// Authors: christianniehaus, NotAlexNoyle.
|
||||
package net.trueog.utilitiesog.listeners;
|
||||
|
||||
import com.destroystokyo.paper.event.player.PlayerAdvancementCriterionGrantEvent;
|
||||
import net.trueog.utilitiesog.FastOfflinePlayer;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import com.destroystokyo.paper.event.player.PlayerAdvancementCriterionGrantEvent;
|
||||
|
||||
public class NoAdvancementsInCreativeListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
@@ -18,8 +20,6 @@ public class NoAdvancementsInCreativeListener implements Listener {
|
||||
|
||||
}
|
||||
|
||||
final FastOfflinePlayer fop = new FastOfflinePlayer(event.getPlayer().getUniqueId());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ public class NoFlippyListener implements Listener {
|
||||
catch (FlagConflictException error) {
|
||||
|
||||
// Log the WorldGuard Flag conflict to the server console.
|
||||
UtilitiesOG.getPlugin().getLogger().severe(
|
||||
UtilitiesOG.logToConsole(InternalFunctions.getPrefix(),
|
||||
"ERROR: can-flippy of the NoFlippy Module has a WorldGuard Flag conflict! " + error.getMessage());
|
||||
|
||||
// Pulls the WorldGuard Flag from the registry that some other plugin registered
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.ShapedRecipe;
|
||||
|
||||
import net.trueog.utilitiesog.UtilitiesOG;
|
||||
import net.trueog.utilitiesog.InternalFunctions;
|
||||
|
||||
// Declare the Chain Armor Module.
|
||||
public class ChainArmorModule {
|
||||
@@ -18,23 +18,24 @@ public class ChainArmorModule {
|
||||
|
||||
// Defines a crafting recipe for Chainmail Helmet from Chains.
|
||||
final ShapedRecipe ChainHelmet = new ShapedRecipe(
|
||||
new NamespacedKey(UtilitiesOG.getPlugin(), "Chainmail_Helmet1"),
|
||||
new NamespacedKey(InternalFunctions.getPlugin(), "Chainmail_Helmet1"),
|
||||
new ItemStack(Material.CHAINMAIL_HELMET)).shape("ccc", "c c").setIngredient('c', Material.CHAIN);
|
||||
|
||||
// Defines a crafting recipe for Chainmail Chestplate from Chains.
|
||||
final ShapedRecipe ChainChestPlate = new ShapedRecipe(
|
||||
new NamespacedKey(UtilitiesOG.getPlugin(), "Chainmail_Chestplate"),
|
||||
new NamespacedKey(InternalFunctions.getPlugin(), "Chainmail_Chestplate"),
|
||||
new ItemStack(Material.CHAINMAIL_CHESTPLATE)).shape("c c", "ccc", "ccc")
|
||||
.setIngredient('c', Material.CHAIN);
|
||||
|
||||
// Defines a crafting recipe for Chainmail Leggings from Chains.
|
||||
final ShapedRecipe ChainLeggings = new ShapedRecipe(
|
||||
new NamespacedKey(UtilitiesOG.getPlugin(), "Chainmail_Leggings"),
|
||||
new NamespacedKey(InternalFunctions.getPlugin(), "Chainmail_Leggings"),
|
||||
new ItemStack(Material.CHAINMAIL_LEGGINGS)).shape("ccc", "c c", "c c")
|
||||
.setIngredient('c', Material.CHAIN);
|
||||
|
||||
// Defines a crafting recipe for Chainmail Boots from Chains.
|
||||
final ShapedRecipe ChainBoots = new ShapedRecipe(new NamespacedKey(UtilitiesOG.getPlugin(), "Chainmail_Boots1"),
|
||||
final ShapedRecipe ChainBoots = new ShapedRecipe(
|
||||
new NamespacedKey(InternalFunctions.getPlugin(), "Chainmail_Boots1"),
|
||||
new ItemStack(Material.CHAINMAIL_BOOTS)).shape("c c", "c c").setIngredient('c', Material.CHAIN);
|
||||
|
||||
// Add the Chainmail Armor crafting recipes to the server.
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.bukkit.inventory.meta.ItemMeta;
|
||||
// Import libraries.
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.trueog.utilitiesog.UtilitiesOG;
|
||||
import net.trueog.utilitiesog.InternalFunctions;
|
||||
|
||||
// Declare the Mock Bamboo Wood Module.
|
||||
public class MockBambooModule {
|
||||
@@ -34,8 +34,8 @@ public class MockBambooModule {
|
||||
bambooPlanks.setItemMeta(bambooPlanksMeta);
|
||||
|
||||
// Defines a crafting recipe for Bamboo Planks.
|
||||
final ShapedRecipe BambooPlanks = new ShapedRecipe(new NamespacedKey(UtilitiesOG.getPlugin(), "Bamboo_Planks"),
|
||||
bambooPlanks).shape("bb", "bb")
|
||||
final ShapedRecipe BambooPlanks = new ShapedRecipe(
|
||||
new NamespacedKey(InternalFunctions.getPlugin(), "Bamboo_Planks"), bambooPlanks).shape("bb", "bb")
|
||||
// Use Bamboo as the base ingredient.
|
||||
.setIngredient('b', Material.BAMBOO);
|
||||
|
||||
@@ -57,7 +57,7 @@ public class MockBambooModule {
|
||||
|
||||
// Define a crafting recipe for mock Bamboo Wood.
|
||||
final ShapedRecipe imitationBambooWoodRecipe = new ShapedRecipe(
|
||||
new NamespacedKey(UtilitiesOG.getPlugin(), "Imitation_Bamboo_Wood"), imitationBambooWood)
|
||||
new NamespacedKey(InternalFunctions.getPlugin(), "Imitation_Bamboo_Wood"), imitationBambooWood)
|
||||
.shape("bb", "bb")
|
||||
// Use the previously created bamboo planks as the base ingredient.
|
||||
.setIngredient('b', bambooPlanks);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
// Authors: christianniehaus, NotAlexNoyle.
|
||||
package net.trueog.utilitiesog.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -19,3 +19,10 @@ Ping: true
|
||||
RanksMenu: true
|
||||
# Should players earn advancements in non survival game modes?
|
||||
NoAdvancementsInCreative: true
|
||||
# PostgreSQL Setup for FastOfflinePlayer database.
|
||||
postgresUrl: jdbc:postgresql://localhost:5432/fastofflineplayer
|
||||
postgresUser: postgres
|
||||
postgresPassword: postgresPassword
|
||||
postgresTable: fastofflineplayer
|
||||
postgresLogTable: fastofflineplayer_log
|
||||
postgresLogLimit: 500
|
||||
@@ -1,352 +1,498 @@
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
// Authors: NotAlexNoyle.
|
||||
package net.trueog.utilitiesog;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.github.jasync.sql.db.QueryResult;
|
||||
import com.github.jasync.sql.db.ResultSet;
|
||||
import com.github.jasync.sql.db.RowData;
|
||||
import com.github.jasync.sql.db.pool.ConnectionPool;
|
||||
|
||||
import be.seeseemelk.mockbukkit.MockBukkit;
|
||||
import be.seeseemelk.mockbukkit.ServerMock;
|
||||
|
||||
// Test cases for FastOfflinePlayer.java
|
||||
class FastOfflinePlayerTest {
|
||||
|
||||
@Test
|
||||
void testIsOp() {
|
||||
// Declare a test UUID.
|
||||
final UUID testUUID = UUID.randomUUID();
|
||||
// Declare a test username.
|
||||
final String testName = "NotAlexNoyle";
|
||||
// Declare a mock server container using MockBukkit.
|
||||
private static ServerMock server;
|
||||
|
||||
fail("Not yet implemented");
|
||||
// Runs before all tests.
|
||||
@BeforeAll
|
||||
static void setUp() {
|
||||
|
||||
// Initialize the MockBukkit server.
|
||||
server = MockBukkit.mock();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetOp() {
|
||||
// Runs after each test.
|
||||
@AfterEach
|
||||
void resetDb() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
// Ensure each test gets a clean supplier.
|
||||
FastOfflinePlayer.resetConnectionSupplierForTests();
|
||||
|
||||
}
|
||||
|
||||
// Runs after all tests.
|
||||
@AfterAll
|
||||
static void tearDown() {
|
||||
|
||||
// Bring down MockBukkit server.
|
||||
MockBukkit.unmock();
|
||||
|
||||
}
|
||||
|
||||
// TODO: Uncomment and finish
|
||||
/*
|
||||
* @Test void testIsOp() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testSetOp() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*/
|
||||
|
||||
// FastOfflinePlayer.serialize() test.
|
||||
@Test
|
||||
void testSerialize() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
// Declare a test player.
|
||||
final FastOfflinePlayer testSerializePlayer = FastOfflinePlayer.deserialize(testUUID, Map.of("name", testName));
|
||||
|
||||
// JUnit: Compare the expected map to the FastOfflinePlayer map.
|
||||
assertEquals(Map.of("name", testName), testSerializePlayer.serialize());
|
||||
|
||||
}
|
||||
|
||||
// FastOfflinePlayer.deserialize() test.
|
||||
@Test
|
||||
void testIsOnline() {
|
||||
void testDeserialize() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
// Compose a deserialization control group map.
|
||||
final Map<String, Object> yaml = Map.of("name", testName);
|
||||
|
||||
// Declare a test player.
|
||||
final FastOfflinePlayer testDeserializePlayer = FastOfflinePlayer.deserialize(testUUID, yaml);
|
||||
|
||||
// JUnit: Compare the expected UUID to the FastOfflinePlayer UUID.
|
||||
assertEquals(testUUID, testDeserializePlayer.getUniqueId());
|
||||
// JUnit: Compare the expected name to the FastOfflinePlayer name.
|
||||
assertEquals(testName, testDeserializePlayer.getName());
|
||||
|
||||
}
|
||||
|
||||
// TODO: Uncomment and finish
|
||||
/*
|
||||
* @Test void testIsOnline() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*/
|
||||
|
||||
// FastOfflinePlayer.getName() test.
|
||||
@Test
|
||||
void testGetName() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
// Declare a jasync Postgres connection pool.
|
||||
final ConnectionPool<?> pool = mockPoolReturning(
|
||||
mockQueryResult(mockResultSet(mockRow(Map.of("username", testName)))));
|
||||
installMockDb(pool);
|
||||
|
||||
// Declare a test player.
|
||||
final FastOfflinePlayer testGetNamePlayer = new FastOfflinePlayer(UUID.randomUUID());
|
||||
|
||||
// JUnit: Compare the expected name to the actual name from database.
|
||||
assertEquals(testName, testGetNamePlayer.getNameAsync().join());
|
||||
// JUnit: Compare the expected name to the actual name from cache.
|
||||
assertEquals(testName, testGetNamePlayer.getName());
|
||||
|
||||
// Verify that multiple queries are not overlapping.
|
||||
verify(pool, times(1)).sendPreparedStatement(anyString(), anyList());
|
||||
|
||||
}
|
||||
|
||||
// FastOfflinePlayer.getUniqueID() test.
|
||||
@Test
|
||||
void testGetUniqueId() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
// Declare a test player.
|
||||
final FastOfflinePlayer uuidTestPlayer = new FastOfflinePlayer(testUUID);
|
||||
|
||||
// JUnit: Compare the expected UUID to the FastOfflinePlayer UUID.
|
||||
assertEquals(testUUID, uuidTestPlayer.getUniqueId());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPlayerProfile() {
|
||||
// TODO: Uncomment and finish
|
||||
/*
|
||||
* @Test void testGetPlayerProfile() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testIsBanned() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testIsWhitelisted() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testSetWhitelisted() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetPlayer() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetFirstPlayed() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetLastPlayed() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testHasPlayedBefore() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetBedSpawnLocation() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetLastLogin() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetLastSeen() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testIncrementStatisticStatistic() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testDecrementStatisticStatistic() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testIncrementStatisticStatisticInt() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testDecrementStatisticStatisticInt() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testSetStatisticStatisticInt() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetStatisticStatistic() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testIncrementStatisticStatisticMaterial() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testDecrementStatisticStatisticMaterial() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetStatisticStatisticMaterial() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testIncrementStatisticStatisticMaterialInt() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testDecrementStatisticStatisticMaterialInt() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testSetStatisticStatisticMaterialInt() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testIncrementStatisticStatisticEntityType() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testDecrementStatisticStatisticEntityType() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetStatisticStatisticEntityType() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testIncrementStatisticStatisticEntityTypeInt() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testDecrementStatisticStatisticEntityTypeInt() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testSetStatisticStatisticEntityTypeInt() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetLastDeathLocation() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetAllowFlight() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testSetAllowFlight() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testIsFlying() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testSetFlying() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testSetFlySpeed() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testSetWalkSpeed() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetFlySpeed() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetWalkSpeed() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testGetLocation() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testTeleportOfflineLocation() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testTeleportOfflineLocationTeleportCause() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testTeleportOfflineAsyncLocation() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Test void testTeleportOfflineAsyncLocationTeleportCause() {
|
||||
*
|
||||
* fail("Not yet implemented");
|
||||
*
|
||||
* }
|
||||
*/
|
||||
|
||||
fail("Not yet implemented");
|
||||
// Declare a fake jasync Postgres row for tests to use.
|
||||
private static RowData mockRow(Map<String, Object> cols) {
|
||||
|
||||
// Declare a Mockito mock for a single jasync Postgres row.
|
||||
final RowData row = mock(RowData.class);
|
||||
|
||||
// When getString(columnName) is called, look up the value from the map.
|
||||
when(row.getString(anyString())).thenAnswer(inv -> {
|
||||
|
||||
// If absent, return null; otherwise, coerce to String to match the API.
|
||||
final Object v = cols.get(inv.getArgument(0));
|
||||
return v == null ? null : String.valueOf(v);
|
||||
|
||||
});
|
||||
|
||||
// Return the configured mock row.
|
||||
return row;
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsBanned() {
|
||||
// Declare a fake jasync Postgres result set for tests to use.
|
||||
private static ResultSet mockResultSet(RowData... rowArray) {
|
||||
|
||||
fail("Not yet implemented");
|
||||
// Create a Mockito mock for a jasync Postgres ResultSet.
|
||||
final ResultSet rs = mock(ResultSet.class);
|
||||
|
||||
// Mock a result set. isEmpty() should reflect whether any rows have been passed
|
||||
// in.
|
||||
when(rs.isEmpty()).thenReturn(rowArray.length == 0);
|
||||
|
||||
// Loop that runs once for each result row.
|
||||
for (int i = 0; i < rowArray.length; i++) {
|
||||
|
||||
// Stub indexed access to return the corresponding RowData from the array.
|
||||
when(rs.get(i)).thenReturn(rowArray[i]);
|
||||
|
||||
}
|
||||
|
||||
// Return the configured mock result set.
|
||||
return rs;
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsWhitelisted() {
|
||||
// Declare a fake jasync Postgres query result for tests to use.
|
||||
private static QueryResult mockQueryResult(ResultSet rows) {
|
||||
|
||||
fail("Not yet implemented");
|
||||
// Create a Mockito mock for a jasync Postgres QueryResult that wraps a given
|
||||
// ResultSet.
|
||||
final QueryResult qr = mock(QueryResult.class);
|
||||
|
||||
// Mock a query result.
|
||||
when(qr.getRows()).thenReturn(rows);
|
||||
|
||||
// Return the mocked query result.
|
||||
return qr;
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetWhitelisted() {
|
||||
// Declare a fake jasync Postgres ConnectionPool for tests to use.
|
||||
private static ConnectionPool<?> mockPoolReturning(QueryResult result) {
|
||||
|
||||
fail("Not yet implemented");
|
||||
// Create a Mockito mock for a jasync Postgres ConnectionPool.
|
||||
final ConnectionPool<?> pool = mock(ConnectionPool.class);
|
||||
|
||||
// Mock a ConnectionPool.
|
||||
when(pool.sendPreparedStatement(anyString(), anyList())).thenReturn(CompletableFuture.completedFuture(result));
|
||||
|
||||
// Return the mocked mock pool.
|
||||
return pool;
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPlayer() {
|
||||
// Initialize the mocked jasync Postgres database.
|
||||
private static void installMockDb(ConnectionPool<?> pool) {
|
||||
|
||||
fail("Not yet implemented");
|
||||
// Install the mocked pool into FastOfflinePlayer via its test seam so code
|
||||
// under test uses this pool instead of touching UtilitiesOG. This prevents
|
||||
// missing class errors due to not all UtilitiesOG.java calls being on the test
|
||||
// class path.
|
||||
FastOfflinePlayer.overrideConnectionSupplierForTests(() -> pool);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetFirstPlayed() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLastPlayed() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHasPlayedBefore() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetBedSpawnLocation() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLastLogin() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLastSeen() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIncrementStatisticStatistic() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecrementStatisticStatistic() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIncrementStatisticStatisticInt() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecrementStatisticStatisticInt() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetStatisticStatisticInt() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetStatisticStatistic() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIncrementStatisticStatisticMaterial() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecrementStatisticStatisticMaterial() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetStatisticStatisticMaterial() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIncrementStatisticStatisticMaterialInt() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecrementStatisticStatisticMaterialInt() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetStatisticStatisticMaterialInt() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIncrementStatisticStatisticEntityType() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecrementStatisticStatisticEntityType() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetStatisticStatisticEntityType() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIncrementStatisticStatisticEntityTypeInt() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecrementStatisticStatisticEntityTypeInt() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetStatisticStatisticEntityTypeInt() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLastDeathLocation() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAllowFlight() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetAllowFlight() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsFlying() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetFlying() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetFlySpeed() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetWalkSpeed() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetFlySpeed() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetWalkSpeed() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLocation() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTeleportOfflineLocation() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTeleportOfflineLocationTeleportCause() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTeleportOfflineAsyncLocation() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTeleportOfflineAsyncLocationTeleportCause() {
|
||||
|
||||
fail("Not yet implemented");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user