Compare commits

...
Sign in to create a new pull request.

6 commits

48 changed files with 598 additions and 790 deletions

2
.gitignore vendored
View file

@ -27,4 +27,4 @@ bin/
### Server ###
run/
CHANGELOG.secret.log
CHANGELOG.log

7
.idea/gradle.xml generated
View file

@ -5,9 +5,16 @@
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="/usr/share/java/gradle" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/mappings" />
<option value="$PROJECT_DIR$/mappings/v1_20" />
<option value="$PROJECT_DIR$/mappings/v1_20_2" />
<option value="$PROJECT_DIR$/mappings/v1_20_4" />
<option value="$PROJECT_DIR$/mappings/v1_20_6" />
<option value="$PROJECT_DIR$/mappings/v1_21" />
</set>
</option>
</GradleProjectSettings>

2
.idea/misc.xml generated
View file

@ -4,7 +4,7 @@
<component name="PWA">
<option name="wasEnabledAtLeastOnce" value="true" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="azul-17.0.10" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="graalvm-21.0.4" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View file

@ -1,8 +1,13 @@
1.1.8: Update n°12 (XX/XX/24)
1.2.0: Update n°12 (XX/XX/24)
[FEATURES]
- Players are now able to save disguises as presets.
- Modernized the messages and added various sound effects upon interacting with Nicko.
[OTHER]
- Dropped the release candidate status as Nicko is now considered stable.
[FIXES]
- Fixed an oversight preventing the configuration from properly being migrated.
[LANGUAGE]
- Moved the prefix to the language file.
1.1.7-RC1: Hotfix n°5 (04/05/24)
[OTHER]

View file

@ -1,116 +0,0 @@
1.2.0: Update n°13 (XX/XX/24)
[FEATURES]
- Players are now able to save disguises as presets.
[FIXES]
- Fixed an oversight preventing the configuration from properly being migrated.
[LANGUAGE]
- Moved the prefix to the language file.
- Updated the language files to modernize the messages.
[OTHER]
- Dropped the release candidate status as Nicko is now considered stable.
1.1.7-RC1: Hotfix n°5 (04/05/24)
[OTHER]
- Restored download link again on spigotmc.org
1.1.6-RC1: Update n°11 (04/05/24)
[FEATURES]
- Update dependencies in preparation to the 1.20.5 update
[OTHER]
- Restored download link on spigotmc.org
1.1.5-RC1: Update n°10 (25/12/23)
[FEATURES]
- Various improvements to performance.
[FIXES]
- Fixed a bug related to configuration migration.
1.1.4-RC1: Update n°9 (07/02/23)
[OTHER]
- The repository hosting the previous version of Nicko had expired, this is now fixed.
1.1.3-RC1: Hotfix n°4 (28/12/23)
[FIXES]
- Fixed the English Locale version being late.
1.1.2-RC1: Update n°8 (28/12/23)
[FEATURES]
- Players now default back to their original appearance upon failure.
[FIXES]
- Fixed an invalid placeholder parameter (%nicko_random_skin% now gets if the player has random skin on login set or not).
- Fixed the error reason not appearing upon failure.
- Fixed player profiles (name and skin associated) not being reset gracefully upon failure.
- Fixed error messages not being precise enough.
- Various optimizations and improvements.
1.1.1-RC1: Update n°7 (27/12/23)
[FEATURES]
- Made Nicko compatible with 1.20.3 and 1.20.4.
1.1.0-RC1: Update n°6 (23/12/23)
[BREAKING]
- The language system has been updated to use the Adventure library (https://docs.advntr.dev/index.html). This results in the custom locale breaking
Nicko upon usage of legacy color codes (e.g., "§6Nicko"). Your custom locale will be backed up upon starting this version and you will be able to
use the new default English locale to help you make your locale compatible with the new formatting.
[FEATURES]
- Players can now choose to get a random appearance via a list of more than 400 usernames and skins associated.
- Players can now toggle a setting to automatically get a random appearance upon joining.
- Introduced a version string inside Nicko's language files to plan future updates to the file. (see [BREAKING])
(Note: the random skin functionality is still work-in-progress and might break or not work at all because of
the lack of time that I have to test all the usernames and skins associated.)
[FIXES]
- Various optimizations and improvements.
- Internal refactoring
- bStats metrics are not minified anymore.
1.0.8-RC1: Update n°5 (19/12/23)
[FEATURES]
- Introduced a version string inside Nicko's configuration to plan future updates to the file. Your previous configuration file will automatically be migrated to this current version (with the backup of your old one included!)
- Persistence and cache will now fallback to local alternatives when unreachable.
- Player check GUI has been updated to better reflect the current state of player's disguises.
- Developers can now listen to the PlayerDisguiseEvent and cancel the disguise process.
[OTHER]
- Various optimizations and improvements.
- Internal refactoring
1.0.7-RC1: Update n°4 (13/12/23)
[OTHER]
- In line with my thinking that Minecraft servers should always be in one of the latest versions to give developers more freedom and less maintenance hassle, Nicko will now only be supporting the current major version and the one before it. This results in this version of Nicko now needing at minimum Java version 17 and a server running 1.19. If you can't upgrade, consider myself sorry.
- Various optimizations and improvements following the upgrade to Java 17.
1.0.6-RC1: Update n°3 (11/12/23)
[OTHER]
- Added telemetry via bStats to gather useful informations about Nicko. This feature is optional and can be disabled inside the "bStats" folder found in plugins folder. Informations gathered are public record and can be found at: https://bstats.org/plugin/bukkit/Nicko/20483.
1.0.5-RC1: Update n°2 (11/12/23)
[OTHER]
- Moved plugin to the Gradle build chain, resulting in faster builds and smaller Jar. This has no consequences for players.
1.0.4-RC1:
[FEATURES]
- The players check GUI is now updated upon player's joining and leaving
- Administrators are now able to remove a player's disguise through the player check GUI
1.0.3-RC1: Hotfix n°3 (07/12/23)
[FIXES]
- Fixed a visual bug where players in survival mode were seeing themselves as having full health and hunger after disguising.
1.0.2-RC1: Hotfix n°2 (06/12/23)
[OTHER]
- Internal refactoring
1.0.1-RC1: Hotfix n°1 (06/12/23)
[FIXES]
- Fixed an issue when joining and players being disguised were not for the player joining.

View file

@ -1,11 +1,35 @@
plugins {
id("java")
id("io.github.goooler.shadow") version "8.1.7"
id("com.gradleup.shadow") version "8.3.2"
id("xyz.jpenilla.run-paper") version "2.3.0"
}
group = "xyz.ineanto"
version = "1.1.8"
allprojects {
group = "xyz.ineanto.nicko"
version = "1.2.0"
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/")
}
}
}
java {
sourceCompatibility = JavaVersion.VERSION_21
@ -15,36 +39,13 @@ java {
}
}
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/")
}
}
dependencies {
// Nicko
compileOnly("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT")
compileOnly("com.github.dmulloy2:ProtocolLib:master-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT")
compileOnly("com.github.dmulloy2:ProtocolLib:-SNAPSHOT")
compileOnly("me.clip:placeholderapi:2.11.5")
compileOnly("net.kyori:adventure-api:4.17.0")
implementation("xyz.xenondevs.invui:invui:1.35")
implementation("net.kyori:adventure-api:4.17.0")
implementation("xyz.xenondevs.invui:invui:1.37")
implementation("net.wesjd:anvilgui:1.10.1-SNAPSHOT")
implementation("com.github.jsixface:yamlconfig:1.2")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2")
@ -55,10 +56,12 @@ dependencies {
implementation("com.google.code.gson:gson:2.10.1")
implementation("org.bstats:bstats-bukkit:3.0.2")
testImplementation("com.github.MockBukkit:MockBukkit:v3.99.1")
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")
implementation(project(":mappings"))
subprojects.forEach {
if (!it.name.startsWith("v")) return@forEach
implementation(project(":mappings:${it.name}"))
}
}
tasks {
@ -106,26 +109,9 @@ tasks {
exclude("org/yaml/**")
exclude("google/protobuf/**")
exclude("net/kyori/**")
// MINIFY
minimize {
exclude(dependency("xyz.xenondevs.invui:.*"))
exclude(dependency("net.wesjd:.*"))
exclude(dependency("org.bstats:.*"))
}
}
jar {
enabled = false
}
test {
useJUnitPlatform()
}
runServer {
dependsOn(shadowJar)
downloadPlugins {
url("https://download.luckperms.net/1554/bukkit/loader/LuckPerms-Bukkit-5.4.139.jar")

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.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

41
gradlew vendored
View file

@ -55,7 +55,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 +80,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 "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@ -133,22 +131,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 +198,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 +214,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.

35
gradlew.bat vendored
View file

@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@ -25,7 +25,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 +41,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 +57,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 +76,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

7
mappings/DISCLAIMER.md Normal file
View file

@ -0,0 +1,7 @@
For full transparency, the following project structure
and code are __heavily__ inspired by SkinRestorer. <br>
I made some slight tweaking here and there, but credit where credit is due.
```
SkinsRestorer Copyright (C) 2021-2024 SRTeam
```

15
mappings/build.gradle.kts Normal file
View file

@ -0,0 +1,15 @@
plugins {
id("java")
}
dependencies {
compileOnly("io.papermc.paper:paper-api:1.20-R0.1-SNAPSHOT")
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

View file

@ -0,0 +1,11 @@
package xyz.ineanto.nicko.mapping;
import org.bukkit.entity.Player;
import java.util.Set;
public abstract class Mapping {
public abstract void respawn(Player player);
public abstract Set<String> supportedVersions();
}

View file

@ -0,0 +1,21 @@
plugins {
id("java")
id("io.papermc.paperweight.userdev") version "1.7.2"
}
dependencies {
paperweight.paperDevBundle("1.20-R0.1-SNAPSHOT")
compileOnly(project(":mappings"))
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.assemble {
dependsOn(tasks.reobfJar)
}

View file

@ -0,0 +1,84 @@
package xyz.ineanto.nicko.mapping.v1_20;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundRespawnPacket;
import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ServerPlayerGameMode;
import net.minecraft.server.players.PlayerList;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.level.biome.BiomeManager;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.mapping.Mapping;
import java.util.List;
import java.util.Set;
public class Mapping1_20 extends Mapping {
@Override
public void respawn(Player player) {
// Really Mojang...? (also applies to Bukkit/Spigot maintainers)
// I'll have to do this everytime I want to update Nicko for the foreseeable future.
// (until ProtocolLib has reworked its API to be more maintainable that said)
// I already when through this hassle with NickReloaded back in 2017,
// when mappings were not included by default, mind you.
// I had to rework the entire project structure and build process just for... you.
// I can't be bothered with fighting your game anymore.
// We need an easy and reliable way to send packets across multiple server versions.
// And I know that this is easier said than done, the game protocol needs
// to evolve and be updated, I get it.
// But I think you can at least try.
// You made a step forward by providing the mappings for Java, this I can agree with.
// (and still stripped them from Bedrock against community feedback, haha f*ck you.)
// However, we still need a stable and reliable Packet API (and so much more!) one day.
final ServerPlayer entityPlayer = (ServerPlayer) player;
final ServerLevel world = entityPlayer.serverLevel();
final ServerPlayerGameMode gameMode = entityPlayer.gameMode;
final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(
world.dimensionTypeId(),
world.dimension(),
BiomeManager.obfuscateSeed(world.getSeed()),
gameMode.getGameModeForPlayer(),
gameMode.getPreviousGameModeForPlayer(),
world.isDebug(),
world.isFlat(),
ClientboundRespawnPacket.KEEP_ALL_DATA,
entityPlayer.getLastDeathLocation(),
entityPlayer.getPortalCooldown()
);
entityPlayer.connection.send(new ClientboundPlayerInfoRemovePacket(List.of(player.getUniqueId())));
entityPlayer.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityPlayer)));
entityPlayer.connection.send(respawn);
entityPlayer.onUpdateAbilities();
entityPlayer.connection.teleport(player.getLocation());
entityPlayer.resetSentInfo();
final PlayerList playerList = entityPlayer.server.getPlayerList();
playerList.sendPlayerPermissionLevel(entityPlayer);
playerList.sendLevelInfo(entityPlayer, world);
playerList.sendAllPlayerInfo(entityPlayer);
for (MobEffectInstance effect : entityPlayer.getActiveEffects()) {
entityPlayer.connection.send(new ClientboundUpdateMobEffectPacket(entityPlayer.getId(), effect));
}
}
@Override
public Set<String> supportedVersions() {
return Set.of("1.20", "1.20.1");
}
}

View file

@ -0,0 +1,21 @@
plugins {
id("java")
id("io.papermc.paperweight.userdev") version "1.7.2"
}
dependencies {
paperweight.paperDevBundle("1.20.2-R0.1-SNAPSHOT")
compileOnly(project(":mappings"))
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.assemble {
dependsOn(tasks.reobfJar)
}

View file

@ -0,0 +1,54 @@
package xyz.ineanto.nicko.mapping.v1_20_2;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundRespawnPacket;
import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.players.PlayerList;
import net.minecraft.world.effect.MobEffectInstance;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.mapping.Mapping;
import java.util.List;
import java.util.Set;
public class Mapping1_20_2 extends Mapping {
@Override
public void respawn(Player player) {
final ServerPlayer entityPlayer = (ServerPlayer) player;
final ServerLevel world = entityPlayer.serverLevel();
final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(
entityPlayer.createCommonSpawnInfo(world),
ClientboundRespawnPacket.KEEP_ALL_DATA
);
entityPlayer.connection.send(new ClientboundPlayerInfoRemovePacket(List.of(player.getUniqueId())));
entityPlayer.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityPlayer)));
entityPlayer.connection.send(respawn);
entityPlayer.onUpdateAbilities();
entityPlayer.connection.teleport(player.getLocation());
entityPlayer.resetSentInfo();
final PlayerList playerList = entityPlayer.server.getPlayerList();
playerList.sendPlayerPermissionLevel(entityPlayer);
playerList.sendLevelInfo(entityPlayer, world);
playerList.sendAllPlayerInfo(entityPlayer);
for (MobEffectInstance effect : entityPlayer.getActiveEffects()) {
entityPlayer.connection.send(new ClientboundUpdateMobEffectPacket(entityPlayer.getId(), effect));
}
}
@Override
public Set<String> supportedVersions() {
return Set.of("1.20.2", "1.20.3");
}
}

View file

@ -0,0 +1,21 @@
plugins {
id("java")
id("io.papermc.paperweight.userdev") version "1.7.2"
}
dependencies {
paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT")
compileOnly(project(":mappings"))
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.assemble {
dependsOn(tasks.reobfJar)
}

View file

@ -0,0 +1,54 @@
package xyz.ineanto.nicko.mapping.v1_20_4;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundRespawnPacket;
import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.players.PlayerList;
import net.minecraft.world.effect.MobEffectInstance;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.mapping.Mapping;
import java.util.List;
import java.util.Set;
public class Mapping1_20_4 extends Mapping {
@Override
public void respawn(Player player) {
final ServerPlayer entityPlayer = (ServerPlayer) player;
final ServerLevel world = entityPlayer.serverLevel();
final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(
entityPlayer.createCommonSpawnInfo(world),
ClientboundRespawnPacket.KEEP_ALL_DATA
);
entityPlayer.connection.send(new ClientboundPlayerInfoRemovePacket(List.of(player.getUniqueId())));
entityPlayer.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityPlayer)));
entityPlayer.connection.send(respawn);
entityPlayer.onUpdateAbilities();
entityPlayer.connection.teleport(player.getLocation());
entityPlayer.resetSentInfo();
final PlayerList playerList = entityPlayer.server.getPlayerList();
playerList.sendPlayerPermissionLevel(entityPlayer);
playerList.sendLevelInfo(entityPlayer, world);
playerList.sendAllPlayerInfo(entityPlayer);
for (MobEffectInstance effect : entityPlayer.getActiveEffects()) {
entityPlayer.connection.send(new ClientboundUpdateMobEffectPacket(entityPlayer.getId(), effect));
}
}
@Override
public Set<String> supportedVersions() {
return Set.of("1.20.4", "1.20.5");
}
}

View file

@ -0,0 +1,19 @@
plugins {
id("java")
id("io.papermc.paperweight.userdev") version "1.7.2"
}
dependencies {
paperweight.paperDevBundle("1.20.6-R0.1-SNAPSHOT")
compileOnly(project(":mappings"))
}
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.REOBF_PRODUCTION

View file

@ -0,0 +1,53 @@
package xyz.ineanto.nicko.mapping.v1_20_6;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundRespawnPacket;
import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.players.PlayerList;
import net.minecraft.world.effect.MobEffectInstance;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.mapping.Mapping;
import java.util.List;
import java.util.Set;
public class Mapping1_20_6 extends Mapping {
@Override
public void respawn(Player player) {
final ServerPlayer entityPlayer = (ServerPlayer) player;
final ServerLevel world = entityPlayer.serverLevel();
final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(
entityPlayer.createCommonSpawnInfo(world),
ClientboundRespawnPacket.KEEP_ALL_DATA
);
entityPlayer.connection.send(new ClientboundPlayerInfoRemovePacket(List.of(player.getUniqueId())));
entityPlayer.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityPlayer)));
entityPlayer.connection.send(respawn);
entityPlayer.onUpdateAbilities();
entityPlayer.connection.teleport(player.getLocation());
entityPlayer.resetSentInfo();
final PlayerList playerList = entityPlayer.server.getPlayerList();
playerList.sendPlayerPermissionLevel(entityPlayer);
playerList.sendLevelInfo(entityPlayer, world);
playerList.sendAllPlayerInfo(entityPlayer);
for (MobEffectInstance effect : entityPlayer.getActiveEffects()) {
entityPlayer.connection.send(new ClientboundUpdateMobEffectPacket(entityPlayer.getId(), effect, true));
}
}
@Override
public Set<String> supportedVersions() {
return Set.of("1.20.6");
}
}

View file

@ -0,0 +1,19 @@
plugins {
id("java")
id("io.papermc.paperweight.userdev") version "1.7.2"
}
dependencies {
paperweight.paperDevBundle("1.21.1-R0.1-SNAPSHOT")
compileOnly(project(":mappings"))
}
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.REOBF_PRODUCTION

View file

@ -0,0 +1,53 @@
package xyz.ineanto.nicko.mapping.v1_21;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundRespawnPacket;
import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.players.PlayerList;
import net.minecraft.world.effect.MobEffectInstance;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.mapping.Mapping;
import java.util.List;
import java.util.Set;
public class Mapping1_21 extends Mapping {
@Override
public void respawn(Player player) {
final ServerPlayer entityPlayer = (ServerPlayer) player;
final ServerLevel world = entityPlayer.serverLevel();
final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(
entityPlayer.createCommonSpawnInfo(world),
ClientboundRespawnPacket.KEEP_ALL_DATA
);
entityPlayer.connection.send(new ClientboundPlayerInfoRemovePacket(List.of(player.getUniqueId())));
entityPlayer.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityPlayer)));
entityPlayer.connection.send(respawn);
entityPlayer.onUpdateAbilities();
entityPlayer.connection.teleport(player.getLocation());
entityPlayer.resetSentInfo();
final PlayerList playerList = entityPlayer.server.getPlayerList();
playerList.sendPlayerPermissionLevel(entityPlayer);
playerList.sendLevelInfo(entityPlayer, world);
playerList.sendAllPlayerInfo(entityPlayer);
for (MobEffectInstance effect : entityPlayer.getActiveEffects()) {
entityPlayer.connection.send(new ClientboundUpdateMobEffectPacket(entityPlayer.getId(), effect, true));
}
}
@Override
public Set<String> supportedVersions() {
return Set.of("1.21", "1.21.1");
}
}

