feat: update paper plugin sender, fix protocollib classpath access
This commit is contained in:
parent
9adf5f34f5
commit
875a04a850
14 changed files with 84 additions and 210 deletions
|
@ -6,7 +6,7 @@ import org.bukkit.event.player.PlayerTeleportEvent;
|
|||
import xyz.ineanto.nicko.Nicko;
|
||||
import xyz.ineanto.nicko.event.custom.PlayerDisguiseEvent;
|
||||
import xyz.ineanto.nicko.event.custom.PlayerResetDisguiseEvent;
|
||||
import xyz.ineanto.nicko.packet.InternalPacketSender;
|
||||
import xyz.ineanto.nicko.packet.PaperPacketSender;
|
||||
import xyz.ineanto.nicko.packet.PacketSender;
|
||||
import xyz.ineanto.nicko.profile.NickoProfile;
|
||||
import xyz.ineanto.nicko.storage.PlayerDataStore;
|
||||
|
@ -24,7 +24,7 @@ public class AppearanceManager {
|
|||
|
||||
public AppearanceManager(Player player) {
|
||||
this.player = player;
|
||||
this.packetSender = new InternalPacketSender(player, getNickoProfile());
|
||||
this.packetSender = new PaperPacketSender(player, getNickoProfile());
|
||||
}
|
||||
|
||||
public ActionResult reset() {
|
||||
|
@ -51,10 +51,14 @@ public class AppearanceManager {
|
|||
final NickoProfile profile = getNickoProfile();
|
||||
final String displayName = profile.getName() == null ? player.getName() : profile.getName();
|
||||
|
||||
final ActionResult result = packetSender.sendGameProfileUpdate(displayName, skinChange, reset);
|
||||
final ActionResult result = packetSender.updatePlayerProfile(displayName);
|
||||
|
||||
if (result.isError()) {
|
||||
return reset();
|
||||
if (skinChange) {
|
||||
final ActionResult propertiesUpdateResult = packetSender.updatePlayerProfileProperties();
|
||||
|
||||
if (propertiesUpdateResult.isError()) {
|
||||
return reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Call the event.
|
||||
|
@ -63,8 +67,8 @@ public class AppearanceManager {
|
|||
|
||||
packetSender.sendEntityMetadataUpdate();
|
||||
packetSender.sendTabListUpdate(displayName);
|
||||
respawnPlayer();
|
||||
packetSender.sendEntityRespawn();
|
||||
//respawnPlayer();
|
||||
//packetSender.sendEntityRespawn();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.bukkit.entity.Player;
|
|||
import xyz.ineanto.nicko.language.LanguageKey;
|
||||
import xyz.ineanto.nicko.language.PlayerLanguage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -16,12 +17,13 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
public class SignPrompt implements Prompt {
|
||||
private final Player player;
|
||||
private final PlayerLanguage playerLanguage;
|
||||
|
||||
private List<String> lines = List.of(
|
||||
"VVVVVVVVVVVVVVV",
|
||||
null,
|
||||
null,
|
||||
"ΛΛΛΛΛΛΛΛΛΛΛΛΛΛΛ"
|
||||
private final ArrayList<String> lines = new ArrayList<>(
|
||||
List.of(
|
||||
"VVVVVVVVVVVVVVV",
|
||||
"",
|
||||
"",
|
||||
"ΛΛΛΛΛΛΛΛΛΛΛΛΛΛΛ"
|
||||
)
|
||||
);
|
||||
|
||||
private final AtomicReference<Optional<String>> name = new AtomicReference<>();
|
||||
|
@ -73,6 +75,7 @@ public class SignPrompt implements Prompt {
|
|||
try {
|
||||
final SignGUI gui = SignGUI.builder()
|
||||
.setLines(lines.toArray(new String[0]))
|
||||
.setLine(2, null)
|
||||
.setType(Material.OAK_SIGN)
|
||||
.setHandler((_, result) -> {
|
||||
final String internalLine2 = result.getLineWithoutColor(2);
|
||||
|
@ -89,6 +92,7 @@ public class SignPrompt implements Prompt {
|
|||
gui.open(player);
|
||||
return reference.get();
|
||||
} catch (SignGUIVersionException exception) {
|
||||
exception.printStackTrace();
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ public enum Language implements Serializable {
|
|||
FRENCH("fr", "Français"),
|
||||
CUSTOM("cm", "Server Custom");
|
||||
|
||||
public static final Version VERSION = new Version(1, 2, 0);
|
||||
public static final Version VERSION = new Version(1, 3, 0);
|
||||
|
||||
private final String code;
|
||||
private transient final String name;
|
||||
|
|
|
@ -10,8 +10,7 @@ public class LanguageKey {
|
|||
|
||||
public static final String PERMISSION = ERROR_KEY + "permission";
|
||||
public static final String CACHE = ERROR_KEY + "cache";
|
||||
public static final String MOJANG_NAME = ERROR_KEY + "mojang_name";
|
||||
public static final String MOJANG_SKIN = ERROR_KEY + "mojang_skin";
|
||||
public static final String MOJANG = ERROR_KEY + "mojang";
|
||||
}
|
||||
|
||||
public static class Event {
|
||||
|
|
|
@ -3,8 +3,8 @@ package xyz.ineanto.nicko.loader;
|
|||
import io.papermc.paper.plugin.loader.PluginClasspathBuilder;
|
||||
import io.papermc.paper.plugin.loader.PluginLoader;
|
||||
import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver;
|
||||
import org.eclipse.aether.graph.Dependency;
|
||||
import org.eclipse.aether.artifact.DefaultArtifact;
|
||||
import org.eclipse.aether.graph.Dependency;
|
||||
import org.eclipse.aether.repository.RemoteRepository;
|
||||
|
||||
public class NickoPluginLoader implements PluginLoader {
|
||||
|
@ -15,7 +15,6 @@ public class NickoPluginLoader implements PluginLoader {
|
|||
resolver.addRepository(new RemoteRepository.Builder("xenondevs", "default", "https://repo.xenondevs.xyz/releases/").build());
|
||||
resolver.addRepository(new RemoteRepository.Builder("codemc", "default", "https://repo.codemc.io/repository/maven-snapshots/").build());
|
||||
resolver.addDependency(new Dependency(new DefaultArtifact("xyz.xenondevs.invui:invui:pom:1.44"), null));
|
||||
//resolver.addDependency(new Dependency(new DefaultArtifact("net.wesjd:anvilgui:1.10.4-SNAPSHOT"), null));
|
||||
|
||||
pluginClasspathBuilder.addLibrary(resolver);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package xyz.ineanto.nicko.mojang;
|
||||
|
||||
import com.destroystokyo.paper.profile.ProfileProperty;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public record MojangSkin(String value, String signature) {
|
||||
public static MojangSkin buildFromJson(JsonObject object) {
|
||||
final JsonObject properties = object.get("properties").getAsJsonArray().get(0).getAsJsonObject();
|
||||
|
@ -9,4 +13,8 @@ public record MojangSkin(String value, String signature) {
|
|||
final String signature = properties.get("signature").getAsString();
|
||||
return new MojangSkin(value, signature);
|
||||
}
|
||||
|
||||
public Collection<ProfileProperty> asProfileProperties() {
|
||||
return Collections.singleton(new ProfileProperty("textures", value, signature));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@ import xyz.ineanto.nicko.appearance.ActionResult;
|
|||
public interface PacketSender {
|
||||
void sendEntityRespawn();
|
||||
|
||||
ActionResult sendGameProfileUpdate(String name, boolean skinChange, boolean reset);
|
||||
ActionResult updatePlayerProfile(String name);
|
||||
|
||||
ActionResult updatePlayerProfileProperties();
|
||||
|
||||
void sendEntityMetadataUpdate();
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package xyz.ineanto.nicko.packet;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import com.mojang.authlib.properties.PropertyMap;
|
||||
import com.destroystokyo.paper.profile.CraftPlayerProfile;
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.minecraft.Optionull;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
|
@ -39,11 +38,11 @@ import java.util.concurrent.ExecutionException;
|
|||
* I want you to really stare at this code.
|
||||
* You made me do this.
|
||||
*/
|
||||
public class InternalPacketSender implements PacketSender {
|
||||
public class PaperPacketSender implements PacketSender {
|
||||
private final Player player;
|
||||
private final NickoProfile profile;
|
||||
|
||||
public InternalPacketSender(Player player, NickoProfile profile) {
|
||||
public PaperPacketSender(Player player, NickoProfile profile) {
|
||||
this.player = player;
|
||||
this.profile = profile;
|
||||
}
|
||||
|
@ -74,41 +73,40 @@ public class InternalPacketSender implements PacketSender {
|
|||
}
|
||||
|
||||
@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");
|
||||
}
|
||||
}
|
||||
public ActionResult updatePlayerProfile(String name) {
|
||||
final PlayerProfile playerProfile = new CraftPlayerProfile(player.getUniqueId(), name);
|
||||
// Copy previous properties to preserve skin
|
||||
playerProfile.setProperties(playerProfile.getProperties());
|
||||
player.setPlayerProfile(playerProfile);
|
||||
return ActionResult.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult updatePlayerProfileProperties() {
|
||||
final PlayerProfile playerProfile = new CraftPlayerProfile(player.getUniqueId(), profile.getName() == null ? player.getName() : profile.getName());
|
||||
|
||||
try {
|
||||
final MojangAPI mojangAPI = Nicko.getInstance().getMojangAPI();
|
||||
|
||||
final Optional<String> uuid = mojangAPI.getUUID(profile.getSkin());
|
||||
if (uuid.isEmpty()) {
|
||||
return ActionResult.error(LanguageKey.Error.MOJANG);
|
||||
}
|
||||
|
||||
final Optional<MojangSkin> skin = mojangAPI.getSkin(uuid.get());
|
||||
if (skin.isEmpty()) {
|
||||
return ActionResult.error(LanguageKey.Error.MOJANG);
|
||||
}
|
||||
|
||||
final MojangSkin skinResult = skin.get();
|
||||
playerProfile.setProperties(skinResult.asProfileProperties());
|
||||
player.setPlayerProfile(playerProfile);
|
||||
return ActionResult.ok();
|
||||
} catch (ExecutionException | IOException e) {
|
||||
return ActionResult.error(LanguageKey.Error.CACHE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEntityMetadataUpdate() {
|
||||
final SynchedEntityData.DataValue<?> dataValueComponent =
|
|
@ -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,7 +1,7 @@
|
|||
# Nicko ${version} - Language File:
|
||||
|
||||
# Specifies the configuration version, don't change.
|
||||
version: "1.2.0"
|
||||
version: "1.3.0"
|
||||
|
||||
prefix: "<b><gradient:#01a97c:#8ffd54>NICKO</gradient></b>"
|
||||
whoosh: "<b><gradient:#01a97c:#8ffd54>WHOOSH!</gradient></b>"
|
||||
|
@ -10,8 +10,7 @@ oops: "<b><color:#ff4640>OOPS!</color></b>"
|
|||
error:
|
||||
permission: "<gray>You're missing the permission to do that.</gray>"
|
||||
invalid_username: "<gray>This is an invalid Minecraft username.</gray>"
|
||||
mojang_name: "<gray>There's is not Minecraft account with this username.</gray>"
|
||||
mojang_skin: "<gray>This Minecraft account has no skin.</gray>"
|
||||
mojang: "<gray>Something went wrong while fetching data from Mojang.</gray>"
|
||||
cache: "<gray>Unable to get data from the cache.</gray>"
|
||||
|
||||
event:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Nicko ${version} - Fichier de langue:
|
||||
|
||||
# Précise la version de la configuration, ne pas changer.
|
||||
version: "1.2.0"
|
||||
version: "1.3.0"
|
||||
|
||||
prefix: "<b><gradient:#01a97c:#8ffd54>NICKO</gradient></b>"
|
||||
whoosh: "<b><gradient:#01a97c:#8ffd54>WHOOSH!</gradient></b>"
|
||||
|
@ -10,8 +10,7 @@ oops: "<b><color:#ff4640>OOPS!</color></b>"
|
|||
error:
|
||||
permission: "<gray>Vous n'avez pas la permission de faire cela.<gray>"
|
||||
invalid_username: "<gray>Nom d'utilisateur Minecraft invalide.<gray>"
|
||||
mojang_name: "<gray>Aucun compte Minecraft associé à ce nom d'utilisateur.<gray>"
|
||||
mojang_skin: "<gray>Ce compte Minecraft n'a pas de skin.<gray>"
|
||||
mojang: "<gray>Une erreur est surevenue en récupérant les information depuis Mojang.<gray>"
|
||||
cache: "<gray>Impossible de récupérer les données depuis le cache.<gray>"
|
||||
|
||||
event:
|
||||
|
|
|
@ -9,10 +9,11 @@ softdepend: [ PlaceholderAPI ]
|
|||
depend:
|
||||
- ProtocolLib
|
||||
|
||||
# Suppose we require ProtocolLib to be loaded for our plugin
|
||||
AnvilGUI:
|
||||
join-classpath: true
|
||||
required: true
|
||||
dependencies:
|
||||
server:
|
||||
ProtocolLib:
|
||||
load: BEFORE
|
||||
join-classpath: true
|
||||
|
||||
permissions:
|
||||
nicko.*:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue