feat: switch to paperweight and create plugin loader

This commit is contained in:
ineanto 2025-03-20 18:50:06 +01:00
parent ff892a7451
commit a996858ba9
Signed by: ineanto
GPG key ID: E511F9CAA2F9CE84
20 changed files with 155 additions and 680 deletions

5
.gitignore vendored
View file

@ -26,4 +26,7 @@ bin/
!**/src/test/**/bin/
### Server ###
run/
run/
### Private ###
TODO

1
.idea/gradle.xml generated
View file

@ -5,6 +5,7 @@
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="22" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />

View file

@ -1,74 +1,52 @@
import io.papermc.paperweight.userdev.ReobfArtifactConfiguration
import io.papermc.paperweight.util.path
import xyz.jpenilla.runtask.RunExtension
plugins {
id("java")
id("com.gradleup.shadow") version "8.3.2"
id("xyz.jpenilla.run-paper") version "2.3.0"
id("io.papermc.paperweight.userdev") version "1.7.4"
id("io.papermc.paperweight.userdev") version "2.0.0-beta.10"
}
group = "xyz.ineanto"
version = "1.2.0"
val invuiVersion: String = "1.44"
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
sourceCompatibility = JavaVersion.VERSION_22
targetCompatibility = JavaVersion.VERSION_22
toolchain {
languageVersion = JavaLanguageVersion.of(21)
languageVersion = JavaLanguageVersion.of(22)
}
}
repositories {
mavenCentral()
mavenLocal()
maven { url = uri("https://jitpack.io") }
maven {
name = "xenondevs"
url = uri("https://repo.xenondevs.xyz/releases")
}
maven {
name = "papermc"
url = uri("https://repo.papermc.io/repository/maven-public/")
}
maven {
name = "codemc"
url = uri("https://repo.codemc.io/repository/maven-snapshots/")
}
maven {
name = "placeholderapi"
url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/")
}
maven { url = uri("https://repo.xenondevs.xyz/releases") }
maven { url = uri("https://repo.papermc.io/repository/maven-public/") }
maven { url = uri("https://repo.codemc.io/repository/maven-snapshots/") }
maven { url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/") }
}
dependencies {
paperweight.paperDevBundle("1.21.3-R0.1-SNAPSHOT")
paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT")
compileOnly("com.github.dmulloy2:ProtocolLib:5.3.0")
compileOnly("com.comphenix.protocol:ProtocolLib:5.4.0-SNAPSHOT")
compileOnly("me.clip:placeholderapi:2.11.5")
compileOnly("net.kyori:adventure-api:4.17.0")
compileOnly("xyz.xenondevs.invui:invui-core:$invuiVersion")
compileOnly("net.wesjd:anvilgui:1.10.4-SNAPSHOT")
implementation("xyz.xenondevs.invui:invui-core:1.41")
implementation("xyz.xenondevs.invui:inventory-access-r21:1.41")
//implementation("xyz.xenondevs.invui:inventory-access-r22:$invuiVersion:remapped-mojang")
implementation("net.wesjd:anvilgui:1.10.3-SNAPSHOT")
implementation("com.github.jsixface:yamlconfig:1.2")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.1")
implementation("com.fasterxml.jackson.core:jackson-core:2.18.1")
implementation("com.mysql:mysql-connector-j:9.1.0")
implementation("org.mariadb.jdbc:mariadb-java-client:3.5.0")
implementation("com.mysql:mysql-connector-j:9.2.0")
implementation("org.mariadb.jdbc:mariadb-java-client:3.5.2")
implementation("redis.clients:jedis:5.2.0")
implementation("com.google.code.gson:gson:2.10.1")
testImplementation("com.github.MockBukkit:MockBukkit:v3.133.2")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.2")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.2")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
}
paperweight {
reobfArtifactConfiguration = ReobfArtifactConfiguration.REOBF_PRODUCTION
}
tasks {
@ -83,10 +61,10 @@ tasks {
shadowJar {
// RELOCATIONS
relocate("xyz.xenondevs", "xyz.ineanto.nicko.libs.invui")
relocate("me.clip", "xyz.ineanto.nicko.libs.placeholderapi")
relocate("net.wesjd", "xyz.ineanto.nicko.libs.anvilgui")
//relocate("xyz.xenondevs", "xyz.ineanto.nicko.libs.invui")
//relocate("net.wesjd", "xyz.ineanto.nicko.libs.anvilgui")
relocate("com.github.jsixface", "xyz.ineanto.nicko.libs.yaml")
relocate("me.clip", "xyz.ineanto.nicko.libs.placeholderapi")
relocate("com.fasterxml.jackson", "xyz.ineanto.nicko.libs.jacksonpr")
relocate("com.mysql", "xyz.ineanto.nicko.libs.mysql")
relocate("org.mariadb.jdbc", "xyz.ineanto.nicko.libs.mariadb")
@ -113,49 +91,24 @@ tasks {
// MINIFY
minimize {
exclude(dependency("xyz.xenondevs.invui:.*"))
exclude(dependency("net.wesjd:.*"))
//exclude(dependency("xyz.xenondevs.invui:.*"))
//exclude(dependency("net.wesjd:.*"))
exclude(dependency("org.bstats:.*"))
}
manifest {
attributes["paperweight-mappings-namespace"] = "spigot"
attributes["paperweight-mappings-namespace"] = "mojang"
}
}
runServer {
dependsOn(reobfJar)
/**
* https://github.com/jpenilla/run-task/issues/56
*
* jpenilla:
* "On 1.20.5+ it makes no sense to waste time obfuscating the jar in development
* just for it to be immediately deobfuscated.
* If you have an edge case setup where this makes sense somehow,
* you can disable plugin jar detection and configure the plugin jars collection yourself."
*
* Well, Nicko is an edge case.
* AnvilGUI and InvUI are still using Spigot Mappings,
* and I'm stuck using them until they push a major, breaking update.
*/
args("-add-plugin=${reobfJar.get().outputJar.path.toAbsolutePath()}")
downloadPlugins {
url("https://download.luckperms.net/1554/bukkit/loader/LuckPerms-Bukkit-5.4.139.jar")
// 1.20 - 1.20.4 testing
//url("https://github.com/dmulloy2/ProtocolLib/releases/download/5.2.0/ProtocolLib.jar")
url("https://download.luckperms.net/1568/bukkit/loader/LuckPerms-Bukkit-5.4.151.jar")
// 1.20.5 - latest testing
url("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/build/libs/ProtocolLib.jar")
}
minecraftVersion("1.21.3")
minecraftVersion("1.21.4")
}
}
extensions.configure<RunExtension> {
disablePluginJarDetection()
}

Binary file not shown.

View file

@ -1,6 +1,7 @@
#Mon Dec 11 00:36:17 CET 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

43
gradlew vendored
View file

@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@ -80,13 +82,11 @@ do
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@ -133,22 +133,29 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@ -193,11 +200,15 @@ if "$cygwin" || "$msys" ; then
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
@ -205,6 +216,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.

37
gradlew.bat vendored
View file

@ -13,8 +13,10 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@ -25,7 +27,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

View file

@ -0,0 +1,20 @@
package xyz.ineanto.nicko.loader;
import io.papermc.paper.plugin.loader.PluginClasspathBuilder;
import io.papermc.paper.plugin.loader.PluginLoader;
import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.repository.RemoteRepository;
public class NickoPluginLoader implements PluginLoader {
@Override
public void classloader(PluginClasspathBuilder pluginClasspathBuilder) {
final MavenLibraryResolver resolver = new MavenLibraryResolver();
resolver.addRepository(new RemoteRepository.Builder("xenondevs", "default", "https://repo.xenondevs.xyz/releases/").build());
resolver.addRepository(new RemoteRepository.Builder("wesjd", "default", "https://repo.codemc.io/repository/maven-snapshots/").build());
resolver.addDependency(new Dependency(new DefaultArtifact("xyz.xenondevs.invui:invui:pom:1.44"), null));
resolver.addDependency(new Dependency(new DefaultArtifact("net:wesjd:anvilgui:1.10.4-SNAPSHOT"), null));
pluginClasspathBuilder.addLibrary(resolver);
}
}

View file

@ -149,6 +149,7 @@ public class InternalPacketSender implements PacketSender {
serverPlayer.connection.latency(),
serverPlayer.gameMode.getGameModeForPlayer(),
MutableComponent.create(new PlainTextContents.LiteralContents(displayName)),
true,
serverPlayer.getTabListOrder(),
Optionull.map(serverPlayer.getChatSession(), RemoteChatSession::asData)
));
@ -165,4 +166,4 @@ public class InternalPacketSender implements PacketSender {
private void sendPacket(Packet<?> packet, Player player) {
(((CraftPlayer) player).getHandle()).connection.send(packet);
}
}
}

View file

@ -3,7 +3,11 @@ package xyz.ineanto.nicko.packet.wrapper;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.InternalStructure;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.EnumWrappers;
@ -13,8 +17,11 @@ import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.World;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.RecordComponent;
import java.util.Arrays;
/**
* PacketPlayServerRespawn Wrapper class (1.20.X to 1.21.X)
@ -56,24 +63,49 @@ public class WrapperPlayServerRespawn extends AbstractPacket {
} else {
// 1.20.5 to 1.21.1
/*
Honestly, I've tried everything to make this work.
Fields inside the CommonPlayerSpawnInfo are Record Components and are
marked final.
This would work with some trickery involved, but here's the
caveat: Record Components/Fields and are immutable by DESIGN.
So... here we are now, stopped right in my track by Java's language design and Mojang themselves.
*/
try {
final Object spawnInfoStructureHandle = spawnInfoStructure.getHandle();
final RecordComponent[] components = spawnInfoStructureHandle.getClass().getRecordComponents();
final Class<?> spawnInfoClass = MinecraftReflection.getMinecraftClass("network.protocol.game.CommonPlayerSpawnInfo");
final Field levelKeyField = spawnInfoStructureHandle.getClass().getDeclaredField(components[1].getAccessor().getName());
levelKeyField.setAccessible(true);
levelKeyField.set(spawnInfoStructureHandle, BukkitConverters.getWorldKeyConverter().getGeneric(Bukkit.getWorld("world")));
} catch (NoSuchFieldException | IllegalAccessException e) {
Class<?>[] componentTypes = Arrays.stream(spawnInfoClass.getRecordComponents())
.map(RecordComponent::getType)
.toArray(Class<?>[]::new);
final Constructor<?> spawnInfoConstructor = spawnInfoClass.getDeclaredConstructor(componentTypes);
/**
* Holder<DimensionType> dimensionType,
* ResourceKey<Level> dimension,
* long seed,
* GameType gameType,
* GameType previousGameType,
* boolean isDebug,
* boolean isFlat,
* Optional<GlobalPos> lastDeathLocation,
* int portalCooldown
*/
final World world = Bukkit.getWorld("world");
FuzzyReflection.fromClass(spawnInfoClass).getConstructor(
FuzzyMethodContract
.newBuilder()
.build()
);
final Object spawnInfo = spawnInfoConstructor.newInstance(
BukkitConverters.getDimensionConverter().getGeneric(world),
BukkitConverters.getWorldKeyConverter().getGeneric(world),
world.getSeed(),
EnumWrappers.getGameModeConverter().getGeneric(EnumWrappers.NativeGameMode.fromBukkit(GameMode.SURVIVAL)),
EnumWrappers.getGameModeConverter().getGeneric(EnumWrappers.NativeGameMode.fromBukkit(GameMode.SURVIVAL)),
false,
false,
BukkitConverters.getSectionPositionConverter()
);
final Field commonSpawnDataField = Accessors.getFieldAccessor(TYPE.getPacketClass(), spawnInfoClass, true).getField();
commonSpawnDataField.set(spawnInfoStructure.getHandle(), spawnInfo);
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException |
InstantiationException e) {
throw new RuntimeException();
}
}

