feat: spigot branch
This commit is contained in:
parent
ff892a7451
commit
4948610860
35 changed files with 144 additions and 1291 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
package xyz.ineanto.nicko.appearance;
|
||||
|
||||
public class ActionResult {
|
||||
private final String errorKey;
|
||||
private boolean error = false;
|
||||
|
||||
public static ActionResult ok() {
|
||||
return new ActionResult();
|
||||
}
|
||||
|
||||
public static ActionResult error() {
|
||||
return new ActionResult(null);
|
||||
}
|
||||
|
||||
public static ActionResult error(String errorMessage) {
|
||||
return new ActionResult(errorMessage);
|
||||
}
|
||||
|
||||
private ActionResult() {
|
||||
this.errorKey = null;
|
||||
}
|
||||
|
||||
private ActionResult(String errorMessage) {
|
||||
this.errorKey = errorMessage;
|
||||
this.error = true;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public String getErrorKey() {
|
||||
return errorKey;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
package xyz.ineanto.nicko.mojang;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class MojangAPI {
|
||||
public static final String URL_NAME = "https://api.mojang.com/users/profiles/minecraft/{name}";
|
||||
public static final String URL_SKIN = "https://sessionserver.mojang.com/session/minecraft/profile/{uuid}?unsigned=false";
|
||||
|
||||
private final Logger logger = Logger.getLogger("MojangAPI");
|
||||
private final HashMap<String, String> uuidToName = new HashMap<>();
|
||||
private final ExecutorService worker = Executors.newFixedThreadPool(6);
|
||||
|
||||
private final CacheLoader<String, Optional<MojangSkin>> skinLoader = new CacheLoader<>() {
|
||||
@Nonnull
|
||||
public Optional<MojangSkin> load(@Nonnull String uuid) throws Exception {
|
||||
return getSkinFromMojang(uuid);
|
||||
}
|
||||
};
|
||||
|
||||
private final LoadingCache<String, Optional<MojangSkin>> skinCache = CacheBuilder
|
||||
.newBuilder()
|
||||
.recordStats()
|
||||
.expireAfterWrite(24, TimeUnit.HOURS)
|
||||
.build(skinLoader);
|
||||
|
||||
private final CacheLoader<String, Optional<String>> uuidLoader = new CacheLoader<>() {
|
||||
@Nonnull
|
||||
public Optional<String> load(@Nonnull String name) throws Exception {
|
||||
return getUUIDFromMojang(name);
|
||||
}
|
||||
};
|
||||
|
||||
private final LoadingCache<String, Optional<String>> uuidCache = CacheBuilder
|
||||
.newBuilder()
|
||||
.expireAfterWrite(2, TimeUnit.DAYS)
|
||||
.build(uuidLoader);
|
||||
|
||||
public Optional<MojangSkin> getSkin(String uuid) throws IOException, ExecutionException {
|
||||
return skinCache.get(uuid);
|
||||
}
|
||||
|
||||
public Optional<MojangSkin> getSkinWithoutCaching(String uuid) throws IOException, ExecutionException, InterruptedException {
|
||||
return getSkinFromMojang(uuid);
|
||||
}
|
||||
|
||||
public Optional<String> getUUID(String name) throws IOException, ExecutionException {
|
||||
return uuidCache.get(name);
|
||||
}
|
||||
|
||||
private Optional<String> getUUIDFromMojang(String name) throws ExecutionException, InterruptedException {
|
||||
final String parametrizedUrl = URL_NAME.replace("{name}", name);
|
||||
final JsonObject object = getRequestToUrl(parametrizedUrl);
|
||||
if (hasNoError(object)) {
|
||||
final JsonElement idObject = object.get("id");
|
||||
final String uuid = idObject.getAsString();
|
||||
final Optional<String> uuidOptional = Optional.of(uuid);
|
||||
uuidCache.put(name, uuidOptional);
|
||||
uuidToName.put(uuid, name);
|
||||
return uuidOptional;
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void eraseFromCache(String uuid) {
|
||||
skinCache.invalidate(uuid);
|
||||
uuidToName.remove(uuid);
|
||||
uuidCache.invalidate(uuid);
|
||||
}
|
||||
|
||||
private Optional<MojangSkin> getSkinFromMojang(String uuid) throws ExecutionException, InterruptedException {
|
||||
final String parametrizedUrl = URL_SKIN.replace("{uuid}", uuid);
|
||||
final JsonObject object = getRequestToUrl(parametrizedUrl);
|
||||
if (hasNoError(object)) {
|
||||
final MojangSkin skin = MojangSkin.buildFromJson(object);
|
||||
return Optional.of(skin);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public String getUUIDName(String uuid) {
|
||||
return uuidToName.get(uuid);
|
||||
}
|
||||
|
||||
private JsonObject getRequestToUrl(String parametrizedUrl) throws ExecutionException, InterruptedException {
|
||||
return worker.submit(() -> {
|
||||
final URL url = URI.create(parametrizedUrl).toURL();
|
||||
final HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||
con.setDoInput(true);
|
||||
con.setRequestMethod("GET");
|
||||
|
||||
switch (con.getResponseCode()) {
|
||||
case 404:
|
||||
case 400:
|
||||
logger.warning("Failed to parse request: Invalid Name");
|
||||
return getErrorObject();
|
||||
case 429:
|
||||
logger.warning("Failed to parse request: The connection is throttled.");
|
||||
return getErrorObject();
|
||||
case 200:
|
||||
final BufferedReader input = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = input.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
|
||||
try {
|
||||
final JsonElement jsonElt = JsonParser.parseString(builder.toString());
|
||||
return jsonElt.getAsJsonObject();
|
||||
} catch (JsonParseException | IllegalStateException exception) {
|
||||
logger.warning("Failed to parse request (" + parametrizedUrl + ")!");
|
||||
return getErrorObject();
|
||||
}
|
||||
default:
|
||||
logger.warning("Unhandled response code from Mojang: " + con.getResponseCode());
|
||||
return getErrorObject();
|
||||
}
|
||||
}).get();
|
||||
}
|
||||
|
||||
private JsonObject getErrorObject() {
|
||||
final JsonObject errorObject = new JsonObject();
|
||||
errorObject.addProperty("error", "An error occurred.");
|
||||
return errorObject;
|
||||
}
|
||||
|
||||
private boolean hasNoError(JsonObject object) {
|
||||
return object.get("error") == null;
|
||||
}
|
||||
|
||||
public LoadingCache<String, Optional<MojangSkin>> getSkinCache() {
|
||||
return skinCache;
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package xyz.ineanto.nicko.mojang;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public record MojangSkin(String value, String signature) {
|
||||
public static MojangSkin buildFromJson(JsonObject object) {
|
||||
final JsonObject properties = object.get("properties").getAsJsonArray().get(0).getAsJsonObject();
|
||||
final String value = properties.get("value").getAsString();
|
||||
final String signature = properties.get("signature").getAsString();
|
||||
return new MojangSkin(value, signature);
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package xyz.ineanto.nicko.mojang;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class MojangUtils {
|
||||
public static boolean isUsernameInvalid(String username) {
|
||||
return !Pattern.matches("^\\w{3,16}$", username);
|
||||
}
|
||||
|
||||
public static UUID fromTrimmed(String trimmedUUID) throws IllegalArgumentException {
|
||||
if (trimmedUUID == null) throw new IllegalArgumentException();
|
||||
StringBuilder builder = new StringBuilder(trimmedUUID.trim());
|
||||
/* Backwards adding to avoid index adjustments */
|
||||
try {
|
||||
builder.insert(20, "-");
|
||||
builder.insert(16, "-");
|
||||
builder.insert(12, "-");
|
||||
builder.insert(8, "-");
|
||||
} catch (StringIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
return UUID.fromString(builder.toString());
|
||||
}
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
package xyz.ineanto.nicko.packet;
|
||||
|
||||
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 org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.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.mojang.MojangAPI;
|
||||
import xyz.ineanto.nicko.mojang.MojangSkin;
|
||||
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.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 InternalPacketSender(Player player, NickoProfile profile) {
|
||||
this.player = player;
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEntityRespawn() {
|
||||
if (!profile.hasData()) return;
|
||||
|
||||
final ClientboundRemoveEntitiesPacket destroy = new ClientboundRemoveEntitiesPacket(IntList.of(player.getEntityId()));
|
||||
final ClientboundAddEntityPacket add = new ClientboundAddEntityPacket(
|
||||
new Random().nextInt(9999),
|
||||
player.getUniqueId(),
|
||||
player.getX(),
|
||||
player.getY(),
|
||||
player.getZ(),
|
||||
player.getPitch(),
|
||||
player.getYaw(),
|
||||
EntityType.PLAYER,
|
||||
0,
|
||||
Vec3.ZERO,
|
||||
player.getBodyYaw()
|
||||
);
|
||||
|
||||
Bukkit.getOnlinePlayers().stream().filter(receiver -> receiver.getUniqueId() != player.getUniqueId()).forEach(receiver -> {
|
||||
sendPacket(destroy, player);
|
||||
sendPacket(add, player);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult sendGameProfileUpdate(String name, boolean skinChange, boolean reset) {
|
||||
final GameProfile gameProfile = new GameProfile(player.getUniqueId(), name);
|
||||
|
||||
// TODO (Ineanto, 31/10/2024): Could this be refactored to get rid of the 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 PropertyMap properties = gameProfile.getProperties();
|
||||
properties.get("textures").clear();
|
||||
properties.put("textures", new Property("textures", skinResult.value(), skinResult.signature()));
|
||||
((CraftPlayer) player).getHandle().gameProfile = gameProfile;
|
||||
} 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 SynchedEntityData.DataValue<?> dataValueComponent =
|
||||
new SynchedEntityData.DataItem<>(
|
||||
new EntityDataAccessor<>(17, EntityDataSerializers.BYTE),
|
||||
(byte) 0x7f
|
||||
).value();
|
||||
|
||||
final ClientboundSetEntityDataPacket data = new ClientboundSetEntityDataPacket(player.getEntityId(), List.of(dataValueComponent));
|
||||
sendPacket(data, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPlayerRespawn() {
|
||||
final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
|
||||
final ServerLevel level = serverPlayer.serverLevel();
|
||||
|
||||
final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(serverPlayer.createCommonSpawnInfo(level), (byte) 0x03);
|
||||
sendPacket(respawn, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTabListUpdate(String displayName) {
|
||||
final ServerPlayer serverPlayer = (((CraftPlayer) player)).getHandle();
|
||||
|
||||
final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = EnumSet.of(
|
||||
ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER,
|
||||
ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT,
|
||||
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED,
|
||||
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME,
|
||||
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE,
|
||||
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY);
|
||||
|
||||
final List<ClientboundPlayerInfoUpdatePacket.Entry> entries = List.of(new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
serverPlayer.getUUID(),
|
||||
serverPlayer.gameProfile,
|
||||
true,
|
||||
serverPlayer.connection.latency(),
|
||||
serverPlayer.gameMode.getGameModeForPlayer(),
|
||||
MutableComponent.create(new PlainTextContents.LiteralContents(displayName)),
|
||||
serverPlayer.getTabListOrder(),
|
||||
Optionull.map(serverPlayer.getChatSession(), RemoteChatSession::asData)
|
||||
));
|
||||
|
||||
final ClientboundPlayerInfoUpdatePacket update = new ClientboundPlayerInfoUpdatePacket(actions, entries);
|
||||
final ClientboundPlayerInfoRemovePacket remove = new ClientboundPlayerInfoRemovePacket(List.of(player.getUniqueId()));
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach(onlinePlayer -> {
|
||||
sendPacket(remove, onlinePlayer);
|
||||
sendPacket(update, onlinePlayer);
|
||||
});
|
||||
}
|
||||
|
||||
private void sendPacket(Packet<?> packet, Player player) {
|
||||
(((CraftPlayer) player).getHandle()).connection.send(packet);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue