feat: spigot branch

This commit is contained in:
ineanto 2024-12-12 19:22:11 +01:00
parent ff892a7451
commit 4948610860
Signed by: ineanto
GPG key ID: E511F9CAA2F9CE84
35 changed files with 144 additions and 1291 deletions

View file

@ -8,6 +8,9 @@
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/common" />
<option value="$PROJECT_DIR$/mappings" />
<option value="$PROJECT_DIR$/mappings/v1_21_R1" />
</set>
</option>
</GradleProjectSettings>

View file

@ -1,12 +1,7 @@
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"
}
group = "xyz.ineanto"
@ -23,34 +18,24 @@ 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/")
}
maven { url = uri("https://repo.codemc.io/repository/maven-snapshots/") }
maven { url = uri("https://repo.xenondevs.xyz/releases") }
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") }
maven { url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/") }
}
dependencies {
paperweight.paperDevBundle("1.21.3-R0.1-SNAPSHOT")
compileOnly("org.spigotmc:spigot-api:1.21.3-R0.1-SNAPSHOT")
compileOnly("com.github.dmulloy2:ProtocolLib:5.3.0")
compileOnly("com.github.dmulloy2:ProtocolLib:6845acd89d")
compileOnly("me.clip:placeholderapi:2.11.5")
compileOnly("net.kyori:adventure-api:4.17.0")
compileOnly("xyz.xenondevs.invui:invui:1.41")
implementation("xyz.xenondevs.invui:invui-core:1.41")
implementation("xyz.xenondevs.invui:inventory-access-r21:1.41")
implementation(project(":common"))
implementation(project(":mappings"))
implementation("net.wesjd:anvilgui:1.10.3-SNAPSHOT")
implementation("com.github.jsixface:yamlconfig:1.2")
@ -60,15 +45,6 @@ dependencies {
implementation("org.mariadb.jdbc:mariadb-java-client:3.5.0")
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,7 +59,6 @@ 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("com.github.jsixface", "xyz.ineanto.nicko.libs.yaml")
@ -93,7 +68,6 @@ tasks {
relocate("redis.clients", "xyz.ineanto.nicko.libs.redis")
relocate("com.google.gson", "xyz.ineanto.nicko.libs.gson")
relocate("org.apache.commons.pool2", "xyz.ineanto.nicko.libs.pool2")
relocate("org.bstats", "xyz.ineanto.nicko.libs.bstats")
// EXCLUSIONS
exclude("colors.bin")
@ -113,20 +87,11 @@ tasks {
// MINIFY
minimize {
exclude(dependency("xyz.xenondevs.invui:.*"))
exclude(dependency("net.wesjd:.*"))
exclude(dependency("org.bstats:.*"))
}
manifest {
attributes["paperweight-mappings-namespace"] = "spigot"
}
}
runServer {
dependsOn(reobfJar)
/**
* https://github.com/jpenilla/run-task/issues/56
*
@ -140,7 +105,7 @@ tasks {
* 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()}")
//args("-add-plugin=${reobfJar.get().outputJar.path.toAbsolutePath()}")
downloadPlugins {
url("https://download.luckperms.net/1554/bukkit/loader/LuckPerms-Bukkit-5.4.139.jar")
@ -152,10 +117,6 @@ tasks {
url("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/build/libs/ProtocolLib.jar")
}
minecraftVersion("1.21.3")
minecraftVersion("1.20.6")
}
}
extensions.configure<RunExtension> {
disablePluginJarDetection()
}

14
common/build.gradle.kts Normal file
View file

@ -0,0 +1,14 @@
plugins {
id("java")
}
group = "xyz.ineanto.nicko"
version = project.version
repositories {
mavenCentral()
}
dependencies {
compileOnly("org.spigotmc:spigot-api:1.23.3-R0.1-SNAPSHOT")
}

View file

@ -1,4 +1,4 @@
package xyz.ineanto.nicko.appearance;
package xyz.ineanto.nicko.action;
public class ActionResult {
private final String errorKey;

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

@ -0,0 +1,10 @@
plugins {
id("java")
}
group = "xyz.ineanto.nicko.mappings"
version = project.version
repositories {
mavenCentral()
}

View file

@ -0,0 +1,26 @@
package xyz.ineanto.nicko.packet;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.action.ActionResult;
public abstract class PacketSender {
protected final Player player;
protected final String name;
protected final String skin;
public PacketSender(Player player, String name, String skin) {
this.player = player;
this.name = name;
this.skin = skin;
}
public abstract void sendEntityRespawn();
public abstract ActionResult sendGameProfileUpdate(String name, boolean skinChange, boolean reset);
public abstract void sendEntityMetadataUpdate();
public abstract void sendPlayerRespawn();
public abstract void sendTabListUpdate(String displayName);
}

View file

@ -0,0 +1,21 @@
plugins {
id("java")
}
group = "xyz.ineanto.nicko.mappings"
version = project.version
// maybe see
// https://github.com/tagavari/nms-remap?tab=readme-ov-file
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
compileOnly(project(":mappings"))
compileOnly(project(":common"))
compileOnly("org.spigotmc:spigot:1.21.3-R0.1-SNAPSHOT")
}

View file

@ -1,31 +1,21 @@
package xyz.ineanto.nicko.packet;
package xyz.ineanto.nicko.mappings;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import com.mojang.authlib.properties.PropertyMap;
import it.unimi.dsi.fastutil.ints.IntList;
import net.minecraft.Optionull;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.RemoteChatSession;
import net.minecraft.network.chat.contents.PlainTextContents;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.*;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.phys.Vec3;
import net.minecraft.network.protocol.game.PacketPlayOutEntityDestroy;
import net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity;
import net.minecraft.world.entity.EntityTypes;
import net.minecraft.world.phys.Vec3D;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_21_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.appearance.ActionResult;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.action.ActionResult;
import xyz.ineanto.nicko.mojang.MojangAPI;
import xyz.ineanto.nicko.mojang.MojangSkin;
import xyz.ineanto.nicko.profile.NickoProfile;
import xyz.ineanto.nicko.packet.PacketSender;
import java.io.IOException;
import java.util.EnumSet;
@ -34,37 +24,29 @@ import java.util.Optional;
import java.util.Random;
import java.util.concurrent.ExecutionException;
/**
* Look at this Mojang.
* I want you to really stare at this code.
* You made me do this.
*/
public class InternalPacketSender implements PacketSender {
private final Player player;
private final NickoProfile profile;
public class Mapping1_21_R1 extends PacketSender {
public InternalPacketSender(Player player, NickoProfile profile) {
this.player = player;
this.profile = profile;
public Mapping1_21_R1(Player player, String name, String skin) {
super(player, name, skin);
}
@Override
public void sendEntityRespawn() {
if (!profile.hasData()) return;
if (name == null || name.isEmpty() || skin == null || skin.isEmpty()) return;
final ClientboundRemoveEntitiesPacket destroy = new ClientboundRemoveEntitiesPacket(IntList.of(player.getEntityId()));
final ClientboundAddEntityPacket add = new ClientboundAddEntityPacket(
final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(IntList.of(player.getEntityId()));
final PacketPlayOutSpawnEntity add = new PacketPlayOutSpawnEntity(
new Random().nextInt(9999),
player.getUniqueId(),
player.getX(),
player.getY(),
player.getZ(),
player.getPitch(),
player.getYaw(),
EntityType.PLAYER,
player.getLocation().getX(),
player.getLocation().getY(),
player.getLocation().getZ(),
player.getLocation().getPitch(),
player.getLocation().getYaw(),
EntityTypes.bS,
0,
Vec3.ZERO,
player.getBodyYaw()
Vec3D.c,
player.getEyeLocation().getYaw()
);
Bukkit.getOnlinePlayers().stream().filter(receiver -> receiver.getUniqueId() != player.getUniqueId()).forEach(receiver -> {
@ -81,10 +63,10 @@ public class InternalPacketSender implements PacketSender {
if (skinChange) {
Optional<MojangSkin> skin;
try {
final MojangAPI mojangAPI = Nicko.getInstance().getMojangAPI();
final Optional<String> uuid = mojangAPI.getUUID(profile.getSkin());
final MojangAPI mojang = new MojangAPI();
final Optional<String> uuid = mojang.getUUID(skin);
if (uuid.isPresent()) {
skin = reset ? mojangAPI.getSkinWithoutCaching(uuid.get()) : mojangAPI.getSkin(uuid.get());
skin = reset ? mojang.getSkinWithoutCaching(uuid.get()) : mojang.getSkin(uuid.get());
if (skin.isPresent()) {
final MojangSkin skinResult = skin.get();
final PropertyMap properties = gameProfile.getProperties();
@ -149,7 +131,6 @@ public class InternalPacketSender implements PacketSender {
serverPlayer.connection.latency(),
serverPlayer.gameMode.getGameModeForPlayer(),
MutableComponent.create(new PlainTextContents.LiteralContents(displayName)),
serverPlayer.getTabListOrder(),
Optionull.map(serverPlayer.getChatSession(), RemoteChatSession::asData)
));
@ -163,6 +144,6 @@ public class InternalPacketSender implements PacketSender {
}
private void sendPacket(Packet<?> packet, Player player) {
(((CraftPlayer) player).getHandle()).connection.send(packet);
(((CraftPlayer) player).getHandle()).f.a(packet);
}
}
}

View file

@ -1,2 +1,4 @@
rootProject.name = "nicko"
include("mappings")
include("mappings:v1_21_R1")
include("common")

View file

@ -64,7 +64,7 @@ public class Nicko extends JavaPlugin {
if (!MinecraftVersion.TRAILS_AND_TAILS.atOrAbove()) {
getLogger().severe("This version (" + MinecraftVersion.getCurrentVersion().getVersion() + ") is not supported by Nicko!");
getLogger().severe("As of version 1.2.0, Nicko only supports the latest Minecraft version. (Currently 1.21.3)");
getLogger().severe("As of version 1.2.0, Nicko only supports the latest two majors Minecraft versions. (Currently 1.20.6-1.21.X)");
dataStore.getStorage().setError(true);
Bukkit.getPluginManager().disablePlugin(this);
}

View file

@ -3,6 +3,7 @@ package xyz.ineanto.nicko.appearance;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.action.ActionResult;
import xyz.ineanto.nicko.packet.InternalPacketSender;
import xyz.ineanto.nicko.packet.PacketSender;
import xyz.ineanto.nicko.profile.NickoProfile;

View file

@ -0,0 +1,19 @@
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.artifact.DefaultArtifact;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.repository.RemoteRepository;
import org.jetbrains.annotations.NotNull;
public class NickoLibraryLoader implements PluginLoader {
@Override
public void classloader(@NotNull PluginClasspathBuilder pluginClasspathBuilder) {
MavenLibraryResolver resolver = new MavenLibraryResolver();
resolver.addRepository(new RemoteRepository.Builder("xenondevs", "default", "https://repo.xenondevs.xyz/releases/").build());
resolver.addDependency(new Dependency(new DefaultArtifact("xyz.xenondevs.invui", "invui", "pom", "1.41"), null));
pluginClasspathBuilder.addLibrary(resolver);
}
}

View file

@ -1,15 +0,0 @@
package xyz.ineanto.nicko.packet;
import xyz.ineanto.nicko.appearance.ActionResult;
public interface PacketSender {
void sendEntityRespawn();
ActionResult sendGameProfileUpdate(String name, boolean skinChange, boolean reset);
void sendEntityMetadataUpdate();
void sendPlayerRespawn();
void sendTabListUpdate(String displayName);
}

View file

@ -1,139 +0,0 @@
package xyz.ineanto.nicko.packet;
import com.comphenix.protocol.wrappers.*;
import com.google.common.collect.Multimap;
import it.unimi.dsi.fastutil.ints.IntList;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.appearance.ActionResult;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.mojang.MojangAPI;
import xyz.ineanto.nicko.mojang.MojangSkin;
import xyz.ineanto.nicko.packet.wrapper.*;
import xyz.ineanto.nicko.profile.NickoProfile;
import java.io.IOException;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
public class WrapperPacketSender implements PacketSender {
private final Player player;
private final NickoProfile profile;
private WrappedGameProfile gameProfile;
public WrapperPacketSender(Player player, NickoProfile profile) {
this.player = player;
this.profile = profile;
}
@Override
public void sendEntityRespawn() {
if (!profile.hasData()) return;
final WrapperPlayServerEntityDestroy destroy = new WrapperPlayServerEntityDestroy();
final WrapperPlayServerSpawnEntity spawn = new WrapperPlayServerSpawnEntity();
destroy.setEntityIds(IntList.of(player.getEntityId()));
spawn.setEntityId(player.getEntityId());
spawn.setLocation(player.getLocation());
spawn.setPlayerId(player.getUniqueId());
Bukkit.getOnlinePlayers().stream().filter(receiver -> receiver.getUniqueId() != player.getUniqueId()).forEach(receiver -> {
destroy.sendPacket(receiver);
spawn.sendPacket(receiver);
});
}
@Override
public ActionResult sendGameProfileUpdate(String name, boolean skinChange, boolean reset) {
this.gameProfile = WrappedGameProfile.fromPlayer(player).withName(name);
// TODO (Ineanto, 31/10/2024): Could get refactored to omit this boolean?
if (skinChange) {
Optional<MojangSkin> skin;
try {
final MojangAPI mojangAPI = Nicko.getInstance().getMojangAPI();
final Optional<String> uuid = mojangAPI.getUUID(profile.getSkin());
if (uuid.isPresent()) {
skin = reset ? mojangAPI.getSkinWithoutCaching(uuid.get()) : mojangAPI.getSkin(uuid.get());
if (skin.isPresent()) {
final MojangSkin skinResult = skin.get();
final Multimap<String, WrappedSignedProperty> properties = gameProfile.getProperties();
properties.get("textures").clear();
properties.put("textures", new WrappedSignedProperty("textures", skinResult.value(), skinResult.signature()));
} else {
return ActionResult.error(LanguageKey.Error.MOJANG_SKIN);
}
} else {
return ActionResult.error(LanguageKey.Error.MOJANG_NAME);
}
return ActionResult.ok();
} catch (ExecutionException e) {
return ActionResult.error(LanguageKey.Error.CACHE);
} catch (IOException e) {
return ActionResult.error(LanguageKey.Error.MOJANG_NAME);
} catch (InterruptedException e) {
return ActionResult.error("Unknown error");
}
}
return ActionResult.ok();
}
@Override
public void sendEntityMetadataUpdate() {
final WrappedDataWatcher entityWatcher = WrappedDataWatcher.getEntityWatcher(player);
entityWatcher.setObject(17, (byte) 0x7f, true);
}
@Override
public void sendPlayerRespawn() {
final World world = player.getWorld();
final WrapperPlayServerRespawn respawn = new WrapperPlayServerRespawn();
respawn.setDimension(world);
respawn.setSeed(world.getSeed());
respawn.setGameMode(player.getGameMode());
respawn.setPreviousGameMode(player.getGameMode());
respawn.setCopyMetadata(true);
respawn.sendPacket(player);
}
@Override
public void sendTabListUpdate(String displayName) {
if (gameProfile == null) {
Nicko.getInstance().getLogger().warning("Hello. I sincerely hope you're doing great out there.");
Nicko.getInstance().getLogger().warning("If you see this message, I've failed at my task and I'm a terrible programmer.");
Nicko.getInstance().getLogger().warning("Report this issue on https://git.ineanto.xyz/ineanto/nicko, thank you!");
return;
}
final WrapperPlayerServerPlayerInfo add = new WrapperPlayerServerPlayerInfo();
final WrapperPlayerServerPlayerInfoRemove remove = new WrapperPlayerServerPlayerInfoRemove();
final EnumSet<EnumWrappers.PlayerInfoAction> actions = EnumSet.of(
EnumWrappers.PlayerInfoAction.ADD_PLAYER,
EnumWrappers.PlayerInfoAction.INITIALIZE_CHAT,
EnumWrappers.PlayerInfoAction.UPDATE_LISTED,
EnumWrappers.PlayerInfoAction.UPDATE_DISPLAY_NAME,
EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE,
EnumWrappers.PlayerInfoAction.UPDATE_LATENCY);
remove.setUUIDs(List.of(player.getUniqueId()));
remove.broadcastPacket();
add.setActions(actions);
add.setData(List.of(new PlayerInfoData(
player.getUniqueId(),
player.getPing(),
true,
EnumWrappers.NativeGameMode.fromBukkit(player.getGameMode()),
gameProfile,
WrappedChatComponent.fromText(displayName),
WrappedRemoteChatSessionData.fromPlayer(player)
)));
add.broadcastPacket();
}
}

View file

@ -1,82 +0,0 @@
package xyz.ineanto.nicko.packet.debug;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.wrappers.MinecraftKey;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import xyz.ineanto.nicko.Nicko;
import java.util.Arrays;
import java.util.Optional;
public class RespawnPacketListener implements PacketListener {
@Override
public void onPacketSending(PacketEvent event) {
try {
final Optional<World> world = getWorld(event);
if (world.isEmpty()) {
Bukkit.broadcast(Component.text("did not find the world the player was in"));
return;
}
Bukkit.broadcast(Component.text("found " + world.get().getName() + "!"));
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
public void onPacketReceiving(PacketEvent event) {
}
@Override
public ListeningWhitelist getSendingWhitelist() {
return ListeningWhitelist.newBuilder().types(PacketType.Play.Server.RESPAWN).build();
}
@Override
public ListeningWhitelist getReceivingWhitelist() {
return ListeningWhitelist.EMPTY_WHITELIST;
}
@Override
public Plugin getPlugin() {
return Nicko.getInstance();
}
private boolean keysEquals(MinecraftKey wrappedKey, NamespacedKey bukkitKey) {
// compare bukkit minecraft key and NMS wrapped minecraft key
return wrappedKey.getPrefix().equals(bukkitKey.getNamespace()) && wrappedKey.getKey().equals(bukkitKey.getKey());
}
public Optional<World> getWorld(PacketEvent event) throws Throwable {
// access CommonPlayerSpawnInfo, first field of that type in the Respawn / Login packets
final Object packetHandle = event.getPacket().getHandle();
final Object commonSpawnData = packetHandle.getClass().getRecordComponents()[0].getAccessor().invoke(packetHandle);
Arrays.stream(commonSpawnData.getClass().getRecordComponents()).forEach(component -> {
component.getAccessor().setAccessible(true);
System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-");
System.out.println(component.getName());
System.out.println(component.getType().getSimpleName());
component.getAccessor().setAccessible(false);
}
);
// get the key of the level the player is joining. Second field in the object. First of type ResourceKey
final MinecraftKey key = MinecraftKey.fromHandle(commonSpawnData.getClass().getRecordComponents()[1]);
for (World world : Bukkit.getWorlds()) {
if (keysEquals(key, world.getKey())) {
return Optional.of(world);
}
}
return Optional.empty();
}
}

View file

@ -1,73 +0,0 @@
/**
* PacketWrapper - ProtocolLib wrappers for Minecraft packets
* Copyright (C) dmulloy2 <http://dmulloy2.net>
* Copyright (C) Kristian S. Strangeland
* <p>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package xyz.ineanto.nicko.packet.wrapper;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.google.common.base.Objects;
import org.bukkit.entity.Player;
public abstract class AbstractPacket {
protected PacketContainer handle;
/**
* Constructs a new strongly typed wrapper for the given packet.
*
* @param handle - handle to the raw packet data.
* @param type - the packet type.
*/
protected AbstractPacket(PacketContainer handle, PacketType type) {
// Make sure we're given a valid packet
if (handle == null)
throw new IllegalArgumentException("Packet handle cannot be NULL.");
if (!Objects.equal(handle.getType(), type))
throw new IllegalArgumentException(handle.getHandle()
+ " is not a packet of type " + type);
this.handle = handle;
}
/**
* Retrieve a handle to the raw packet data.
*
* @return Raw packet data.
*/
public PacketContainer getHandle() {
return handle;
}
/**
* Send the current packet to the given receiver.
*
* @param receiver - the receiver.
* @throws RuntimeException If the packet cannot be sent.
*/
public void sendPacket(Player receiver) {
ProtocolLibrary.getProtocolManager().sendServerPacket(receiver,
getHandle());
}
/**
* Send the current packet to all online players.
*/
public void broadcastPacket() {
ProtocolLibrary.getProtocolManager().broadcastServerPacket(getHandle());
}
}

View file

@ -1,32 +0,0 @@
package xyz.ineanto.nicko.packet.wrapper;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.wrappers.Converters;
import it.unimi.dsi.fastutil.ints.IntList;
/**
* Sent by the server to the client to remove one or more entities.
*/
public class WrapperPlayServerEntityDestroy extends AbstractPacket {
/**
* The packet type that is wrapped by this wrapper.
*/
public static final PacketType TYPE = PacketType.Play.Server.ENTITY_DESTROY;
public WrapperPlayServerEntityDestroy() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
/**
* Sets the list of entity ids to remove
*
* @param value New value for field 'entityIds'
*/
public void setEntityIds(IntList value) {
this.handle.getModifier().withType(IntList.class, Converters.passthrough(IntList.class)).writeSafely(0, value);
}
}

View file

@ -1,115 +0,0 @@
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.StructureModifier;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.MinecraftKey;
import com.google.common.hash.Hashing;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.World;
import java.lang.reflect.Field;
import java.lang.reflect.RecordComponent;
/**
* PacketPlayServerRespawn Wrapper class (1.20.X to 1.21.X)
* <p>
* In 1.20.2, all the fields were merged inside a
* single "CommonPlayerSpawnInfo" record.
*
* @author inenato (w/ additional help from lukalt), based on work from dmulloy2 and Kristian S. Strangeland
*/
public class WrapperPlayServerRespawn extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.RESPAWN;
private InternalStructure spawnInfoStructure = null;
public WrapperPlayServerRespawn() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
spawnInfoStructure = handle.getStructures().read(0);
}
}
public void setDimension(World value) {
final MinecraftVersion v1_20_5 = new MinecraftVersion(1, 20, 5);
if (!MinecraftVersion.getCurrentVersion().isAtLeast(v1_20_5)) {
// 1.20 - 1.20.4
final StructureModifier<InternalStructure> structureModifier = spawnInfoStructure == null ?
handle.getStructures() : spawnInfoStructure.getStructures();
final StructureModifier<World> worldStructureModifier = spawnInfoStructure == null ?
handle.getWorldKeys() : spawnInfoStructure.getWorldKeys();
final InternalStructure dimensionType = structureModifier.read(0);
dimensionType.getMinecraftKeys().writeSafely(0, new MinecraftKey("minecraft", "dimension_type"));
dimensionType.getMinecraftKeys().writeSafely(1, new MinecraftKey("minecraft", "overworld"));
structureModifier.writeSafely(0, dimensionType);
worldStructureModifier.writeSafely(0, value);
} 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 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) {
throw new RuntimeException();
}
}
}
public void setGameMode(GameMode value) {
if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
// 1.20 to 1.20.1
handle.getGameModes().writeSafely(0, EnumWrappers.NativeGameMode.fromBukkit(value));
return;
}
spawnInfoStructure.getGameModes().writeSafely(0, EnumWrappers.NativeGameMode.fromBukkit(value));
}
public void setPreviousGameMode(GameMode value) {
if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
// 1.20 to 1.20.1
handle.getGameModes().writeSafely(1, EnumWrappers.NativeGameMode.fromBukkit(value));
return;
}
spawnInfoStructure.getGameModes().writeSafely(1, EnumWrappers.NativeGameMode.fromBukkit(value));
}
public void setCopyMetadata(boolean value) {
if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) return;
// 1.20 to 1.20.1
handle.getBooleans().writeSafely(0, value);
}
public void setSeed(long value) {
if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
// 1.20 to 1.20.1
handle.getLongs().writeSafely(0, Hashing.sha256().hashLong(value).asLong());
}
}
}

View file

@ -1,103 +0,0 @@
package xyz.ineanto.nicko.packet.wrapper;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import javax.annotation.Nonnull;
import java.util.UUID;
/**
* This packet is sent by the server when a player comes into visible range, not when a player joins.
*/
public class WrapperPlayServerSpawnEntity extends AbstractPacket {
/**
* The packet type that is wrapped by this wrapper.
*/
public static final PacketType TYPE = PacketType.Play.Server.SPAWN_ENTITY;
/**
* Constructors a new wrapper for the specified packet
*/
public WrapperPlayServerSpawnEntity() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
/**
* Sets the entity id of the player
*
* @param value New value for field 'entityId'
*/
public void setEntityId(int value) {
this.handle.getIntegers().writeSafely(0, value);
this.handle.getEntityTypeModifier().writeSafely(0, EntityType.PLAYER);
}
/**
* Sets the unique id of the player
*
* @param value New value for field 'playerId'
*/
public void setPlayerId(UUID value) {
this.handle.getUUIDs().writeSafely(0, value);
}
/**
* Sets the value of field 'x'
*
* @param value New value for field 'x'
*/
public void setX(double value) {
this.handle.getDoubles().writeSafely(0, value);
}
/**
* Sets the value of field 'y'
*
* @param value New value for field 'y'
*/
public void setY(double value) {
this.handle.getDoubles().writeSafely(1, value);
}
/**
* Sets the value of field 'z'
*
* @param value New value for field 'z'
*/
public void setZ(double value) {
this.handle.getDoubles().write(2, value);
}
/**
* Sets the discrete rotation around the y-axis (yaw)
*
* @param value New value for field 'yRot'
*/
public void setYRotRaw(byte value) {
this.handle.getBytes().writeSafely(0, value);
}
/**
* Sets the discrete rotation around the x-axis (pitch)
*
* @param value New value for field 'xRot'
*/
public void setXRotRaw(byte value) {
this.handle.getBytes().writeSafely(1, value);
}
public void setLocation(@Nonnull Location location) {
setX(location.getX());
setY(location.getY());
setZ(location.getZ());
setYRotRaw(degreesToAngle(location.getYaw()));
setXRotRaw(degreesToAngle(location.getPitch()));
}
private byte degreesToAngle(float degree) {
return (byte)((int)(degree * 256.0F / 360.0F));
}
}

View file

@ -1,37 +0,0 @@
package xyz.ineanto.nicko.packet.wrapper;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.PlayerInfoData;
import java.util.List;
import java.util.Set;
/**
* Up-to-date version of the Wrapper class
* for the PlayerServerPlayerInfo.
*
* @author ineanto, based on work from dmulloy2 and Kristian S. Strangeland
*/
public class WrapperPlayerServerPlayerInfo extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.PLAYER_INFO;
public WrapperPlayerServerPlayerInfo() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public void setActions(Set<EnumWrappers.PlayerInfoAction> value) {
if (MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
handle.getPlayerInfoActions().writeSafely(0, value);
} else {
handle.getPlayerInfoAction().writeSafely(0, value.stream().iterator().next()); // Get the first Value.
}
}
public void setData(List<PlayerInfoData> value) {
handle.getPlayerInfoDataLists().writeSafely(1, value);
}
}

View file

@ -1,27 +0,0 @@
package xyz.ineanto.nicko.packet.wrapper;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import java.util.List;
import java.util.UUID;
/**
* Up-to-date version of the Wrapper class
* for the PlayerServerPlayerInfoRemove.
*
* @author ineanto, based on work from dmulloy2 and Kristian S. Strangeland
*/
public class WrapperPlayerServerPlayerInfoRemove extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.PLAYER_INFO_REMOVE;
public WrapperPlayerServerPlayerInfoRemove() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public void setUUIDs(List<UUID> value) {
handle.getUUIDLists().writeSafely(0, value);
}
}

View file

@ -1,17 +1,13 @@
name: Nicko
main: xyz.ineanto.nicko.Nicko
loader: xyz.ineanto.nicko.loader.NickoLibraryLoader
version: ${version}
author: Ineanto
authors: [ Ineanto ]
description: "The feature packed, next generation disguise plugin for Minecraft."
api-version: 1.21
softdepend: [ PlaceholderAPI ]
depend:
- ProtocolLib
load: POSTWORLD
commands:
nicko:
description: "Opens Nicko's GUI."
permission: nicko.use
api-version: "1.20"
dependencies:
server:
{ "ProtocolLib" }
permissions:
nicko.*:
default: op

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