View file

@ -1,33 +0,0 @@
package xyz.ineanto.nicko.test;
import be.seeseemelk.mockbukkit.MockBukkit;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.config.Configuration;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class NickoPluginTest {
private static Nicko plugin;
@BeforeAll
public static void setup() {
final Configuration config = Configuration.DEFAULT;
MockBukkit.mock();
plugin = MockBukkit.load(Nicko.class, config);
}
@Test
@DisplayName("Plugin Initialization")
public void initializePlugin() {
assertNotNull(plugin);
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

View file

@ -1,38 +0,0 @@
package xyz.ineanto.nicko.test.appearance;
import be.seeseemelk.mockbukkit.MockBukkit;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.appearance.random.RandomNameFetcher;
import xyz.ineanto.nicko.config.Configuration;
import xyz.ineanto.nicko.mojang.MojangUtils;
import static org.junit.jupiter.api.Assertions.*;
public class RandomNameTest {
private static Nicko plugin;
@BeforeAll
public static void setup() {
final Configuration config = Configuration.DEFAULT;
MockBukkit.mock();
plugin = MockBukkit.load(Nicko.class, config);
}
@Test
@DisplayName("Get random name")
public void getRandomName() {
final RandomNameFetcher randomNameFetcher = new RandomNameFetcher(plugin);
final String username = randomNameFetcher.getRandomUsername();
assertNotNull(username);
assertFalse(MojangUtils.isUsernameInvalid(username));
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

View file

@ -1,35 +0,0 @@
package xyz.ineanto.nicko.test.config;
import be.seeseemelk.mockbukkit.MockBukkit;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.config.Configuration;
import static org.junit.jupiter.api.Assertions.assertFalse;
public class ConfigurationTest {
private static Nicko plugin;
@BeforeAll
public static void setup() {
MockBukkit.mock();
final Configuration config = Configuration.DEFAULT;
plugin = MockBukkit.load(Nicko.class, config);
}
@Test
@DisplayName("Read configuration")
public void readConfiguration() {
final Configuration configuration = plugin.getNickoConfig();
assertFalse(configuration.getSqlConfiguration().isEnabled());
assertFalse(configuration.getRedisConfiguration().isEnabled());
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

View file

@ -1,63 +0,0 @@
package xyz.ineanto.nicko.test.config;
import be.seeseemelk.mockbukkit.MockBukkit;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.config.Configuration;
import xyz.ineanto.nicko.config.DefaultDataSources;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ConfigurationVersionTest {
@BeforeAll
public static void setup() {
MockBukkit.mock();
final Configuration configuration = Configuration.DEFAULT;
MockBukkit.load(Nicko.class, configuration);
}
@Test
@DisplayName("Compare configuration version")
public void compareConfigurationVersion() {
final Configuration configuration = Configuration.DEFAULT;
assertEquals(configuration.getVersionObject().compareTo(Configuration.VERSION), 0);
}
@Test
@DisplayName("Compare newer configuration version")
public void compareNewerConfigurationVersion() {
final Configuration configuration = new Configuration("24.1.0",
DefaultDataSources.SQL_EMPTY,
DefaultDataSources.REDIS_EMPTY,
false);
assertEquals(configuration.getVersionObject().compareTo(Configuration.VERSION), 1);
}
@Test
@DisplayName("Compare older configuration version")
public void compareOlderConfigurationVersion() {
final Configuration configuration = new Configuration("0.23.3",
DefaultDataSources.SQL_EMPTY,
DefaultDataSources.REDIS_EMPTY,
false);
assertEquals(configuration.getVersionObject().compareTo(Configuration.VERSION), -1);
}
@Test
@DisplayName("Compare unknown configuration version")
public void compareUnknownConfigurationVersion() {
final Configuration configuration = new Configuration(null,
DefaultDataSources.SQL_EMPTY,
DefaultDataSources.REDIS_EMPTY,
false);
assertEquals(configuration.getVersionObject().compareTo(Configuration.VERSION), -1);
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

View file

@ -1,56 +0,0 @@
package xyz.ineanto.nicko.test.i18n;
import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.entity.PlayerMock;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.config.Configuration;
import xyz.ineanto.nicko.language.Language;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.language.Translation;
import static org.junit.jupiter.api.Assertions.*;
public class ItemTranslationTest {
private static PlayerMock player;
@BeforeAll
public static void setup() {
final Configuration config = Configuration.DEFAULT;
MockBukkit.mock();
MockBukkit.load(Nicko.class, config);
}
@Test
@DisplayName("Translate Item Without Lore")
public void translateItemTranslationWithoutLore() {
final PlayerLanguage playerLanguage = new PlayerLanguage(Language.FRENCH);
final Translation translation = playerLanguage.translateAndReplace(LanguageKey.GUI.GO_BACK);
assertTrue(translation.lore().isEmpty());
assertEquals(translation.name(), "Retour");
}
@Test
@DisplayName("Translate Item")
public void translateItemLore() {
final PlayerLanguage playerLanguage = new PlayerLanguage(Language.FRENCH);
final Translation test = playerLanguage.translateAndReplace(LanguageKey.GUI.Settings.TOGGLEABLE_BUTTON, "EST", "EST");
test.lore().forEach(System.out::println);
final Translation translation = playerLanguage.translateAndReplace(LanguageKey.GUI.Admin.Cache.STATISTICS, "1", "1");
assertFalse(translation.lore().isEmpty());
assertEquals("Nombre de requêtes: <aqua>1</aqua>", translation.lore().get(0));
assertEquals("Nb. de skin dans le cache: <aqua>1</aqua>", translation.lore().get(1));
assertEquals("<dark_gray><i>Le cache est vidé toutes les 24 heures.</i></dark_gray>", translation.lore().get(2));
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

View file

@ -1,36 +0,0 @@
package xyz.ineanto.nicko.test.i18n;
import be.seeseemelk.mockbukkit.MockBukkit;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.config.Configuration;
import xyz.ineanto.nicko.language.Language;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TranslationTest {
@BeforeAll
public static void setup() {
final Configuration config = Configuration.DEFAULT;
MockBukkit.mock();
MockBukkit.load(Nicko.class, config);
}
@Test
@DisplayName("Translate Line With Replacement")
public void translateItemTranslationWithoutLore() {
final PlayerLanguage playerLanguage = new PlayerLanguage(Language.FRENCH);
final String translation = playerLanguage.translate(LanguageKey.Event.Settings.ERROR, false, "Test");
assertEquals("§cImpossible de mettre à jour vos paramètres. §7§o(Test)", translation);
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

View file

@ -1,73 +0,0 @@
package xyz.ineanto.nicko.test.migration;
import be.seeseemelk.mockbukkit.MockBukkit;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.config.Configuration;
import xyz.ineanto.nicko.config.DefaultDataSources;
import xyz.ineanto.nicko.language.CustomLanguage;
import xyz.ineanto.nicko.migration.CustomLocaleMigrator;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationTest {
private static Nicko plugin;
private static File folder;
private static File localeFile;
@BeforeAll
public static void setup() throws IOException {
MockBukkit.mock();
final Configuration configuration = new Configuration(Configuration.VERSION.toString(),
DefaultDataSources.SQL_EMPTY,
DefaultDataSources.REDIS_EMPTY,
true);
plugin = MockBukkit.load(Nicko.class, configuration);
folder = new File(plugin.getDataFolder(), "/locale/");
localeFile = new File(folder, "locale.yml");
folder.mkdirs();
localeFile.createNewFile();
}
@Test
public void testLanguageFileMigration() throws IOException {
final String content = """
# Nicko - Language File:
# hello I'm the invalid version
version: "1.0.0"
""";
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(localeFile));
outputStream.write(content.getBytes(StandardCharsets.UTF_8));
outputStream.flush();
// Get wrong locale
final CustomLanguage customLanguageBeforeMigration = new CustomLanguage();
assertEquals(customLanguageBeforeMigration.getVersion(), "1.0.0");
// Migrate the wrong locale to the correct one
final CustomLocaleMigrator localeMigrator = new CustomLocaleMigrator(plugin, customLanguageBeforeMigration);
localeMigrator.migrate();
// Get the migrated locale
final CustomLanguage customLanguageMigrated = new CustomLanguage();
assertEquals(customLanguageMigrated.getVersion(), "1.1.0");
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
folder.delete();
localeFile.delete();
}
}

View file

@ -1,42 +0,0 @@
package xyz.ineanto.nicko.test.storage;
import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.ServerMock;
import be.seeseemelk.mockbukkit.entity.PlayerMock;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.config.Configuration;
import xyz.ineanto.nicko.profile.NickoProfile;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class MapCacheTest {
private static Nicko plugin;
private static PlayerMock player;
@BeforeAll
public static void setup() {
final Configuration config = Configuration.DEFAULT;
final ServerMock server = MockBukkit.mock();
plugin = MockBukkit.load(Nicko.class, config);
player = server.addPlayer();
}
@Test
@DisplayName("Cache Player Data")
public void cachePlayerData() {
final Optional<NickoProfile> optionalProfile = plugin.getDataStore().getData(player.getUniqueId());
assertTrue(optionalProfile.isPresent());
assertTrue(plugin.getDataStore().getCache().isCached(player.getUniqueId()));
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

View file

@ -1,78 +0,0 @@
package xyz.ineanto.nicko.test.storage;
import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.ServerMock;
import be.seeseemelk.mockbukkit.entity.PlayerMock;
import org.junit.jupiter.api.*;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.appearance.ActionResult;
import xyz.ineanto.nicko.config.Configuration;
import xyz.ineanto.nicko.config.DataSourceConfiguration;
import xyz.ineanto.nicko.config.DefaultDataSources;
import xyz.ineanto.nicko.profile.NickoProfile;
import xyz.ineanto.nicko.storage.PlayerDataStore;
import xyz.ineanto.nicko.storage.redis.RedisCacheProvider;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class RedisCacheTest {
private static Nicko plugin;
private static PlayerMock player;
@BeforeAll
public static void setup() {
final Configuration config = new Configuration(
"",
DefaultDataSources.SQL_EMPTY,
new DataSourceConfiguration(true, "127.0.0.1", 6379, "", ""),
false);
final ServerMock server = MockBukkit.mock();
plugin = MockBukkit.load(Nicko.class, config);
player = server.addPlayer();
assertInstanceOf(RedisCacheProvider.class, plugin.getDataStore().getCache().getProvider());
}
@Test
@DisplayName("Cache Profile")
@Order(1)
public void cacheProfile() {
final Optional<NickoProfile> optionalProfile = plugin.getDataStore().getData(player.getUniqueId());
assertTrue(optionalProfile.isPresent());
assertTrue(plugin.getDataStore().getCache().isCached(player.getUniqueId()));
}
@Test
@DisplayName("Update Cache Profile")
@Order(2)
public void updateCache() {
final Optional<NickoProfile> optionalProfile = NickoProfile.get(player);
assertTrue(optionalProfile.isPresent());
final NickoProfile profile = optionalProfile.get();
final PlayerDataStore dataStore = plugin.getDataStore();
profile.setName("Notch");
dataStore.updateCache(player.getUniqueId(), profile);
final Optional<NickoProfile> retrieve = dataStore.getCache().retrieve(player.getUniqueId());
assertTrue(retrieve.isPresent());
final NickoProfile retrieved = retrieve.get();
assertEquals(retrieved.getName(), "Notch");
}
@Test
@DisplayName("Delete Cache Profile")
@Order(3)
public void deleteCache() {
final PlayerDataStore dataStore = plugin.getDataStore();
final ActionResult cacheDelete = dataStore.getCache().delete(player.getUniqueId());
assertFalse(cacheDelete.isError());
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

View file

@ -1,104 +0,0 @@
package xyz.ineanto.nicko.test.storage;
import be.seeseemelk.mockbukkit.MockBukkit;
import org.junit.jupiter.api.*;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.appearance.ActionResult;
import xyz.ineanto.nicko.config.Configuration;
import xyz.ineanto.nicko.config.DefaultDataSources;
import xyz.ineanto.nicko.config.SQLDataSourceConfiguration;
import xyz.ineanto.nicko.language.Language;
import xyz.ineanto.nicko.profile.NickoProfile;
import xyz.ineanto.nicko.storage.PlayerDataStore;
import xyz.ineanto.nicko.storage.mariadb.MariaDBStorageProvider;
import java.util.Optional;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class SQLStorageTest {
private static PlayerDataStore dataStore;
private static UUID uuid;
@BeforeAll
public static void setup() {
final Configuration config = new Configuration(
"",
new SQLDataSourceConfiguration(true, "127.0.0.1", 3306, "root", "12345", true),
DefaultDataSources.REDIS_EMPTY,
false);
MockBukkit.mock();
final Nicko plugin = MockBukkit.load(Nicko.class, config);
dataStore = plugin.getDataStore();
uuid = UUID.randomUUID();
assertInstanceOf(MariaDBStorageProvider.class, dataStore.getStorage().getProvider());
}
@Test
@DisplayName("Create tables")
@Order(1)
public void createTables() {
assertFalse(dataStore.getStorage().isError());
}
@Test
@DisplayName("Store empty profile")
@Order(2)
public void storeEmptyProfile() {
final Optional<NickoProfile> optionalProfile = NickoProfile.get(uuid);
assertTrue(optionalProfile.isPresent());
}
@Test
@DisplayName("Update profile")
@Order(3)
public void updateProfile() {
final Optional<NickoProfile> optionalProfile = NickoProfile.get(uuid);
assertTrue(optionalProfile.isPresent());
final NickoProfile profile = optionalProfile.get();
assertNull(profile.getName());
assertNull(profile.getSkin());
assertEquals(profile.getLocale(), Language.ENGLISH);
assertTrue(profile.isRandomSkin());
profile.setName("Notch");
profile.setSkin("Notch");
profile.setLocale(Language.FRENCH);
profile.setRandomSkin(false);
final ActionResult result = dataStore.getStorage().store(uuid, profile);
assertFalse(result.isError());
}
@Test
@DisplayName("Get updated profile")
@Order(4)
public void hasProfileBeenUpdated() {
final Optional<NickoProfile> optionalProfile = NickoProfile.get(uuid);
assertTrue(optionalProfile.isPresent());
final NickoProfile updatedProfile = optionalProfile.get();
assertEquals(updatedProfile.getName(), "Notch");
assertEquals(updatedProfile.getSkin(), "Notch");
assertEquals(updatedProfile.getLocale(), Language.FRENCH);
assertFalse(updatedProfile.isRandomSkin());
}
@Test
@DisplayName("Delete profile")
@Order(5)
public void deleteProfile() {
final ActionResult sqlDelete = dataStore.getStorage().delete(uuid);
assertFalse(sqlDelete.isError());
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}