View file

@ -1,2 +1,9 @@
rootProject.name = "nicko"
include(":mappings")
setOf(
"1_20", "1_20_2", "1_20_4", "1_20_6",
"1_21"
).forEach {
include(":mappings:v$it")
}

View file

@ -14,6 +14,7 @@ import xyz.ineanto.nicko.event.PlayerJoinListener;
import xyz.ineanto.nicko.event.PlayerQuitListener;
import xyz.ineanto.nicko.language.CustomLanguage;
import xyz.ineanto.nicko.language.Language;
import xyz.ineanto.nicko.mapping.MappingManager;
import xyz.ineanto.nicko.migration.ConfigurationMigrator;
import xyz.ineanto.nicko.migration.CustomLocaleMigrator;
import xyz.ineanto.nicko.mojang.MojangAPI;
@ -40,6 +41,7 @@ public class Nicko extends JavaPlugin {
private CustomLanguage customLanguage;
private PlayerNameStore nameStore;
private RandomNameFetcher nameFetcher;
private MappingManager mappingManager;
private Metrics metrics;
public Nicko() {
@ -63,8 +65,9 @@ public class Nicko extends JavaPlugin {
configurationManager.saveDefaultConfig();
dataStore = new PlayerDataStore(mojangAPI, getNickoConfig());
mappingManager = new MappingManager();
if (!MinecraftVersion.TRAILS_AND_TAILS.atOrAbove()) {
if (!MinecraftVersion.TRAILS_AND_TAILS.atOrAbove() || mappingManager.getMappingForServer().isEmpty()) {
getLogger().severe("This version (" + MinecraftVersion.getCurrentVersion().getVersion() + ") is not supported by Nicko!");
getLogger().severe("As of version 1.0.7, Nicko only supports the latest two majors Minecraft versions. (Currently 1.20.X-1.21.X)");
dataStore.getStorage().setError(true);
@ -116,7 +119,7 @@ public class Nicko extends JavaPlugin {
}
}
final PluginCommand command = getCommand("nicko");
final PluginCommand command = getCommand("xyz/ineanto/nicko");
if (command != null) {
command.setExecutor(new NickoCommand());
}
@ -198,4 +201,8 @@ public class Nicko extends JavaPlugin {
public CustomLanguage getCustomLocale() {
return customLanguage;
}
public MappingManager getMappingManager() {
return mappingManager;
}
}

View file

@ -10,6 +10,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.mapping.Mapping;
import xyz.ineanto.nicko.mojang.MojangAPI;
import xyz.ineanto.nicko.mojang.MojangSkin;
import xyz.ineanto.nicko.profile.NickoProfile;
@ -58,7 +59,7 @@ public class AppearanceManager {
if (!result.isError()) {
updateMetadata();
updateTabList(gameProfile, displayName);
respawnPlayer();
respawnPlayerViaMappings();
respawnEntityForOthers();
}
return result;
@ -140,7 +141,14 @@ public class AppearanceManager {
entityWatcher.setObject(17, (byte) 0x7f, true);
}
private void respawnPlayer() {
private void respawnPlayerViaMappings() {
final Optional<Mapping> mapping = instance.getMappingManager().getMappingForServer();
if (mapping.isEmpty()) return;
mapping.get().respawn(player);
}
@Deprecated
private void respawnPlayerViaProtocolLib() {
final World world = player.getWorld();
final boolean wasFlying = player.isFlying();
final boolean wasAllowedToFly = player.getAllowFlight();

View file

@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import xyz.ineanto.nicko.version.Version;
public class Configuration {
public static final Version VERSION = new Version(1, 0, 9);
public static final Version VERSION = new Version(1, 2, 0);
public static final Configuration DEFAULT = new Configuration(VERSION.toString(),
DefaultDataSources.SQL_EMPTY,
DefaultDataSources.REDIS_EMPTY,

View file

@ -5,8 +5,8 @@ import xyz.ineanto.nicko.gui.items.appearance.ChangeBothItem;
import xyz.ineanto.nicko.gui.items.appearance.ChangeNameItem;
import xyz.ineanto.nicko.gui.items.appearance.ChangeSkinItem;
import xyz.ineanto.nicko.gui.items.home.*;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.window.Window;

View file

@ -9,7 +9,7 @@ public enum Language implements Serializable {
FRENCH("fr", "Français"),
CUSTOM("cm", "Server Custom");
public static final Version VERSION = new Version(1, 1, 4);
public static final Version VERSION = new Version(1, 2, 0);
private final String code;
private transient final String name;

View file

@ -0,0 +1,27 @@
package xyz.ineanto.nicko.mapping;
import org.bukkit.Bukkit;
import xyz.ineanto.nicko.mapping.v1_20.Mapping1_20;
import xyz.ineanto.nicko.mapping.v1_20_2.Mapping1_20_2;
import xyz.ineanto.nicko.mapping.v1_20_4.Mapping1_20_4;
import xyz.ineanto.nicko.mapping.v1_20_6.Mapping1_20_6;
import xyz.ineanto.nicko.mapping.v1_21.Mapping1_21;
import java.util.List;
import java.util.Optional;
public class MappingManager {
private final List<Mapping> mappings = List.of(
new Mapping1_20(),
new Mapping1_20_2(),
new Mapping1_20_4(),
new Mapping1_20_6(),
new Mapping1_21()
);
public Optional<Mapping> getMappingForServer() {
return mappings.stream()
.filter(mapping -> mapping.supportedVersions().contains(Bukkit.getMinecraftVersion()))
.findFirst();
}
}

View file

@ -19,7 +19,7 @@ public class NickoExpansion extends PlaceholderExpansion {
@Override
public @NotNull String getIdentifier() {
return "nicko";
return "xyz/ineanto/nicko";
}
@Override

View file

@ -16,7 +16,7 @@ public class MariaDBStorageProvider implements StorageProvider {
private Connection connection;
private final String schemaName = "nicko";
private final String schemaName = "xyz/ineanto/nicko";
public MariaDBStorageProvider(Configuration configuration) {
this.configuration = configuration;

View file

@ -16,7 +16,7 @@ public class MySQLStorageProvider implements StorageProvider {
private Connection connection;
private final String schemaName = "nicko";
private final String schemaName = "xyz/ineanto/nicko";
public MySQLStorageProvider(Configuration configuration) {
this.configuration = configuration;

View file

@ -1,11 +1,7 @@
# Nicko ${version} - Config:
# Specifies the configuration version, don't change.
version: "1.0.9"
#
# Language
#
version: "1.2.0"
# Nicko will copy the English locale as "lang.yml"
# and will use the translations in that file when "Server Custom"
@ -13,10 +9,6 @@ version: "1.0.9"
# Accepted values: false (Disabled), true (Enabled)
customLocale: false
#
# Storage
#
sql:
# Indicates wherever the data will be stored locally
# inside a .json file or in an SQL database.
@ -39,8 +31,6 @@ sql:
# Accepted values: any string
password: "password"
# This configuration section manages Redis (enabled BungeeCord support).
# It is used to transfer data between multiple servers.
redis:
# Indicates wherever the data will be stored through
# Redis to transfer whenever a player switches server.

View file

@ -1,7 +1,7 @@
# Nicko ${version} - Language File:
# Specifies the configuration version, don't change.
version: "1.1.4"
version: "1.2.0"
prefix: "<b><gradient:#01a97c:#8ffd54>NICKO</gradient></b>"
whoosh: "<b><gradient:#01a97c:#8ffd54>WHOOSH!</gradient></b>"

View file

@ -1,7 +1,7 @@
# Nicko ${version} - Fichier de langue:
# Précise la version de la configuration, ne pas changer.
version: "1.1.4"
version: "1.2.0"
prefix: "<b><gradient:#01a97c:#8ffd54>NICKO</gradient></b>"
whoosh: "<b><gradient:#01a97c:#8ffd54>WHOOSH!</gradient></b>"

View file

@ -5,8 +5,6 @@ author: Ineanto
description: "The feature packed, next generation disguise plugin for Minecraft."
api-version: 1.20
softdepend: [ PlaceholderAPI ]
depend:
- ProtocolLib
load: POSTWORLD
commands:
nicko:

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();
}
}

View file

@ -1,4 +0,0 @@
# Nicko ${version} - Language File:
# hello I'm the good version
version: "1.1.0"